T09 · Insecure Skill Coding Practices
- Location
scripts/check_domain.py:37- Finding
OS Command Injection Through Unsanitized Domain Input
- Content
View full analysis
Vulnerability Details
File Location:
scripts/check_domain.py, lines 37–46
Vulnerability Type: OS command injection caused by unsafe shell interpolation
Risk Level: HighVulnerable Code
python domain = sys.argv[1].strip() whois_out = 'WHOIS command not available' if shutil.which('whois'): whois_out = run(['bash', '-lc', f'whois {domain} | sed -n "1,80p"']) result = { 'domain': domain, 'whois': whois_out, 'rdap': fetch_rdap(domain), 'dns_a': run(['bash', '-lc', f'dig +short {domain} A']), 'dns_mx': run(['bash', '-lc', f'dig +short {domain} MX']), 'dns_txt': run(['bash', '-lc', f'dig +short {domain} TXT']), }Technical Analysis
The domain value is read directly from
sys.argv[1]and interpolated into four command strings passed tobash -lc. The application performs no hostname validation and applies no shell escaping.Although
subprocess.check_outputis invoked with an argument list inside therunfunction, this does not prevent injection because the code explicitly starts Bash and asks it to interpret the constructed string. Shell metacharacters contained in the domain value—such as;,|, command substitutions, redirects, or logical operators—are therefore interpreted as shell syntax.For example, a value shaped like the following would append an additional command:
text example.com; id #The issue affects the WHOIS invocation when
whoisis installed and all threediginvocations. The DNS paths remain exploitable regardless of whether the optional WHOIS utility is available, provided the script is invoked and Bash can execute the injected command.Attack Path
- An attacker supplies a crafted domain to a workflow that invokes
scripts/check_domain.py. - The script reads the attacker-controlled string from
sys.argv[1]. - The string is inserted verbatim into the WHOIS and DNS command strings.
bash -lcparses the supplied shell metacharacters.- Bash executes t ...[truncated 1271 chars]
- An attacker supplies a crafted domain to a workflow that invokes
- Remediation
View remediation
Remediation Suggestions
- Remove the shell interpreter entirely. Invoke each utility with a literal argument array:
python whois_out = run(['whois', domain]) dns_a = run(['dig', '+short', domain, 'A']) dns_mx = run(['dig', '+short', domain, 'MX']) dns_txt = run(['dig', '+short', domain, 'TXT'])- Truncate WHOIS output in Python rather than piping it through
sed:
python def first_lines(value, limit=80): return '\n'.join(value.splitlines()[:limit])-
Strictly validate and normalize the input before use. Accept only a syntactically valid DNS hostname, enforce total and per-label length limits, reject empty labels and shell/control characters, and handle internationalized domain names through an explicit IDNA normalization policy.
-
Do not rely only on shell escaping. Quoting may reduce immediate exploitability, but removing
bash -lcis the safer architectural correction. -
Use least privilege and process isolation. Run the helper as a restricted account with limited filesystem access, no unnecessary credentials, and constrained outbound networking.
-
Add regression tests covering metacharacters and malformed values, including semicolons, pipes, substitutions, redirects, newlines, leading hyphens, and oversized input. Tests should verify that invalid values are rejected and never reach a subprocess.
-
Return structured validation errors before starting WHOIS, RDAP, or DNS requests so callers can distinguish malformed targets from lookup failures.
