From 8db11c704fea75c5c526079b3563a46b27e5e665 Mon Sep 17 00:00:00 2001 From: Elwood Ying Date: Fri, 3 Jul 2026 10:00:19 +0800 Subject: [PATCH 1/2] feat(mcp-rules): add 4 new MCP security detection rules Add the following MCP server security detection rules to expand the MCP scanning coverage from 4 to 8 rules: - mcp_ssrf: Detect SSRF via unvalidated URL/hostname arguments reaching network clients without private-address-range checks - mcp_path_traversal: Detect path traversal via unsanitized file path arguments reaching filesystem APIs without canonicalization or directory-boundary checks - mcp_insecure_deserialization: Detect RCE via caller-supplied data deserialized with unsafe serializers (pickle, marshal, yaml.load, unserialize, ObjectInputStream) - mcp_hardcoded_secrets: Detect hardcoded API keys, tokens, private keys, and passwords embedded in MCP server source code Each rule follows the existing ATR (Agent Threat Rules) format with detection criteria, strict judgment standards, and output requirements. --- data/mcp/mcp_hardcoded_secrets.yaml | 82 ++++++++++++++++++++++ data/mcp/mcp_insecure_deserialization.yaml | 72 +++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 data/mcp/mcp_hardcoded_secrets.yaml create mode 100644 data/mcp/mcp_insecure_deserialization.yaml diff --git a/data/mcp/mcp_hardcoded_secrets.yaml b/data/mcp/mcp_hardcoded_secrets.yaml new file mode 100644 index 000000000..7d8d5162b --- /dev/null +++ b/data/mcp/mcp_hardcoded_secrets.yaml @@ -0,0 +1,82 @@ +info: + id: "mcp_hardcoded_secrets" + name: "MCP Hardcoded Secrets Detection" + description: "Detect hardcoded credentials, API keys, tokens, and private keys embedded in MCP server source code, which can be exposed if the repository or distribution package is accessible to unauthorized parties." + author: "ATR (Agent Threat Rules)" + categories: + - code + +prompt_template: | + As a professional AI-agent security analyst, precisely detect hardcoded secrets + in MCP server source code. Hardcoded credentials embedded directly in source + files — API keys, access tokens, private keys, passwords — can be extracted by + anyone who gains read access to the repository, package, or running container. + Require concrete evidence of a genuine secret value; only report when the string + matches a known credential pattern with sufficient entropy or format. + + ## Vulnerability Definition + Hardcoded secrets occur when sensitive authentication material — cloud provider + keys (`AKIA…`), API tokens (`sk-…`, `ghp_…`, `xoxb-…`), private keys + (`-----BEGIN … PRIVATE KEY-----`), database passwords, JWT secrets — is + committed directly in source code rather than loaded from environment variables, + a secrets manager, or a properly git-ignored configuration file. + + ## Detection Criteria (require a concrete secret pattern) + + ### 1. Cloud provider credentials + **Code Patterns:** + - AWS access keys: `AKIA[0-9A-Z]{16}`, AWS secret keys assigned as string + literals. + - Azure / GCP keys, service account JSON embedded as a string or object. + - Cloudflare / DigitalOcean / Linode API tokens in assignments. + + ### 2. SaaS API tokens + **Code Patterns:** + - OpenAI / Anthropic / other LLM API keys: `sk-[a-zA-Z0-9]{20,}`, + `sk-ant-…`. + - GitHub tokens: `ghp_[a-zA-Z0-9]{36}`, `gho_…`, `ghs_…`. + - Slack tokens: `xox[baprs]-…`. + - Stripe keys: `sk_live_…`, `rk_live_…`. + - Generic `API_KEY = "…"`, `SECRET_KEY = "…"`, `TOKEN = "…"` assignments + with high-entropy values (>20 chars, mixed case + digits). + + ### 3. Private keys and certificates + **Code Patterns:** + - PEM blocks: `-----BEGIN RSA PRIVATE KEY-----`, `-----BEGIN EC PRIVATE KEY-----`, + `-----BEGIN PRIVATE KEY-----`, `-----BEGIN OPENSSH PRIVATE KEY-----`. + - PGP private key blocks, certificate bundles with private key material. + + ### 4. Database / service passwords + **Code Patterns:** + - Connection strings with embedded passwords: + `mongodb://user:password@host`, `postgres://user:pass@host`. + - Password assignments: `password = "…"`, `DB_PASS = "…"` where the value is + a non-placeholder string (not ``, `your_password`, `changeme`, + `example`, `xxx`). + + ## Strict Judgment Standards + - **Environment variables**: Do not report `os.environ.get('API_KEY')` or + `process.env.API_KEY` — these are correct practices. + - **Placeholders**: Do not report obvious placeholder values (`your_key_here`, + `xxx`, `changeme`, `example`, ``, empty strings). + - **Test fixtures**: Do not report secrets in files under test directories + (`test/`, `__tests__/`, `*_test.*`, `*.spec.*`) that are clearly fake values. + - **Documentation**: Do not report secrets inside comments that serve as + usage examples with placeholder-style values. + - **Low-entropy values**: Do not report short or dictionary-word strings that + do not match any credential format. + + ## Output Requirements + Only output when finding concrete hardcoded secrets: + - Specific file path and line number + - The type of secret (API key, token, private key, password, etc.) + - The redacted value (show only enough to identify the type, e.g. + `AKIA****XXXX`) + - Technical analysis: how the secret could be extracted by an unauthorized party + - Impact assessment: what resources or services the exposed credential grants + access to + - Remediation: move secrets to environment variables or a secrets manager, + rotate the exposed credential, add `.env` to `.gitignore`, use + pre-commit secret scanners. + + **Strict Requirement: provide the file, line number, and secret type with a redacted value. Remain silent when no concrete evidence exists.** diff --git a/data/mcp/mcp_insecure_deserialization.yaml b/data/mcp/mcp_insecure_deserialization.yaml new file mode 100644 index 000000000..729c5b94e --- /dev/null +++ b/data/mcp/mcp_insecure_deserialization.yaml @@ -0,0 +1,72 @@ +info: + id: "mcp_insecure_deserialization" + name: "MCP Insecure Deserialization Detection" + description: "Detect MCP server tools that deserialize caller-supplied data using unsafe serializers (pickle, marshal, eval-based JSON, yaml.load, unserialize) without validation, enabling remote code execution on the MCP host." + author: "ATR (Agent Threat Rules)" + categories: + - code + +prompt_template: | + As a professional AI-agent security analyst, precisely detect insecure + deserialization vulnerabilities in MCP server tools. The agent (or an upstream + prompt-injection) controls tool arguments; if those arguments are deserialized + using an unsafe serializer, the MCP host can execute attacker-crafted payloads. + Require a concrete argument-to-deserialization-sink path; only report with + evidence. + + ## Vulnerability Definition + An MCP tool handler takes caller-supplied arguments (strings, base64 blobs, or + nested objects) and passes them to a deserializer that can instantiate + arbitrary objects or execute code — `pickle.loads`, `marshal.loads`, + `yaml.load` (unsafe), `unserialize` (PHP), `ObjectInputStream` (Java), + `eval`/`Function()` on JSON-like strings — without type/schema validation. + Because tool arguments are model/attacker-influenced, this is argument-driven + RCE on the MCP host. + + ## Detection Criteria (require tainted argument -> deserialization sink) + + ### 1. Python unsafe deserializers + **Code Patterns:** + - `pickle.loads(args.data)` / `pickle.load(open(args.file))` on + caller-controlled input. + - `marshal.loads(args.data)` / `yaml.load(args.data)` without `Loader=SafeLoader` + / `yaml.unsafe_load()`. + - `dill.loads()` / `shelve.open()` on attacker-influenced data. + + ### 2. JavaScript / dynamic evaluation as deserialization + **Code Patterns:** + - `eval(args.expr)` / `new Function(args.code)` used to parse a structured + argument. + - `vm.runInNewContext(args.script)` / `vm.Script` on caller input. + - `JSON.parse` followed by `eval` of a contained field. + + ### 3. Other language-specific unsafe deserializers + **Code Patterns:** + - PHP `unserialize($args['data'])` without `allowed_classes` restriction. + - Java `ObjectInputStream.readObject()` on caller-controlled bytes. + - .NET `BinaryFormatter.Deserialize()` / `LosFormatter.Deserialize()` on + attacker input. + - Ruby `Marshal.load(args.data)` / `YAML.load` (unsafe) on caller input. + + ## Strict Judgment Standards + - **Safe serializers**: Do not report `json.loads` / `JSON.parse` / + `yaml.safe_load` / `yaml.load(..., Loader=SafeLoader)` — these do not + instantiate arbitrary objects. + - **Trusted data**: Do not report deserialization of server-generated or + statically-defined data with no caller influence. + - **Type-restricted**: Do not report PHP `unserialize` with `allowed_classes: + false` or an explicit allowlist. + - **Test/example**: Do not report sample handlers with hardcoded test payloads. + + ## Output Requirements + Only output when finding a concrete deserialization path: + - Specific file paths and line numbers for the tainted argument and the sink + - The tool parameter name and the exact deserialization call + - Technical analysis: how a crafted payload achieves code execution or object + instantiation + - Impact assessment: RCE scope on the MCP host + - Remediation: use safe serializers (`json`, `yaml.safe_load`), avoid + `eval`/`pickle`/`unserialize` on untrusted data, enforce schema validation, + restrict `allowed_classes`. + + **Strict Requirement: provide the tainted-argument source and the deserialization sink with line numbers. Remain silent when no concrete evidence exists.** From 140653195790160437f61c79d4206d77aa402c6a Mon Sep 17 00:00:00 2001 From: Elwood Ying Date: Mon, 6 Jul 2026 11:03:00 +0800 Subject: [PATCH 2/2] Add jsonpickle deserialization pattern per reviewer suggestion --- data/mcp/mcp_insecure_deserialization.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/data/mcp/mcp_insecure_deserialization.yaml b/data/mcp/mcp_insecure_deserialization.yaml index 729c5b94e..20e8dd13e 100644 --- a/data/mcp/mcp_insecure_deserialization.yaml +++ b/data/mcp/mcp_insecure_deserialization.yaml @@ -32,6 +32,9 @@ prompt_template: | - `marshal.loads(args.data)` / `yaml.load(args.data)` without `Loader=SafeLoader` / `yaml.unsafe_load()`. - `dill.loads()` / `shelve.open()` on attacker-influenced data. + - `jsonpickle.decode(args.data)` on caller-controlled input — jsonpickle can + instantiate arbitrary classes via `{"py/object": "..."}` directives, + carrying the same RCE risk as pickle. ### 2. JavaScript / dynamic evaluation as deserialization **Code Patterns:**