flawopen.com/Teardowns/cve-2026-97662-aws-security-agent-mcp-git-argument-injection
CVE-2026-97662: AWS Security Agent MCP Git Argument Injection
CVE-2026-97662 let a caller-influenced Git revision in AWS Security Agent MCP diff scans be parsed as a command option, bypassing workspace confinement and enabling host file writes. Upgrade to 0.2.0 or later.[1], [2]
CVSS vector
CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:N/VI:H/VA:H/SC:N/SI:N/SA:NA clerk is told to find a folder by its label, but accepts a label that starts with a control instruction. The filing system follows the instruction instead of looking for a folder. Here, a Git revision beginning with a dash could be interpreted as a Git option; rejecting empty and option-like refs before starting Git closes that input boundary. This is Git option parsing, not arbitrary shell-command execution.[2]
Core Concepts & Subsystem Terms
MCP server- A local process that exposes tools to an AI application through the Model Context Protocol. Tool arguments cross into the server as untrusted input.
Argument injection (CWE-88)- Untrusted input is interpreted as an option or delimiter by a command-line program, even when the caller uses an argument array instead of a shell string.[2], [4]
Framework mappings
- CWE reference for the weakness described in this guide: CWE-88
- OWASP GenAI 2025 — LLM01:2025 Prompt Injection
Root Cause Analysis
AWS describes a context-dependent argument-injection flaw in the diff scan operation: a crafted reference supplied to the scan could be treated as a command-line option rather than a Git revision. The upstream PR confirms that start_diff_scan passed base_ref to git diff <base_ref> -- and git archive; empty or leading-dash values could therefore be misinterpreted. This is not shell metacharacter injection: an argument list can prevent shell parsing while still allowing the target program to parse an argument as an option. The advisory says the resulting operation could create, overwrite, or truncate files outside the intended workspace, with writes limited by the server process's OS permissions. The merged fix validates base_ref before Git, rejecting blank values and values whose trimmed form starts with -; tests assert no subprocess or upload occurs for rejected input. The advisory identifies versions >=0.1.1 and <0.2.0 as affected and 0.2.0 as fixed. CVE record scoring is CVSS 4.0 6.9 Medium; the GitHub advisory also lists CVSS 3.1 8.2 High. No exploit payload is reproduced here.[1], [2], [3], [4]
Step-by-Step Attack Flow
An agent invokes a diff-scan tool
The local MCP server receives a caller-influenced base_ref. The risk depends on a workflow that allows an untrusted repository, content source, or user to influence that value; a prompt injection alone does not automatically reach this code path.[2]
Boundary trace: revision text versus Git options
Conceptual data-flow trace, not a command sequence or exploit reproduction.
Two parsers, two separate boundaries
- Shell parsing
- An argument array keeps the shell from interpreting the value as shell syntax, closing that boundary.[3]
Source Code: Flaw vs. Secure Implementation
This is a focused representation of the upstream call boundary, not a complete copy of the scanner. The merged upstream change validates the reference before Git and tests blank and leading-dash values, including that rejected input causes no subprocess or upload. An argument array avoids shell parsing but does not stop Git from parsing an option. The validation should remain adjacent to every use of base_ref in Git commands. This excerpt shows only the git diff call; the same validation must guard every use of base_ref, including git archive.[3]
Source excerpt: src/security-agent-mcp-server/awslabs/security_agent_mcp_server/scanner.py — start_diff_scan and _validate_git_ref
def start_diff_scan(path: str, base_ref: str):
# The option-like ref reaches Git before validation.
return subprocess.run(
["git", "diff", base_ref, "--"],
cwd=path,
check=False,
)
def _validate_git_ref(base_ref: str) -> None:
if not base_ref or not base_ref.strip():
raise ValueError("base_ref must not be empty.")
if base_ref.strip().startswith("-"):
raise ValueError("base_ref must not start with '-'.")
def start_diff_scan(path: str, base_ref: str):
_validate_git_ref(base_ref) # Reject before subprocesses or uploads.
return subprocess.run(
["git", "diff", base_ref, "--"],
cwd=path,
check=False,
)
Engineering & System Hardening Checklist
- ✓Upgrade
awslabs.security-agent-mcp-serverversions 0.1.1 through 0.1.x to 0.2.0 or later; verify the version of the running MCP process, not just the IDE or agent host.[1], [2], [6] - ✓Validate every user- or repository-influenced Git ref before any Git subprocess, and reject blank or option-like values before uploads or other side effects.[2], [3]
- ✓Add regression tests proving leading-dash and whitespace-only refs cause no subprocess invocation, upload, or remote API call; include valid refs such as
main,origin/main, andHEAD~1.[3] - ✓Use argument arrays rather than shell command strings, but separately validate arguments according to the called program's option grammar; shell escaping alone does not prevent argument injection.[3]
- ✓Run local MCP servers with least-privilege filesystem permissions and an isolated workspace. Treat this as impact containment, not a substitute for upgrading.[1]
- ✓FlawOpen analysis: For workflows that feed untrusted content into agent tool arguments, trace the complete path to tool invocation, then enforce authorization and validation in the MCP server.