fix(api): tighten redactSecrets after deep-review on #2188#2235
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: b336f6d The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
🔵 Tier 2 — Low RiskSmall, isolated change with no API route or data model modifications. Why this tier:
Review process: AI review + quick human skim (target: 5–15 min). Reviewer validates AI assessment and checks for domain-specific concerns. Stats
|
PR Review
|
E2E Test Results✅ All tests passed • 168 passed • 3 skipped • 1219s
Tests ran across 4 shards in parallel. |
Deep ReviewScope: 3 files on Intent: Tighten 🔴 P0/P1 -- must fix
🟡 P2 -- recommended
🔵 P3 nitpicks (4)
Reviewers (7): correctness, security, adversarial, testing, maintainability, kieran-typescript, project-standards. Testing gaps:
|
Deep-review on the merged #2188 surfaced three security/correctness gaps in the redactor; this PR addresses each. - `bearer` value class now includes `_`, so a JWT bearer token with underscores in its signature ("eyJ...AbC_DeF...") no longer terminates at the first underscore and leaks the trailing bytes past the [REDACTED] marker. base64url uses both "_" and "-"; the alphabet is now consistent with the `jwt` pattern. - `basic-auth-url` scheme allowlist now covers the database/queue connection strings most likely to land in observability payloads with embedded credentials: postgres(ql), mysql, mariadb, mongodb(+srv), redis(s), amqp(s), kafka, clickhouse. Previously these slipped through entirely while http(s)/ftp/ssh were redacted. - New `llm-vendor-key` pattern catches OpenAI ("sk-...") and Anthropic ("sk-ant-...") API keys. This redactor specifically fronts an LLM-provider call, so a vendor-shape key must not leak to the very provider that issued it. Floors at 20 chars after the prefix to avoid catching English fragments like "sk-ip" or "sk-line". Docstring now scopes the redactor explicitly to LLM input ("LLM-input only; not a general-purpose secret redactor"), per fleon's caveat on #2188 and the discovered gaps. Pattern coverage test, multi-secret integration test, and per-pattern regression tests cover each new shape plus the JWT-with-underscore regression. 53/53 unit tests pass. No OpenAPI / changeset surface change.
fc72404 to
7439838
Compare
Deep-review on the in-flight #2235 flagged two P0/P1 leak paths and two critical P2 bypass paths. This commit addresses each. - `llm-vendor-key`: add Google Gemini ("AIza..." with 35 trailing chars from [A-Za-z0-9_-]; full key is 39 chars). Without this branch a Gemini key in an observability payload reaches the very provider that issued it. - `basic-auth-url` scheme allowlist: add ws(s), sftp, mssql, sqlserver, snowflake, kafka+ssl, smtp(s), ldap(s), nats. Embedded credentials in those connection strings previously slipped through unredacted. Schemes now alphabetical for easier visual diffing. - `basic-auth-url` regex: add `i` flag. RFC 3986 declares schemes case-insensitive, so HTTPS://user:pass@host now redacts the same as the lowercase form. Previously an attacker could bypass redaction by upcasing the scheme. - `bearer` token alphabet: replace [A-Za-z0-9._~+/=_-]+ with \S+. RFC 6750's b64token alphabet is a strict subset of \S+, but real observability payloads carry plenty of opaque non-JWT bearers with ":", "%", or quote chars in them, and any narrower alphabet leaks the suffix past [REDACTED]. \S+ stops at whitespace, which is what actually terminates a bearer in practice. Tests cover each new shape: a Gemini key (positive + length-floor negative + bare-prefix negative), the 13-scheme parametric row for the extended allowlist (incidentally adding the missing mariadb case), uppercase + mixed-case scheme regressions, and three new opaque-bearer regressions (":", "%", and a "stops at whitespace" guard). Skipped from this commit and tracked elsewhere: the `/api/sk-...` path lookbehind false-positive (#2237) and the P3 nitpicks. 63/63 unit tests pass. No OpenAPI / API surface change. Tier 2.
|
Second-round commit 4181621 closes the four deep-review findings:
Skipped: the |
Summary
Follow-up to #2188 addressing three P0/P1 findings from the deep-review that fired ~20 minutes after merge.
bearervalue class now includes_. A JWT bearer token with underscores in the signature (base64url uses_) terminated at the first underscore, leaking the post-_tail past the[REDACTED]marker. The class is now[A-Za-z0-9._~+/=_-], consistent with thejwtpattern.basic-auth-urlscheme allowlist extended. The original allowlist(https?|ftp|ssh)missed every database/queue connection string most likely to appear in observability payloads with embedded credentials. Now coverspostgres(ql),mysql,mariadb,mongodb(+srv),redis(s),amqp(s),kafka,clickhouse.llm-vendor-keypattern. This redactor specifically fronts an LLM-provider call, so a leaked OpenAI / Anthropic key would be exfiltrated to the very provider that issued it. Pattern is\bsk-(?:ant-)?[A-Za-z0-9_-]{20,}\bso it catches OpenAI's 48+ char and Anthropic's longer formats while avoiding English fragments likesk-ip/sk-line.Docstring now scopes the redactor explicitly to LLM input ("LLM-input only. Do not use as a general-purpose secret redactor"), aligning with fleon's caveat on the original PR.
The deferred P2/P3 items from the same deep-review (false-positive on prose like "a bearer of bad news", JSON-quoted escaped quotes, oversized PEM, vendor tokens for Stripe/Twilio/Datadog/GCP, ReDoS bounds on
basic-auth-url, idempotence assertion, exact-shape vstoContain) are intentionally out of scope here. Several reshape behavior in ways that need a fresh look; tracked in #2237.Test plan
yarn jest src/utils/__tests__/redactSecrets.test.ts(53/53 passing, including the new JWT-with-underscore regression, postgres / mongodb+srv / mysql / redis / amqp / kafka / clickhouse cases, OpenAI / Anthropic / free-floatingsk-cases, and the multi-secret integration test extended with an LLM key)yarn workspace @hyperdx/api ci:lintclean (eslint + tsc + spectral)prose-lint --base origin/main --stagedclean