Skip to content

Input Validation That Sticks:Don't Become an Exploit Gadget

Most security bugs in small tools are not exotic crypto failures. They are trust in strings: paths, URLs, hostnames, and shell fragments that an attacker influences. Validation that sticks happens at every trust boundary, not once as a regex at the front door.

Name the Untrusted Inputs

List them:

  • CLI arguments and flags
  • Environment variables
  • Config files
  • Files whose paths come from users
  • HTTP responses and webhooks
  • Plugin or extension names

If it crossed a boundary, it is untrusted until proven otherwise.

Paths: Contain Them

Path traversal (../../etc/passwd) still works when you naively join user strings to a base directory.

  • Resolve to a canonical path
  • Ensure the result stays under an allowed root
  • Refuse unexpected symlinks when that is your threat model
  • Do not shell out with user paths unquoted

URLs and Network Targets

User-supplied URLs invite SSRF: your tool fetches internal metadata endpoints or localhost admin ports.

  • Allow-list schemes (https only when possible)
  • Block link-local and metadata ranges when fetching on behalf of users
  • Cap redirects
  • Set timeouts

"Just curl whatever they gave us" is a feature request from attackers.

Commands and Shells

If you must run subprocesses:

  • Prefer argument arrays over shell strings
  • Never interpolate untrusted input into shell=True
  • Allow-list executables when the command is selectable

Command injection is almost always a design smell, not bad luck.

Validate Types Early

Parse ints, enums, hostnames, and PEM blocks with strict parsers. Reject unknown fields in configs. Fail with a clear error pointing at the bad value.

Silent coercion hides attacks and bugs alike.

Test the Nasty Cases

Add fixtures for ../, weird unicode dots, newlines in arguments, oversized inputs, and file:// URLs. Security tests are just tests that remember adversaries.

Closing Thoughts

Input validation that sticks treats every boundary as hostile until proven kind. Contain paths, tame URLs, avoid shells, parse strictly. Do that and your CLI stays a tool instead of becoming someone else's gadget.