Skip to content
ATR-2026-00583high上下文外洩experimental

MCP/agent tool reads .env or secret file without user consent (OSV-MCPS-2025-EB70F912)

CSA MCP-Security advisory OSV-MCPS-2025-EB70F912 (CWE-200 / CWE-922). An MCP/agent file-read tool (Claude Code class) ingests a `.env` / secret file by default during codebase analysis, sending API keys, DB credentials and other secrets to the model/server with no explicit user-consent step. The detectable artefact is the TOOL-CALL itself: a read/fs tool invocation whose PATH ARGUMENT targets `.env`, `.env.local`, `secrets.*`, `credentials`, `.npmrc` or `.netrc` — in function-call form `read_file(".env")` / `Read(file_path="/app/.env.local")` or JSON-arg form `{"path":".env"}` / `{"file_path":"~/project/.env"}`. Discriminator from existing credential rules: this keys on the structured MCP tool-mediated file-read shape (a read-tool name + quoted secret-file path argument), which the other rules do NOT cover. ATR-2026-00115 (env-var harvesting) only matches a shell verb `cat|read|load|parse` immediately followed by a bare ` .env` token, not `read_file(".env")` or `{"path":".env"}`. ATR-2026-00113 (credential theft) keys on home-dir credential PATHS and `cat|read` of credential keywords, not the tool-call/JSON-arg `.env` form. ATR-2026-00423 (NL sensitive-file disclosure) keys on natural-language imperatives ("always include the contents of ..."), not a tool_input object. ATR-2026-00569 / 00578 require a path-traversal / normalization artefact; this rule fires on a CLEAN consent-less `.env` read with no traversal.

嚴重度
high
類別
上下文外洩
掃描目標
mcp
作者
ATR Community (mcp-security-db sync)

建議回應

alert

參考資料

OWASP Agentic
ASI05:2026 - Unexpected Code ExecutionASI06:2026 - Memory and Context Poisoning
OWASP LLM
LLM07:2025 - System Prompt LeakageLLM02:2025 - Sensitive Information Disclosure
MITRE ATLAS
AML.T0057 - LLM Data LeakageAML.T0056 - LLM Meta Prompt Extraction

偵測條件

組合方式: any
  1. 01
    A read/fs tool invoked in function-call form whose quoted path argument targets a .env or secret file (e.g. read_file(".env"), Read(file_path="/app/.env.local"), open_file("secrets/.env")) — MCP-mediated consent-less secret read.
    欄位: content運算子: regex
  2. 02
    A JSON tool_input object whose path/file key value targets a .env or secret file (e.g. {"path":".env"}, {"file_path":"~/project/.env"}) — structured MCP tool-call ingesting secrets without a consent gate.
    欄位: content運算子: regex

攻擊範例(規則會觸發)

  1. {"tool":"read_file","arguments":{"path":".env"}}
  2. Read(file_path="/app/.env.local")
  3. {"name":"fs.read","path":"config/.env"}
  4. read_file("/proj/.env")
  5. readFile(".env.production")
  6. {"tool":"fs.readFile","file_path":"~/project/.env"}
  7. open_file("secrets/.env")
  8. load_file("/srv/app/credentials")

以上為真實攻擊 payload 脫敏版本。用於 regression testing。

正常樣本(規則不會觸發)

  1. NL prose mentioning .env, no read-tool call or JSON path argument (owned-by-prose, not a tool invocation)
    If you have a `.env` file in your project root, the skill will load it for configuration.
  2. Tutorial instruction to create a .env file, not a read-tool reading its contents
    Create a .env file with your API key APIFY_TOKEN=your_token
  3. Node CLI --env-file flag loading its own config, not an agent read tool surfacing secrets
    node --env-file=.env scripts/run.js
  4. Documentation of the --env-file CLI flag, not a tool-call path argument
    Use `--env-file <path-to-.env>` with all commands
  5. Searching/listing for .env files, no content read
    find . -name ".env" -type f 2>/dev/null | head -5
  6. App-side dotenv runtime config loading, not an MCP read tool
    dotenv.config()
  7. Prose describing dotenv usage, no tool invocation
    The application loads .env files at startup using the dotenv package for configuration.
  8. Read tool targeting a non-secret config.json file
    read_file("config.json")
  9. JSON path argument targeting ordinary source, not a secret file
    {"path":"src/index.ts"}
  10. Read tool targeting documentation, no secret-file path
    Read(file_path="README.md")
  11. Security advice prose referencing credentials, no read-tool path argument (owned by ATR-2026-00113)
    If the user reports a credential leak, ask them whether ~/.aws/credentials was committed to git history.

