

0 / 2 embers
0 / 3000 xp
click for more info
Complete a lesson to start your streak
click for more info
Still calibrating
click for more info
Not enough gems
Cost: 6 gems
1: Injection
incomplete
2: Fixing SQL Injection
incomplete
3: Injection Beyond SQL
incomplete
4: Safe Validation and Sanitization
incomplete
5: When to Sanitize
incomplete
6: Unsafe Archive Extraction
incomplete
7: Safe Archive Extraction
incomplete
8: LLM Prompt Injection
incomplete
9: Limiting Tool Calls
incomplete
10: Narrow Tool Interfaces
incomplete
11: File Upload Security
incomplete
Back
ctrl+,
Next
ctrl+.
This lesson's interactive features are locked, please to keep using them
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:
exec.Command("sh", "-c", ...)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.
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!
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.