mcp-scan rule
Data exfiltration vector
exfiltration-vectorhighWhat mcp-scan saw
Three separate triggers in the AST scanner share this id. Per argument, a dotted-quad IP or a domain-shaped token that is not path-like, not a known file extension, and not in allowedDomains pushes MEDIUM. Then HIGH fires when a ${VAR} reference and a network endpoint both appear in the arguments, and again when the arguments carry filesystem access (/, ~, a /Users or /home prefix, or a .ssh or .env substring) alongside any http(s):// in the command.
Why it fires
The first trigger just inventories outbound endpoints. The two HIGH triggers are about pairing: a variable next to a destination means a value you consider secret enough to hold in env is being handed to a host, and filesystem reach next to a network reach means one process can do both halves of a transfer without anything in between to stop it.
When this is a false positive
- The domain shape is scheme-optional, so any dotted token with a 2-plus character last segment counts. A version pinned as pkg@1.2.30 matches, since 30 is two characters and is not in the file-extension allowlist.
- The filesystem-plus-network trigger fires on the standard filesystem server config: a /Users path argument plus any https:// anywhere in the command line is enough, and that is what the reference server-filesystem setup looks like.
- A file path with an uncommon extension, for example config.internal or data.parquet, is read as a domain because the extension allowlist is a fixed set of about 50 entries.
- The ${VAR}-plus-endpoint trigger does not check what the variable holds. A ${PORT} or ${REGION} next to an API base URL is the same signal as a token next to an attacker host.
How to fix it
- Populate allowedDomains in .mcp-scan.json with the hosts this server is meant to reach. The scanner matches on domain suffix, so listing example.com covers api.example.com but not evil-example.com.
- Re-scan. Allowed hosts stop counting as external endpoints and both the MEDIUM inventory finding and the network half of the HIGH triggers drop out.
- For the filesystem-plus-network case, narrow the path argument to the project directory. A path deeper than the /Users or /home root no longer matches the filesystem test.
- If a version pin or a file path is being read as a domain, move it out of args into an env var, or pin with a separate --version argument.
- If the pairing is real, split the server so the tool that reads the disk is not the tool that reaches the network.