We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

This lesson's interactive features are locked, please to keep using them

Injection Beyond SQL

While SQL injection is the most famous kind of injection attack, it's far from the only kind. Anywhere that code is built dynamically from user input is a potential injection target:

  • Shell commands: building a shell command from untrusted input with exec.Command("sh", "-c", ...)
  • Template engines: evaluating user input as template source or expressions
  • Search filters and expressions: query languages that accept user-defined operators

Any input that should be data, but can be interpreted as instructions is an injection risk.

99% of the time, the fix is to use robust, context-aware APIs that separate data from instructions, and not try to hand-roll your own interpreters and parsing logic. If you absolutely must build your own interpreter, use its context-specific escaping rules instead of simply concatenating strings.

Shell Injection

Say you want to offer an endpoint that allows a user to specify a domain name and get back its DNS information via nslookup. A naïve implementation might look like this:

domain := request.FormValue("domain")
command := exec.CommandContext(request.Context(), "sh", "-c", "nslookup "+domain)
output, err := command.Output()

The endpoint concatenates whatever domain the user provides directly into a shell command! What happens if the user submits this?

example.com; rm -rf ./uploads

Our server runs two shell commands, and the second one deletes all files in the uploads directory!

Avoid the Shell

One fix in this scenario would be to run nslookup directly with Go's exec.CommandContext instead of passing the command through a shell:

domain := request.FormValue("domain")
command := exec.CommandContext(request.Context(), "nslookup", domain)
output, err := command.Output()

With exec.CommandContext, we specify the binary we want to run (nslookup), then pass its arguments separately. The domain string is one argument, so shell metacharacters can't launch another command.

...but that still doesn't make every argument safe. An attacker might still supply an option or another value that changes how nslookup behaves. The endpoint also needs to validate domain against the hostname syntax it intends to accept.

Once you've done everything you can to use safe APIs, it can also be a good idea to explicitly whitelist the allowed inputs and reject anything that doesn't exactly match the expected pattern.