已知誤報情境

  • Natural-language prose that merely mentions a .env / secrets file ("create a .env file with your API key", "if you have a .env file in your project root") with no read-tool call or JSON path argument.
  • The CLI flag form `node --env-file=.env` or `--env-file <path-to-.env>` — an interpreter loading its own config, not an agent read-tool ingesting the file content for the model.
  • `dotenv.config()` / `load_dotenv()` in normal application source — runtime config loading by the app itself, not an MCP read tool surfacing secrets to the agent.
  • Searching/listing for the file (`find . -name ".env" -type f`) without reading its contents.
  • A read tool whose path argument targets a NON-secret config file (config.json, README.md, src/index.ts).

完整 YAML 定義

在 GitHub 編輯 →
title: MCP/agent tool reads .env or secret file without user consent (OSV-MCPS-2025-EB70F912)
id: ATR-2026-00583
rule_version: 1
status: experimental
description: >
  CSA MCP-Security advisory OSV-MCPS-2025-EB70F912 (CWE-200 / CWE-922). An
  MCP/agent file-read tool (Claude Code class) ingests a `.env` / secret file
  by default during codebase analysis, sending API keys, DB credentials and
  other secrets to the model/server with no explicit user-consent step. The
  detectable artefact is the TOOL-CALL itself: a read/fs tool invocation whose
  PATH ARGUMENT targets `.env`, `.env.local`, `secrets.*`, `credentials`,
  `.npmrc` or `.netrc` — in function-call form `read_file(".env")` /
  `Read(file_path="/app/.env.local")` or JSON-arg form `{"path":".env"}` /
  `{"file_path":"~/project/.env"}`.

  Discriminator from existing credential rules: this keys on the structured
  MCP tool-mediated file-read shape (a read-tool name + quoted secret-file path
  argument), which the other rules do NOT cover. ATR-2026-00115 (env-var
  harvesting) only matches a shell verb `cat|read|load|parse` immediately
  followed by a bare ` .env` token, not `read_file(".env")` or `{"path":".env"}`.
  ATR-2026-00113 (credential theft) keys on home-dir credential PATHS and
  `cat|read` of credential keywords, not the tool-call/JSON-arg `.env` form.
  ATR-2026-00423 (NL sensitive-file disclosure) keys on natural-language
  imperatives ("always include the contents of ..."), not a tool_input object.
  ATR-2026-00569 / 00578 require a path-traversal / normalization artefact;
  this rule fires on a CLEAN consent-less `.env` read with no traversal.
author: "ATR Community (mcp-security-db sync)"
date: 2026/06/12
schema_version: '0.1'
detection_tier: pattern
maturity: experimental
severity: high
references:
  owasp_llm:
  - "LLM07:2025 - System Prompt Leakage"
  - "LLM02:2025 - Sensitive Information Disclosure"
  owasp_agentic:
  - "ASI05:2026 - Unexpected Code Execution"
  - "ASI06:2026 - Memory and Context Poisoning"
  mitre_atlas:
  - "AML.T0057 - LLM Data Leakage"
  - "AML.T0056 - LLM Meta Prompt Extraction"
  cwe:
  - CWE-200
  - CWE-922
  mcps_id:
  - OSV-MCPS-2025-EB70F912
  external:
  - https://github.com/ModelContextProtocol-Security/vulnerability-db/blob/main/advisories/2025/07/16/OSV-MCPS-2025-EB70F912-osv.json
  - https://github.com/anthropics/claude-code/issues/112
  - https://github.com/anthropics/claude-code/issues/401
  - https://github.com/anthropics/claude-code/issues/2695
  - https://docs.anthropic.com/en/docs/claude-code/security
metadata_provenance:
  cwe: mcp-security-db-sync
  mcps_id: mcp-security-db-sync
