Skip to content

fix(server): redact sensitive env vars and headers from connection logs#1296

Open
SarthakB11 wants to merge 1 commit intomodelcontextprotocol:mainfrom
SarthakB11:fix/issue-847
Open

fix(server): redact sensitive env vars and headers from connection logs#1296
SarthakB11 wants to merge 1 commit intomodelcontextprotocol:mainfrom
SarthakB11:fix/issue-847

Conversation

@SarthakB11
Copy link
Copy Markdown

Closes #847.

Summary

The proxy logs the full incoming connection request to stdout in two places in server/src/index.ts:

  • console.log("Query parameters:", JSON.stringify(query)). query.env is a JSON-encoded map of process env vars supplied by the user, frequently containing *_TOKEN, *_KEY, *_SECRET, AWS_*, password, etc.
  • SSE transport: url=..., headers=.... headers regularly carries Authorization and similar.

Those values end up in the proxy's stdout and from there into terminals, shell history, log files, and screen recordings (the original scenario from #375). This PR sanitizes both log lines.

Change

Helpers live in a new server/src/redact.ts, imported by server/src/index.ts at both log sites:

  • SENSITIVE_KEY_PATTERNS: case-insensitive regexes for token, secret, password, passwd, credential, api[-_]?key, (^|_)key($|_), auth, session, private, ^aws_. The (^|_)key($|_) boundary avoids matching monkey while still catching API_KEY, KEY_VALUE, plain key.
  • redactSensitiveEntries(obj): shallow clone, keys preserved, sensitive values replaced with "***".
  • redactQueryForLogging(query): clones the query and re-serializes the embedded env JSON with sensitive entries redacted; falls back to "env": "***" if env isn't valid JSON, so a malformed payload can't spill raw.

Both call sites now log the redacted view; the live env and headers objects are still passed unchanged to the spawned transport / SSEClientTransport. Keys are kept in the log so users can still see which vars / headers were forwarded.

Scope notes

  • The patterns will over-redact some non-secret env vars (e.g. KEY_NAME, AUTHOR). This only affects the log line, not what the spawned process receives, and the trade-off favors over-redaction.
  • The command / args log a few lines below is intentionally left alone; shell args are already user-visible and not expected to carry secrets.
  • The streamable-HTTP path doesn't log headers today, so no change there. The helper is available if that ever changes.
  • redactSensitiveEntries is shallow. env is a string-to-string map and Express normalizes headers to a flat object, so this is sufficient today; deep redaction can be added if a future request shape nests secrets.

Test plan

server/ previously had no test runner. This PR adds a minimal node:test setup using tsx (already in server/devDependencies); zero new dependencies. New test script: server/package.json "test": "node --import tsx --test test/*.test.ts".

server/test/redact.test.ts covers:

  • common secret-bearing env vars redacted (GITHUB_TOKEN, AWS_ACCESS_KEY_ID); benign PATH preserved
  • bare KEY, API_KEY, api-key redacted
  • boundary check: MONKEY and KEYBOARD are NOT redacted (no false positives on words containing key)
  • Authorization header redacted
  • env JSON parsed and redacted entry-by-entry; non-secret entries preserved
  • malformed env falls back to "***" instead of leaking the raw payload
  • queries without env pass through unchanged

Run with: cd server && npm test (7 passed, 0 failed).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hide potentially sensitive env variables from being logged

1 participant