Skip to content

orchestrate: redact the whole value in redactBody, not up to the first space - #242

Open
pucedoteth wants to merge 1 commit into
cursor:mainfrom
pucedoteth:fix-redact-body-auth-scheme
Open

orchestrate: redact the whole value in redactBody, not up to the first space#242
pucedoteth wants to merge 1 commit into
cursor:mainfrom
pucedoteth:fix-redact-body-auth-scheme

Conversation

@pucedoteth

@pucedoteth pucedoteth commented Aug 21, 2026

Copy link
Copy Markdown

What

redactBody's sensitive-assignment pattern matched \S+ after the :/=, so it stopped at the first space:

Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.SECRETPAYLOAD.sig
  ->  "Authorization=[redacted] eyJhbGciOiJIUzI1NiJ9.SECRETPAYLOAD.sig"   reasons: ["contains sensitive key"]

export TOKEN="my secret value"
  ->  "export TOKEN=[redacted] secret value\""                            reasons: ["contains sensitive key"]

In both cases the token is the part after the space, so the function redacted the scheme (Bearer) or the first word and left the credential in the returned text — while reasons reported a successful redaction.

Matching to end of line instead makes the returned text actually redacted:

  ->  "Authorization=[redacted]"
  ->  "export TOKEN=[redacted]"

Why

Authorization: Bearer <token> is the usual shape an auth header takes in the error output and logs that get pasted into a comment body, and it is the one shape the old pattern handled worst.

To be precise about impact: today's only caller is requireSafeCommentBody in cli/comments.ts, which throws whenever reasons is non-empty, so nothing currently reaches Slack with a leaked credential. The defect is in redactBody's own contract — it returns a text that is presented as redacted and isn't — so any caller that uses result.text, which is the obvious reading of the return shape, leaks. The branch also had no test coverage at all: the existing suite covered paths, SHAs, log dumps and size, but never the sensitive-key path.

. does not match newlines, so redaction still stops at the end of the offending line; there's a test for that.

How

One character class in SENSITIVE_ASSIGNMENT_RE (\S+\S.*), plus three tests. The two credential tests fail on main:

Expected: "Authorization=[redacted]"
Received: "Authorization=[redacted] eyJhbGciOiJIUzI1NiJ9.SECRETPAYLOAD.sig"

Expected: "export TOKEN=[redacted]"
Received: "export TOKEN=[redacted] secret value""

Full suite: 212 pass / 0 fail across 28 files. tsc --noEmit and biome check clean.

I left orchestrate/.cursor-plugin/plugin.json at 1.1.0 since version bumps look like a deliberate maintainer step in this repo — happy to bump it if you'd like it in the same PR.


Disclosure: written with AI assistance; the analysis, fix and tests were verified locally.


Note

Medium Risk
Touches secret-redaction logic used for comment bodies. The change is a small regex plus tests; current callers reject on reasons so this mainly closes a leak if result.text is used.

Overview
Fixes redactBody so sensitive assignments redact through end of line instead of stopping at the first space.

The old \S+ match left JWTs after Authorization: Bearer and quoted secrets in result.text while still reporting "contains sensitive key". Matching \S.* now yields KEY=[redacted] for those shapes, still line-scoped. Adds tests for Bearer tokens, quoted values, and neighboring lines.

Reviewed by Cursor Bugbot for commit 0e213ca. Bugbot is set up for automated code reviews on this repo. Configure here.

…t space

The sensitive-assignment pattern matched `\S+` after the separator, so it
consumed only the auth scheme in `Authorization: Bearer <jwt>` and only the
first word of a quoted value. `redactBody` returned "Authorization=[redacted]
<jwt>" with reasons reporting a successful redaction.

Match to end of line instead, and cover the branch with tests -- it had none.
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.

1 participant