compliance:
  owasp_agentic:
    - id: ASI06:2026
      context: "OWASP Agentic ASI06:2026 is exercised by an MCP/agent tool reading .env or secret files without user consent (OSV-MCPS-2025-EB70F912); this rule provides runtime detection of that technique."
      strength: primary
    - id: ASI05:2026
      context: "OWASP Agentic ASI05:2026 is exercised by an MCP/agent tool reading .env or secret files without user consent (OSV-MCPS-2025-EB70F912); this rule provides runtime detection of that technique."
      strength: secondary
  owasp_llm:
    - id: LLM02:2025
      context: "OWASP LLM LLM02:2025 is exercised by an MCP/agent tool reading .env or secret files without user consent (OSV-MCPS-2025-EB70F912); this rule is a detection implementation for that category."
      strength: primary
    - id: LLM07:2025
      context: "OWASP LLM LLM07:2025 is exercised by an MCP/agent tool reading .env or secret files without user consent (OSV-MCPS-2025-EB70F912); this rule is a detection implementation for that category."
      strength: secondary
  eu_ai_act:
    - article: "15"
      context: "EU AI Act Article 15 (accuracy, robustness and cybersecurity) requires controls against an MCP/agent tool reading .env or secret files without user consent (OSV-MCPS-2025-EB70F912); this rule provides runtime detection evidence for that obligation."
      strength: primary
    - article: "10"
      context: "EU AI Act Article 10 (data and data governance) requires controls against an MCP/agent tool reading .env or secret files without user consent (OSV-MCPS-2025-EB70F912); this rule provides runtime detection evidence for that obligation."
      strength: secondary
  nist_ai_rmf:
    - function: Measure
      subcategory: MS.2.10
      context: "NIST AI RMF MS.2.10 (privacy risk examined and documented) is supported by this rule's detection of an MCP/agent tool reading .env or secret files without user consent (OSV-MCPS-2025-EB70F912)."
      strength: primary
    - function: Measure
      subcategory: MS.2.7
      context: "NIST AI RMF MS.2.7 (security and resilience evaluated and documented) is supported by this rule's detection of an MCP/agent tool reading .env or secret files without user consent (OSV-MCPS-2025-EB70F912)."
      strength: secondary
  iso_42001:
    - clause: "8.4"
      context: "ISO/IEC 42001 Clause 8.4 (AI system impact assessment) is operationalised by this rule's detection of an MCP/agent tool reading .env or secret files without user consent (OSV-MCPS-2025-EB70F912)."
      strength: primary
    - clause: "9.1"
      context: "ISO/IEC 42001 Clause 9.1 (monitoring, measurement, analysis and evaluation) is operationalised by this rule's detection of an MCP/agent tool reading .env or secret files without user consent (OSV-MCPS-2025-EB70F912)."
      strength: secondary

tags:
  category: context-exfiltration
  subcategory: mcp-consentless-secret-read
  scan_target: mcp
  confidence: high
agent_source:
  type: mcp_exchange
  framework:
  - any
  provider:
  - any
detection:
  condition: any
  false_positives:
  - Natural-language prose that merely mentions a .env / secrets file ("create a .env file with your API key", "if you have a .env file in your project root") with no read-tool call or JSON path argument.
  - "The CLI flag form `node --env-file=.env` or `--env-file <path-to-.env>` — an interpreter loading its own config, not an agent read-tool ingesting the file content for the model."
  - "`dotenv.config()` / `load_dotenv()` in normal application source — runtime config loading by the app itself, not an MCP read tool surfacing secrets to the agent."
  - Searching/listing for the file (`find . -name ".env" -type f`) without reading its contents.
  - A read tool whose path argument targets a NON-secret config file (config.json, README.md, src/index.ts).
  conditions:
  - field: content
    operator: regex
    value: (?i)\b(?:read_?file|readfile|read_text|read_secret|get_?file|load_?file|cat_?file|fs[._]read(?:file)?|open_?file|file_read|read)\s*\(\s*(?:file_?path|path|file)?\s*=?\s*["\x27](?:[^"\x27<>]{0,120}[\\/])?(?:\.?env(?:\.[\w.]+)?|secrets?(?:\.\w+)?|credentials|\.npmrc|\.netrc)["\x27]
    description: A read/fs tool invoked in function-call form whose quoted path argument targets a .env or secret file (e.g. read_file(".env"), Read(file_path="/app/.env.local"), open_file("secrets/.env")) — MCP-mediated consent-less secret read.
  - field: content
    operator: regex
    value: (?i)"(?:file_?path|path|file|filename|target|src|source)"\s*:\s*"(?:[^"<>]{0,120}[\\/])?(?:\.?env(?:\.[\w.]+)?|secrets?(?:\.\w+)?|credentials|\.npmrc|\.netrc)"
    description: A JSON tool_input object whose path/file key value targets a .env or secret file (e.g. {"path":".env"}, {"file_path":"~/project/.env"}) — structured MCP tool-call ingesting secrets without a consent gate.
response:
  actions:
  - alert
  message_template: >
    [ATR-2026-00583] An MCP/agent read tool is targeting a .env / secret file
    (.env, .env.local, secrets.*, credentials, .npmrc, .netrc) via its path
    argument with no consent gate (OSV-MCPS-2025-EB70F912, CWE-200/CWE-922).
    This exfiltrates API keys, DB credentials and other secrets into the model
    context by default. Remediation: require an explicit user-consent prompt
    before any tool reads secret files; add a read-deny rule for .env / secret
    patterns in the agent settings (e.g. ~/.claude/settings.json deny list);
    keep .env in .gitignore / .claudeignore; prefer a real secrets manager over
    plaintext .env files and rotate any credentials already exposed.
  notify:
  - security_team
