Skip to content

fix(logs): mask sk-proj/sk-svcacct/sk-admin OpenAI keys - #1762

Merged
Dumbris merged 1 commit into
smart-mcp-proxy:mainfrom
rudycelekli:fix/log-sanitizer-openai-project-keys-20261023-01
Oct 25, 2026
Merged

Dumbris merged 1 commit into
smart-mcp-proxy:mainfrom
rudycelekli:fix/log-sanitizer-openai-project-keys-20261023-01

Conversation

@rudycelekli

Copy link
Copy Markdown
Contributor

Bug

The log sanitizer's openai_key pattern is \b(sk-[A-Za-z0-9]{20,})\b, which only matches the legacy OpenAI key format. Current keys are sk-proj-…, sk-svcacct-… and sk-admin-…, with _ and - in the random suffix. The hyphen four characters in breaks the 20-alphanumeric run, so these keys are never matched. In free text, with no =/: before them for high_entropy to catch, they are logged in full.

The audit redactor (internal/audit/redact.go) and the security pattern set (patterns/tokens.go) were already updated for these formats; the log sanitizer was not.

Trigger

logger.Info("using key sk-proj-AbCdEf1234567890_GhIjKl-MnOpQrStUvWxYz0123456789 for upstream")

On main the key is written to the log unchanged.

Fix

Extend the pattern with a (proj|svcacct|admin)- branch that allows _ and - in the suffix. The legacy branch stays alphanumeric, so sk-ant-… keys still fall through to the more specific anthropic_key pattern and keep its mask.

Test

TestSanitizer_OpenAIProjectAndServiceAccountKeys checks that the project, service-account, admin and legacy keys are all masked, and that an sk-ant-api03-… key is still masked by anthropic_key (sk-ant-api***).

Commands run

  • CGO_ENABLED=0 go test -count=1 ./internal/logs: ok
  • With the fix reverted (git stash of sanitizer.go), the new test fails for the sk-proj-, sk-svcacct- and sk-admin- keys with OpenAI key leaked.
  • gofmt -l on the edited files: no output

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@Dumbris Dumbris left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified: the new test fails on main (sk-proj-/sk-svcacct-/sk-admin- keys were logged in full) and passes here; sk-ant- keys still reach anthropic_key, and words like task-proj-… are not matched. Race tests and CI lint for internal/logs are clean, combined with #1760 and #1761, cross-reviewed.

@Dumbris
Dumbris merged commit 1e11118 into smart-mcp-proxy:main Oct 25, 2026
46 checks passed
@Dumbris

Dumbris commented Oct 25, 2026

Copy link
Copy Markdown
Member

Merged. Thank you, @rudycelekli! Current OpenAI keys (sk-proj-, sk-svcacct-, sk-admin-) were written to the logs in full; the log sanitizer now masks them like the audit redactor already did.

Contributions like this are what keep MCPProxy moving, and they matter a lot to the project.

One small ask, only if you feel like it: a short public note about your change (a tweet, a LinkedIn post, a line in a community you are part of) helps more people discover MCPProxy. No pressure at all, and I would be glad to repost it.

Dumbris added a commit that referenced this pull request Oct 29, 2026
## Summary

Fixes two secret leaks in `internal/logs/sanitizer.go` that were already
on `main`.

**1. Bearer suffix leak (pattern order).** The patterns run one after
another over the rewritten string, and every mask inserts `***`, which
no pattern's character class accepts. `github_token`, `openai_key` and
`anthropic_key` ran before `bearer_token`. So when a Bearer credential
started with a known key prefix, the key pattern masked it first, and
bearer then stopped at the inserted `***`:

```
before: Bearer sk-AbCdEf1234567890GhIjKlMnOpQrStUvWxYz0123456789.EXTRA_SECRET
     -> Bearer sk-A***Ab***89.EXTRA_SECRET
after:  -> Bearer sk-A***ET
```

The same thing could happen inside a JWT: a key-shaped run after a `-`
in a segment got masked before `jwt` ran, and the payload and signature
were logged. The fix runs `bearer_token`, then `jwt`, before the
key-specific patterns. A comment above the patterns now states the
ordering rule.

**2. Unsigned JWT (`alg: none`).**
`eyJhbGciOiJub25lIn0.eyJzdWIiOiIxIn0.` has an empty third segment, and
the trailing `\b` could never match after a `.`, so the payload was
logged in clear. The third segment is now `[A-Za-z0-9\-_]*` and the
trailing `\b` is gone. The output is `header.***.***`.

Existing mask formats are unchanged. That includes the tests from #1760,
#1761 and #1762. A credential after `Bearer` now gets the Bearer mask
instead of the key mask.

## Testing

- New `internal/logs/sanitizer_pattern_order_test.go`: Bearer +
sk-/sk-proj-/ghp_/sk-ant- suffix, a JWT with a key-shaped run inside it,
and an unsigned JWT in four contexts. All of these failed before the
fix.
- `go test -race ./internal/logs/` passes.
- golangci-lint v2 (`.github/.golangci.yml`) reports 0 issues, both bare
and with `--build-tags server`.
- Cross-review (opencode gpt-6.1-sol, high): CLEAN.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

3 participants