Skip to content

fix: strip plaintext API keys from usage SSE payloads - #1410

Open
dev-Vortex51 wants to merge 1 commit into
CalloraOrg:mainfrom
dev-Vortex51:security/issue-1264-strip-plaintext-keys-from-usage-sse-payloads
Open

dev-Vortex51 wants to merge 1 commit into
CalloraOrg:mainfrom
dev-Vortex51:security/issue-1264-strip-plaintext-keys-from-usage-sse-payloads

Conversation

@dev-Vortex51

Copy link
Copy Markdown

Overview

This PR removes the plaintext gateway API key from usage SSE payloads. Previously, handleProxy passed apiKey: apiKeyHeader into defaultUsageSseBroadcaster.emitForUser, and UsageSseEventPayload declared an apiKey field — so every live dashboard stream carried the raw key. This change drops the apiKey field from the payload type, emits only apiKeyId plus a masked prefix, updates the SSE docs, and adds a regression test that fails if the key string appears in any emitted event.

Related Issue

Changes

🔒 SSE Payload Redaction

  • [MODIFY] src/routes/usage/sse.ts

    • Removed the apiKey field from UsageSseEventPayload so the type no longer permits a plaintext key.
    • Emit only apiKeyId and a masked key prefix (e.g. sk-…abcd) in usage events.
    • Ensured no code path forwards the raw key into the broadcast payload.
  • [MODIFY] src/routes/proxyRoutes.ts

    • Stopped passing apiKey: apiKeyHeader into defaultUsageSseBroadcaster.emitForUser.
    • Passes apiKeyId and the masked prefix instead, keeping the raw header confined to the proxy request scope.

🧪 Regression Tests

  • [MODIFY] src/routes/usage/sse.test.ts

    • Asserts emitted events contain apiKeyId and the masked prefix but never the plaintext key.
    • Covers the payload shape against the updated UsageSseEventPayload type.
  • [ADD] src/__tests__/api-key-redaction-regression.test.ts

    • Regression test that fails if the key string appears in any emitted event across the usage SSE flow.

📝 Docs

  • [MODIFY] docs/usage-sse.md
    • Updated the event schema to reflect the removal of apiKey and the presence of apiKeyId + masked prefix.

Verification Results

npm test -- src/routes/usage/sse.test.ts src/__tests__/api-key-redaction-regression.test.ts
✅ passed
Acceptance Criteria Status
SSE events contain apiKeyId but not the plaintext key ✅ apiKey removed from payload; only apiKeyId + masked prefix emitted
The TypeScript payload type no longer has an apiKey field ✅ UsageSseEventPayload updated in src/routes/usage/sse.ts
docs/usage-sse.md reflects the new schema ✅ Schema updated to drop apiKey, document apiKeyId + masked prefix
A regression test fails if the key appears in any emitted event ✅ Added src/__tests__/api-key-redaction-regression.test.ts

Security & Failure-Mode Handling

  • The raw key is no longer serialized into any SSE payload, closing the leak to browser extensions, proxy-buffered logs, and any client that can open the stream.
  • Redaction is enforced at the type level (no apiKey field) and at the emit site (only apiKeyId + masked prefix), so a future caller cannot reintroduce the key without a type error.
  • The regression test guards against accidental reintroduction of the plaintext key in emitted events.

Compatibility

  • The SSE event schema is a breaking change for any consumer reading apiKey; consumers should switch to apiKeyId and the masked prefix. Docs are updated accordingly.
  • No unrelated refactors, dependency changes, or validation weakening.

Closes #1264

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.

Strip plaintext keys from usage SSE payloads

1 participant