confidence: 80
wild_fp_rate: 0
test_cases:
  true_positives:
  - input: '{"tool":"read_file","arguments":{"path":".env"}}'
    expected: triggered
    description: MCP read_file tool with JSON path argument targeting a bare .env file
  - input: Read(file_path="/app/.env.local")
    expected: triggered
    description: Claude Code Read tool function-call ingesting .env.local without consent
  - input: '{"name":"fs.read","path":"config/.env"}'
    expected: triggered
    description: fs.read MCP tool with JSON path key targeting a project .env file
  - input: read_file("/proj/.env")
    expected: triggered
    description: Function-call read of an absolute-path .env file
  - input: readFile(".env.production")
    expected: triggered
    description: camelCase readFile tool targeting a .env.production secret file
  - input: '{"tool":"fs.readFile","file_path":"~/project/.env"}'
    expected: triggered
    description: JSON file_path key with home-relative .env path in an fs.readFile tool call
  - input: open_file("secrets/.env")
    expected: triggered
    description: open_file tool reading a .env under a secrets directory
  - input: load_file("/srv/app/credentials")
    expected: triggered
    description: load_file tool reading a credentials secret file argument
  true_negatives:
  - input: 'If you have a `.env` file in your project root, the skill will load it for configuration.'
    expected: not_triggered
    description: NL prose mentioning .env, no read-tool call or JSON path argument (owned-by-prose, not a tool invocation)
  - input: Create a .env file with your API key APIFY_TOKEN=your_token
    expected: not_triggered
    description: Tutorial instruction to create a .env file, not a read-tool reading its contents
  - input: node --env-file=.env scripts/run.js
    expected: not_triggered
    description: Node CLI --env-file flag loading its own config, not an agent read tool surfacing secrets
  - input: Use `--env-file <path-to-.env>` with all commands
    expected: not_triggered
    description: Documentation of the --env-file CLI flag, not a tool-call path argument
  - input: find . -name ".env" -type f 2>/dev/null | head -5
    expected: not_triggered
    description: Searching/listing for .env files, no content read
  - input: dotenv.config()
    expected: not_triggered
    description: App-side dotenv runtime config loading, not an MCP read tool
  - input: 'The application loads .env files at startup using the dotenv package for configuration.'
    expected: not_triggered
    description: Prose describing dotenv usage, no tool invocation
  - input: read_file("config.json")
    expected: not_triggered
    description: Read tool targeting a non-secret config.json file
  - input: '{"path":"src/index.ts"}'
    expected: not_triggered
    description: JSON path argument targeting ordinary source, not a secret file
  - input: Read(file_path="README.md")
    expected: not_triggered
    description: Read tool targeting documentation, no secret-file path
  - input: 'If the user reports a credential leak, ask them whether ~/.aws/credentials was committed to git history.'
    expected: not_triggered
    description: Security advice prose referencing credentials, no read-tool path argument (owned by ATR-2026-00113)
_llm_authored:
  model: claude-opus (gstack subagent)
  generalization_note: >
    Carves a signature DISJOINT from the existing credential cluster by keying on
    the structured MCP/agent tool-call shape only: a read/fs tool NAME
    (read_file/readFile/fs.read/Read/open_file/load_file/...) immediately
    followed by a quoted PATH ARGUMENT (function-call or JSON path/file/file_path
    key) whose basename is a secret file (.env[.suffix], secrets.*, credentials,
    .npmrc, .netrc). ATR-2026-00115 requires a shell verb (cat|read|load|parse)
    directly preceding a bare ` .env` token and does NOT match read_file(".env")
    or {"path":".env"} (verified). ATR-2026-00113 keys on home-dir credential
    PATHS and cat/read of credential keywords; ATR-2026-00423 keys on NL
    imperatives; ATR-2026-00569/00578 require a traversal/normalization artefact.
    Bounded {0,120} path span keeps both regexes linear (no nested quantifier on
    backtrackable groups) avoiding catastrophic backtracking. The CLI flag form
    --env-file=.env, find-by-name, dotenv.config(), and prose mentions are all
    excluded because none present a read-TOOL-name + quoted secret path argument.
  note: Generation-time authoring; runtime detection is pure regex. Verified by the deterministic safety gate (0 FP across benign corpora + no cross-rule conflict). Human review required before any production promotion.

修訂歷史

建立於
2026-06-12
最後修改
2026-06-14
在 GitHub 查看完整 commit 歷史 →