MM-67547: Sanitize Bifrost provider errors before log and user surfaces#579
MM-67547: Sanitize Bifrost provider errors before log and user surfaces#579nickmisasi wants to merge 2 commits intomasterfrom
Conversation
Redact API keys and tokens from Bifrost error messages using shared llm sanitization (ported from mattermost-plugin-agents OpenAI path). Made-with: Cursor
🤖 LLM Evaluation ResultsOpenAI
❌ Failed EvaluationsShow 1 failuresOPENAI1. TestReactEval/[openai]_react_cat_message
Anthropic✅ Overall: 19/19 tests passed (100.0%)
This comment was automatically generated by the eval CI pipeline. |
There was a problem hiding this comment.
Stale comment
Security Review: No Issues Found
This PR adds proper redaction of API keys and secrets from Bifrost provider error messages across all error surfaces (streaming, embeddings, transcription, model listing). The implementation is sound:
- Regex patterns cover the major provider key formats (OpenAI, Anthropic, bearer tokens, JSON fields), plus a configured-key fallback.
regexp.QuoteMetaprevents regex injection from the configured key, and Go's RE2 engine prevents ReDoS.- All downstream code paths that consume these errors use
.Error(), which returns the sanitized message.- The
Unwrap()chain preserves the original error forerrors.Is/errors.Ascompatibility — standard Go practice. No current code path traverses the error chain in a way that would expose unsanitized content.No medium, high, or critical vulnerabilities identified.
Sent by Cursor Automation: Find vulnerabilities
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI (base), Organization UI (inherited) Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughThis PR adds provider-error sanitization utilities and integrates them into Bifrost components by storing API keys on provider structs and passing errors through Changes
Sequence Diagram(s)(Skipped — changes are primarily error sanitization plumbing and new utility, not a multi-actor control flow requiring sequence diagrams.) Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@bifrost/bifrost.go`:
- Around line 36-37: The LLM struct currently stores only apiKey causing AWS
creds to be omitted from redaction; add a field like redactionSecrets []string
on the LLM/bifrost struct, populate it from cfg.APIKey, cfg.AWSAccessKeyID and
cfg.AWSSecretAccessKey when constructing the struct, and remove the single
apiKey-only usage, then update llm.SanitizeProviderError to accept variadic
secrets (...string) and change all call sites to pass b.redactionSecrets...
(e.g., where SanitizeProviderError(...) is invoked) so Bedrock/AWS credential
values are included in the redaction set.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro
Run ID: b8def679-242d-4b6f-b680-6d6ea6632590
📒 Files selected for processing (6)
bifrost/bifrost.gobifrost/embeddings.gobifrost/models.gobifrost/transcription.gollm/provider_error.gollm/provider_error_test.go
| apiKey string // used only to redact configured secrets from provider error surfaces | ||
| defaultModel string |
There was a problem hiding this comment.
Don't drop Bedrock credentials from the redaction set.
LLM now retains only cfg.APIKey, but this config also accepts AWSAccessKeyID and AWSSecretAccessKey. Those never reach llm.SanitizeProviderError, so a Bedrock auth error that echoes either value will still leak it through the new streamed error paths. Please carry a full secret list here instead of a single API key.
🔐 Suggested direction
type LLM struct {
client *bifrostcore.Bifrost
provider schemas.ModelProvider
- apiKey string // used only to redact configured secrets from provider error surfaces
+ redactionSecrets []string
defaultModel string
inputTokenLimit int
outputTokenLimit int
streamingTimeout time.Duration
@@
return &LLM{
client: client,
provider: cfg.Provider,
- apiKey: cfg.APIKey,
+ redactionSecrets: []string{
+ cfg.APIKey,
+ cfg.AWSAccessKeyID,
+ cfg.AWSSecretAccessKey,
+ },
defaultModel: cfg.DefaultModel,
inputTokenLimit: cfg.InputTokenLimit,Then widen the llm.SanitizeProviderError(...) helpers to accept ...string and pass b.redactionSecrets... at the call sites.
Also applies to: 200-200
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@bifrost/bifrost.go` around lines 36 - 37, The LLM struct currently stores
only apiKey causing AWS creds to be omitted from redaction; add a field like
redactionSecrets []string on the LLM/bifrost struct, populate it from
cfg.APIKey, cfg.AWSAccessKeyID and cfg.AWSSecretAccessKey when constructing the
struct, and remove the single apiKey-only usage, then update
llm.SanitizeProviderError to accept variadic secrets (...string) and change all
call sites to pass b.redactionSecrets... (e.g., where SanitizeProviderError(...)
is invoked) so Bedrock/AWS credential values are included in the redaction set.
|
/update-branch |
There was a problem hiding this comment.
Security Review: No Issues Found
This PR adds proper redaction of API keys and secrets from Bifrost provider error messages across all error surfaces (streaming chat/responses, embeddings, transcription, model listing). The implementation is sound:
- Regex injection safe:
regexp.QuoteMetais correctly used on the configured API key before building the replacement regex, preventing attacker-controlled keys from injecting regex patterns. Go's RE2 engine also prevents ReDoS. - All Bifrost error paths covered: Every
bifrostErr.Error.Messagesite is now wrapped withSanitizeProviderError. Unwrap()chain is safe: TheSanitizedProviderError.Unwrap()returns the original unsanitized error, which is standard Go practice forerrors.Is/errors.Ascompatibility. I verified that no downstream code in the repository traverses the error chain to extract.Error()from the unwrapped original — all consumers (streaming/streaming.goL465,llm/stream.goL84,api/api_llm_bridge.goL227) call.Error()on the top-level wrapper, which returns the sanitized message.- Pattern coverage: Regex patterns cover OpenAI keys (
sk-*,sk-proj-*), Anthropic keys (sk-ant-*), Bearer authorization headers, JSONapiKeyfields, and the "Incorrect API key provided" message format. The configured key fallback catch-all handles provider-specific key formats not matched by the static patterns. - Stored
apiKeyfield: The field is unexported (lowercase), not serialized, and only used for redaction comparisons — no new exposure surface.
No medium, high, or critical vulnerabilities identified.
Sent by Cursor Automation: Find vulnerabilities


Summary
Upstream LLM providers sometimes echo credential material inside error bodies (for example incorrect API key messages, bearer tokens, or JSON
apiKeyfields). This change redacts those patterns before Bifrost errors are returned, streamed to clients, or logged.Changes
llm.SanitizeProviderError/SanitizeProviderErrorMessagewith the same redaction approach used elsewhere for OpenAI-style errors (regex passes plus configured-key replacement, then non-printable character sanitization).Ticket
https://mattermost.atlassian.net/browse/MM-67547
Summary by CodeRabbit
New Features
Bug Fixes
Tests