Skip to content

orchestrate: redact quoted JSON keys and whole values in redactBody - #250

Open
h-kod wants to merge 3 commits into
cursor:mainfrom
h-kod:fix/redact-quoted-json-keys
Open

orchestrate: redact quoted JSON keys and whole values in redactBody#250
h-kod wants to merge 3 commits into
cursor:mainfrom
h-kod:fix/redact-quoted-json-keys

Conversation

@h-kod

@h-kod h-kod commented Aug 23, 2026

Copy link
Copy Markdown

What

redactBody's SENSITIVE_ASSIGNMENT_RE wraps the key alternatives in \b. A key that sits next to a quote character - exactly how it appears in a pasted JSON body - never matches, because " is a non-word character and the boundary logic inverts at it:

{"Authorization": "Bearer eyJhbG.sig"}   -> no redaction, reasons: []
{"api_key": "sk-123", "name": "x"}       -> no redaction, reasons: []

The same pattern also stops the value at the first space (\S+), which is #242's point: api_key = super secret value here kept the tail (secret value here") in the returned body.

The fix

Two changes to the one pattern:

  1. Optional surrounding quotes on the key - "?"key"?", so quoted JSON keys match while bare keys keep matching as before.
  2. Lazy whole-value capture instead of \S+ - the value runs to a real assignment boundary: end of line, an unquoted , / ; / } (JSON-ish contexts), or the closing quote. Values containing spaces (Bearer <jwt>) are redacted whole.

Behaviour preserved:

password: hunter2                        -> password=[redacted]
blocked: docker rate-limit on redis:7    -> unchanged (no sensitive key)
the authorization header was missing     -> unchanged (no assignment)

Relation to #242

#242 (open PR) fixes the value-side truncation. This PR fixes the key side - the \b-vs-quote interaction that lets pasted JSON bodies through with zero redaction - which that PR does not touch; its own before/after examples still leak when the body is JSON-shaped. Both changes compose cleanly; happy to rebase on whichever lands first.

Tests

Extended redact-body.test.ts with the quoted-JSON case, values containing spaces, and non-redaction of ordinary prose. 6/6 passing locally (repo tests run under bun:test; verified with a local vitest shim since bun is not installed on this machine).

Note for reviewers: the value-boundary regex treats ' and " inside unquoted values as terminators, so a secret containing a literal quote character would be truncated there. That is strictly better than the current behaviour (which truncated at the first space) and keeps the pattern a single pass; flagging it deliberately rather than over-fitting the regex.


Note

Medium Risk
Touches secret-redaction regex used before posting comment bodies. The change is defensive, but incomplete matching can still leak credentials, so the new patterns need careful review.

Overview
Fixes redactBody leaking secrets in pasted JSON and space-containing values. Quoted keys like "api_key" now match, and values are redacted as a whole instead of stopping at the first space (Bearer <jwt> tails no longer leak).

Quoted values now close with the same quote that opened them (so apostrophes inside "it's a secret" are not treated as terminators). Unquoted values run to , / ; / } and consume that separator so the assignment actually matches.

Tests cover JSON bodies, spaced quoted values, unquoted separator cases, and inner apostrophes.

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

SENSITIVE_ASSIGNMENT_RE wrapped the key alternatives in \b, so a key that
sits next to a quote character - exactly how it appears in a pasted JSON
body like {"api_key": "sk-123"} or {"Authorization": "Bearer eyJ..."} -
never matched, and the secret went out unredacted. The pattern also
stopped the value at the first space (\S+), leaking the tail of
`Bearer <jwt>`-style values.

Allow optional surrounding quotes on the key, and match the value lazily
up to a real assignment boundary (end of line, a JSON-ish separator,
or the closing quote) so the value is redacted whole. Keys without a
sensitive match are returned unchanged; non-assignment prose ("the
authorization header was missing") still passes through untouched.

New tests cover the quoted-JSON case, values containing spaces, and the
non-redaction of ordinary prose.
Comment thread orchestrate/skills/orchestrate/scripts/core/redact-body.ts Outdated
Cursor Bugbot flagged that SENSITIVE_VALUE_RE stopped at , ; } without
consuming them, so for unquoted assignments the combined pattern failed
to match entirely - no redaction ran and the raw secret passed through
(password: hunter2, keep kept hunter2). Make the separator optional in
the match so it is consumed, ending the value at the boundary.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON, but it could not run because the branch was deleted or merged before autofix could start.

Reviewed by Cursor Bugbot for commit 2bfdfc9. Configure here.

Comment thread orchestrate/skills/orchestrate/scripts/core/redact-body.ts Outdated
Bugbot round 2 flagged that the first fix merged double and single quote
handling into a single character class (["'][^"']*["']?), so a JSON
double-quoted value containing an apostrophe ended at it and the secret
tail leaked (e.g. {"password": "it's a secret123"} kept "s a secret123").

Split the value arms back apart and let the opening quote decide the
closing one: a double-quoted value runs to its closing ", a single-quoted
value to its closing ', both honoring backslash escapes, and an unquoted
value still consumes one optional , ; } terminator (round 1 behaviour).
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