T09 · Insecure Skill Coding Practices
- Location
scripts/script.sh:139- Finding
Arbitrary Command Execution Through GNU sed Expression Injection
- Content
View full analysis
Vulnerability Details
File Location:
scripts/script.sh, lines 139–140
Vulnerability Type: Command injection through user-controlledsedprogram construction
Risk Level: Highbash if [ -f "$cfg" ] && grep -q "^${key}=" "$cfg" 2>/dev/null; then sed -i "s|^${key}=.*|${key}=${val}|" "$cfg"Technical Analysis
The
configcommand incorporates the user-controlledkeyandvalarguments directly into asedsubstitution program. Shell quoting prevents ordinary shell expansion at that stage, but it does not prevent the supplied values from changing the syntax and behavior of the resultingsedprogram.In particular, GNU
sedsupports theesubstitution flag, which executes the generated replacement text as a shell command. An attacker can supply a replacement value beginning with the|delimiter to terminate the replacement field and introduce theeflag. The attacker-controlled key is also copied into the replacement text, allowing it to become the command executed by GNUsed.Neither argument is validated or escaped for use as a regular expression, replacement string, or
sedprogram. Other metacharacters can also alter matching and replacement behavior.Attack Path
-
Invoke the configuration command with a key containing the desired shell command so that a matching configuration entry is created:
bash scripts/script.sh config 'touch /tmp/valve-pwned' seedThis creates an entry resembling:
text touch /tmp/valve-pwned=seed -
Update the same key with a crafted value that terminates the replacement and adds GNU
sed's execution flag:bash scripts/script.sh config 'touch /tmp/valve-pwned' '|e;#' -
The vulnerable interpolation produces a
sedprogram equivalent to:sed s|^touch /tmp/valve-pwned=.*|touch /tmp/valve-pwned=|e;#| -
GNU
sedapplies the substitution and ...[truncated 843 chars]
-
- Remediation
View remediation
Remediation Suggestions
Do not build a
sedprogram by interpolating user-controlled strings.-
Restrict configuration keys to an explicitly supported allowlist. If arbitrary names are required, enforce a conservative format:
bash if [[ ! "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]]; then echo "Invalid configuration key" >&2 return 1 fi -
Define and enforce constraints for values, including rejecting embedded newlines and other characters that could corrupt the line-based configuration format.
-
Replace the dynamic
sedexpression with a configuration parser that treats keys and values strictly as data. For example, use Python's standard library to parse and atomically rewrite the file, comparing keys as literal strings rather than regular expressions. -
If a text-processing utility remains necessary, pass data through dedicated argument channels and perform literal equality comparisons. Do not place values into program source, regular expressions, or replacement expressions.
-
Write updates to a securely created temporary file in
DATA_DIR, set restrictive permissions such as0600, and atomically rename the completed file overconfig.txt. -
Add regression tests containing
seddelimiters, backslashes, ampersands, newlines, command-like keys, and payloads such as|e;#, verifying that none are interpreted as executable syntax.
-
