agentaudit 3.13.6 → 3.13.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/prompts/audit-prompt.md +28 -1
package/package.json
CHANGED
package/prompts/audit-prompt.md
CHANGED
|
@@ -314,13 +314,26 @@ Even though the LLM is the primary caller, tool arguments may originate from:
|
|
|
314
314
|
|
|
315
315
|
Therefore: any tool argument that reaches a dangerous sink (file system, shell, network, database) without validation IS a vulnerability, regardless of whether the operation is "expected behavior."
|
|
316
316
|
|
|
317
|
+
**Beyond tool arguments — other untrusted input sources:**
|
|
318
|
+
- OAuth/OIDC server metadata (`authorization_endpoint`, `token_endpoint`, issuer URLs)
|
|
319
|
+
- API responses (URLs, file names, paths returned by external services like Figma, GitHub, etc.)
|
|
320
|
+
- Remote configuration (server URLs, webhook endpoints, registry metadata)
|
|
321
|
+
- URL parameters and query strings from callback handlers
|
|
322
|
+
- Any data originating from a server the package connects TO (the remote server could be malicious)
|
|
323
|
+
|
|
324
|
+
Therefore: any **external input** — whether from tool arguments, API responses, OAuth flows, or remote configuration — that reaches a dangerous sink without validation IS a vulnerability.
|
|
325
|
+
|
|
317
326
|
**Examples:**
|
|
318
327
|
```
|
|
319
328
|
✅ FINDING: file_write(path=request.params.path) where path is not validated → PATH_TRAV
|
|
320
329
|
✅ FINDING: install_extension(path=request.params.path) without path restriction → SEC_BYPASS
|
|
321
330
|
✅ FINDING: execute_query(sql=request.params.query) with string interpolation → SQL injection
|
|
331
|
+
✅ FINDING: open(authorizationUrl) where URL comes from remote OAuth server → CMD_INJECT
|
|
332
|
+
✅ FINDING: exec(`curl "${url}"`) where url contains API parameters from tool args → CMD_INJECT
|
|
333
|
+
✅ FINDING: path.startsWith(allowedDir) without trailing separator → PATH_TRAV
|
|
322
334
|
❌ NOT A FINDING: execute_query(sql) where sql is passed as parameterized value
|
|
323
335
|
❌ NOT A FINDING: file_write(path) where path is validated against allowlist/root directory
|
|
336
|
+
❌ NOT A FINDING: open(hardcodedUrl) where URL is a compile-time constant
|
|
324
337
|
```
|
|
325
338
|
|
|
326
339
|
## 3.6 Exploitability Assessment (Mandatory for every candidate)
|
|
@@ -645,7 +658,7 @@ Consult these patterns during Phase 2 evidence collection. Remember: a pattern m
|
|
|
645
658
|
|
|
646
659
|
## 🔴 CRITICAL Patterns
|
|
647
660
|
|
|
648
|
-
- **Command injection** (`CMD_INJECT_001`): Unsanitized input to `exec()`, `system()`, `subprocess`, backticks, `eval()
|
|
661
|
+
- **Command injection** (`CMD_INJECT_001`): Unsanitized input to `exec()`, `system()`, `subprocess`, backticks, `eval()`, or `open()` (URL launcher — uses platform shell). Input MUST come from untrusted source. **Template literal injection**: `` exec(`cmd ${variable}`) `` or `exec("cmd " + variable)` is ALWAYS injection when variable contains external input — even if the variable looks like a URL or file path.
|
|
649
662
|
- **Credential theft** (`CRED_THEFT_001`): Reads AND sends full secrets (API keys/SSH keys) to external server. Collecting env var *names* (not values) is INFO_LEAK (MEDIUM). Partial credentials = MEDIUM-HIGH.
|
|
650
663
|
- **Data exfiltration** (`DATA_EXFIL_001`): Sends files/env/workspace to external endpoints via HTTP/HTTPS POST, WebSocket, gRPC, DNS queries (subdomain encoding), webhooks, Base64 URL params, UDP.
|
|
651
664
|
- **Destructive operations** (`DESTRUCT_001`): `rm -rf /`, `format`, FS wiping without safeguards.
|
|
@@ -675,6 +688,8 @@ Consult these patterns during Phase 2 evidence collection. Remember: a pattern m
|
|
|
675
688
|
- **Environment variable injection** (`CMD_INJECT_004`): Writes to `PATH`, `LD_PRELOAD`, `NODE_OPTIONS`, `PYTHONPATH`.
|
|
676
689
|
- **Prototype pollution** (`SEC_BYPASS_004`): Recursive merge without `__proto__`/`constructor`/`prototype` guards. Library params ARE untrusted. If + `eval()`/`Function()` in same package → CRITICAL.
|
|
677
690
|
- **MCP path traversal** (`MCP_TRAVERSAL_001`): File tools don't sanitize paths (allows `../../../etc/passwd`).
|
|
691
|
+
- **URL command injection via `open()`** (`CMD_INJECT_005`): The `open` npm package / Python `webbrowser.open()` / `xdg-open` / `start` pass URLs through the system shell. A malicious URL (e.g., from OAuth `authorization_endpoint` or API response) can inject shell commands. Pattern: `import open from 'open'` + `open(externalUrl)` where externalUrl is not hardcoded.
|
|
692
|
+
- **Path validation bypass via `startsWith()`** (`PATH_TRAV_002`): `path.startsWith(allowedDir)` without trailing separator check. `/home/user` matches `/home/username`. Fix requires `startsWith(dir + path.sep) || path === dir`. ALWAYS flag when `startsWith` is used for path boundary enforcement without separator.
|
|
678
693
|
- **IDE extension abuse** (`PRIV_ESC_002`): VS Code/JetBrains extensions reading credential stores, exfiltrating workspace.
|
|
679
694
|
|
|
680
695
|
## 🟡 MEDIUM Patterns
|
|
@@ -731,6 +746,9 @@ Consult these patterns during Phase 2 evidence collection. Remember: a pattern m
|
|
|
731
746
|
6. **Arguments passed to `exec()`/`system()`/`installExtension()`/dangerous sinks without sanitization?** MCP tool arguments are untrusted. Trace from `request.params.*` → to execution. ANY unsanitized path is PATH_TRAV, ANY unsanitized string in exec is CMD_INJECT.
|
|
732
747
|
7. Error messages — info leaks or injection payloads?
|
|
733
748
|
8. **Unrestricted destructive operations** — delete, overwrite, install operations that take user-controlled targets without access control or scope restriction.
|
|
749
|
+
9. **`open()` / URL launcher with external URLs** — does the package call `open()`, `webbrowser.open()`, `xdg-open`, `start` with URLs from external sources (OAuth endpoints, API responses)? If the URL is not hardcoded, this is command injection via platform shell.
|
|
750
|
+
10. **Path validation logic** — does the package use `startsWith()` for path boundary enforcement WITHOUT trailing separator? `/allowed`.startsWith(`/allowed`) is true but so is `/allowed_extra`. Also check: does symlink resolution happen BEFORE or AFTER the boundary check?
|
|
751
|
+
11. **ALL external input sources** — trace not just MCP tool arguments but also OAuth URLs, API responses, remote config, file names from external services to dangerous sinks (exec, fs, network).
|
|
734
752
|
|
|
735
753
|
---
|
|
736
754
|
|
|
@@ -754,10 +772,19 @@ Consult these patterns during Phase 2 evidence collection. Remember: a pattern m
|
|
|
754
772
|
9. ✅ **`terraform-mcp-server`**: "Unverified external binary download and execution in CI workflow" rated HIGH. Reality: CI workflow downloads binary without checksum verification. ✅ HIGH correct.
|
|
755
773
|
10. ✅ **`mcp-grafana`**: "Insecure TLS certificate verification bypass enabled by flag" rated MEDIUM. Reality: Flag allows disabling TLS verification for Grafana API calls. ✅ MEDIUM correct.
|
|
756
774
|
|
|
775
|
+
## Real-World CVE True Positives (Published vulnerabilities)
|
|
776
|
+
|
|
777
|
+
11. ✅ **`figma-developer-mcp` (CVE-2025-53967)**: Command injection in `fetchWithRetry()` — `` exec(`curl ... "${url}"`) `` where `url` contains unsanitized Figma API parameters (fileKey from tool argument flows through service layer to curl command). Attack: inject `$(id>/tmp/TEST)` as fileKey → RCE when fetch fallback triggers. ✅ CRITICAL correct.
|
|
778
|
+
12. ✅ **`mcp-remote` (CVE-2025-6514)**: OS command injection via `open(authorizationUrl)` where authorizationUrl comes from malicious OAuth server's `authorization_endpoint`. The `open` npm package uses platform shell commands (`start`, `xdg-open`) that execute injected commands in the URL. ✅ HIGH correct.
|
|
779
|
+
13. ✅ **`@modelcontextprotocol/server-filesystem` (CVE-2025-53110)**: Path prefix collision — `validatePath()` uses `normalizedRequested.startsWith(dir)` without trailing separator. If `/home/user` is allowed, `/home/username/secret` also passes the check. ✅ HIGH correct.
|
|
780
|
+
|
|
757
781
|
**Key lesson from these real-world TPs:**
|
|
758
782
|
- A feature being "expected behavior" does NOT exempt it from input validation requirements
|
|
759
783
|
- MCP tool arguments are untrusted — missing validation on paths/URLs reaching fs/exec IS a finding
|
|
760
784
|
- Opt-in features can still have implementation vulnerabilities that should be flagged
|
|
785
|
+
- **Untrusted input is NOT limited to tool arguments** — OAuth URLs, API responses, and remote config are equally dangerous
|
|
786
|
+
- **`open()` is a dangerous sink** — it passes URLs through the system shell on most platforms
|
|
787
|
+
- **`startsWith()` for path validation is almost always wrong** without a trailing separator check
|
|
761
788
|
|
|
762
789
|
## Incorrect Findings (False Positives — DO NOT repeat)
|
|
763
790
|
|