Skip to main content
← All rules

mcp-scan rule

Env file secret exposed

env-secret-exposedhigh

What mcp-scan saw

Starting from the directory holding the MCP client config, the scanner walked up toward the filesystem root looking for .env, .env.local, .env.production, .env.development, or .env.staging, and stopped at the first directory containing any of them. In that file it flagged every key matching KEY, SECRET, TOKEN, PASSWORD, API_, AUTH_, CREDENTIAL, BEARER, CERT, PEM, PASSPHRASE, or SIGNING whose value is longer than 20 characters and does not contain your_, replace, example, placeholder, changeme, xxxxx, dummy, test123, or an angle bracket.

Why it fires

The value passed both the key-name test and the placeholder filter, which is the shape of a live credential rather than a template. The walk-up is what makes this useful: it finds the .env that would ship alongside a server, not just one sitting next to the config. It stops at the first directory with any matching file so it does not report the same key from every ancestor.

When this is a false positive

  • The key-name regex includes API_ as a prefix, so API_BASE_URL=https://api.example.com/v2/endpoint is a 40-character non-placeholder value under a matching key and reports as a secret. The same happens for AUTH_URL and AUTH_DOMAIN.
  • CERT and PEM match any key mentioning a certificate path. A value like CERT_PATH=/etc/ssl/certs/company-root.pem is a filesystem path, not a credential.
  • The .env found may belong to an unrelated project. The walk starts at the client config's directory, which for Claude Desktop or Cursor is a home or application-support directory, so the first .env up the tree can be your home directory's, with nothing to do with any MCP server.
  • The file may already be gitignored and local-only, which means the value is not exposed to anyone. The rule reports presence on disk, not reachability.

How to fix it

  1. Open the .env file named in the finding and look at the specific key it quotes.
  2. If the value is a URL or a path rather than a credential, rename the key so it does not start with API_ or AUTH_, for example API_BASE_URL becomes SERVICE_BASE_URL.
  3. If it is a real credential, confirm the file is in .gitignore, then check git log to see whether it was ever committed. If it was, rotate the credential; removing the file does not remove it from history.
  4. Move long-lived credentials into a secret manager or the OS keychain and have the launcher inject them, so the .env holds references rather than values.
  5. Re-scan. The rule reads only the first .env-bearing directory it finds walking up, so fixing that file clears the finding.