Configuration & Environment
MCP server passes a string-literal key to a cryptographic primitive (AES, HMAC, JWT signing, Fernet) — committed to source, the key is permanently compromised.
Once a cryptographic key lands in a git history, it must be considered public. Rotating requires re-issuing every artifact signed with the key, which most teams never finish. The right pattern is keys-from-environment (or a secret manager): the key never appears in the repo.
MCP servers ship as packages — published to npm or PyPI, installed by users, sometimes audited via package-scanning tools. A hardcoded key in such a package is broadcast to every install. The trust boundary is implicit but real: an MCP server's signing key should be unique per deployment, not shipped with the code.
import jwt |
JWT_KEY = "my-super-secret-key-please-dont-leak" |
def sign(claims: dict) -> str: |
return jwt.encode(claims, JWT_KEY, algorithm="HS256") |
import jwt |
import os |
JWT_KEY = os.environ["JWT_SIGNING_KEY"] |
def sign(claims: dict) -> str: |
return jwt.encode(claims, JWT_KEY, algorithm="HS256") |
MCPSafe flags calls to `jwt.encode`, `Fernet(...)`, `hmac.new(...)`, `crypto.createHmac`, and similar cryptographic constructors where the key argument is a string literal. Calls reading from `os.environ`, `process.env`, or a secret-manager client are exempted.
See the full threat catalog for every documented detection.
MCPSafe runs this check — and every other rule in the catalog — on any MCP server you paste in.
Scan now