Skip to main content
← All rules

mcp-scan rule

Env var scope leak

env-var-scope-leakmedium

What mcp-scan saw

The tool-poisoning scanner found a ${NAME} reference anywhere in the scan text (name, description, arguments, and every string inside the tool schemas) where NAME is neither a key in this server's env block nor present in the scanning process's own environment. Both checks are tried, including an uppercased form of the name.

Why it fires

An MCP server's env block is its declared surface. A reference to a variable outside that block means the server depends on ambient state the config does not describe, so the config no longer tells you what the server can read. The ambient-process check exists so that legitimately inherited variables do not report.

When this is a false positive

  • The variable is injected at launch by the client or a wrapper, from a keychain, a .env loaded by the launcher, or a shell profile that the scanning process did not source. It exists at runtime and not during the scan.
  • The scan environment differs from the run environment by design. CI scans and local runs will disagree on this rule for the same config.
  • A ${NAME} that is documentation rather than a reference, for example a description showing the expected shape of a value.
  • The reference is matched anywhere in the scan text including tool schema strings, so a template placeholder inside a tool's description fires even though nothing resolves it.

How to fix it

  1. Read the variable name from the finding and check whether it is set in the shell you scan from: printenv NAME.
  2. If the variable is real, declare it explicitly in the server's env block so the config describes its own dependencies.
  3. If it is injected by the client at launch, add it to the env block with a ${NAME} passthrough so the declaration is visible even though the value is not.
  4. If the ${NAME} is documentation, change it to a form that does not match, for example NAME_GOES_HERE without braces.
  5. Re-scan from the same environment the server runs in, since the check reads the scanning process's own environment.