Skip to content

fix(sentry): protect the rootkey by key name, not value shape#204

Merged
gmaclennan merged 1 commit into
mainfrom
claude/root-key-assumptions-review-vxeafa
Jul 16, 2026
Merged

fix(sentry): protect the rootkey by key name, not value shape#204
gmaclennan merged 1 commit into
mainfrom
claude/root-key-assumptions-review-vxeafa

Conversation

@gmaclennan

Copy link
Copy Markdown
Member

Closes #77. Replaces #196.

#196 proposed an exact-shape base64-22 value rule to catch bare (unmarked) rootkey tokens. Stepping back from that design: the value-shape approach hard-codes the wire encoding in places nothing keeps in sync with backend/index.js's validator (and the encoding has changed before — the legacy app stored the key as hex, see LegacyRootKeyDecoder, an encoding a base64 rule structurally cannot match without redacting every trace id). Meanwhile, tracing the key end-to-end shows every realistic leak shape carries the rootKey field name right next to the value: the key exists as a base64 string only inside the init frame (native → control socket → backend); it never enters the RN JS layer at all, and past the init handler it is a Buffer whose accidental serialisations (hex dump, byte array) a base64 rule would not match anyway.

So this PR filters on the key, not the value's shape, and fixes the holes the bare-token rule was compensating for:

  1. Marker rule reaches quoted values. The rootKey marker regex now consumes an optional quote after the separator. Previously {"rootKey":"…"} (a logged init frame) and rootKey: '…' (a console.warn'd message object, exactly what util.format produces) both passed through unredacted — verified against the old regex. These are the two realistic leak shapes.
  2. Key-named object fields redact regardless of encoding. rootKey/root_key/root-key joins lat/lng in SENSITIVE_KEY_PATTERN, so a structured {rootKey: …} in extra/contexts/breadcrumb data is redacted whatever the value looks like — base64, hex, or anything future. (The walker already did this for coordinates; the rootkey was the inconsistency.)
  3. Capture sites stop logging payloads. simple-rpc.js logged the full message object on the invalid-message path — on the very socket the init frame travels — and both simple-rpc.js and comapeo-rpc.js logged the parse Error on messageerror, whose message embeds a snippet of the raw input under V8 ("…{"rootKey":"MDEy…" is not valid JSON). They now log only the frame type / error name. With the debug-only consoleIntegration on, these were the only real paths for a key to reach a Sentry payload.

There is deliberately no value-shape rule for bare unmarked tokens; the decision and its rationale are documented in both scrubber copies and docs/sentry-integration.md §8. The rootkey metric tag-name ban already covers the realistic metrics mistake, so no tag-value scan is added either.

Tests: shared cases in test-support/scrubber-cases.js cover the JSON-quoted, util.inspect-quoted, and root_key-variant forms (and pin that bare tokens still pass, as a deliberate decision); both scrubEvent suites assert key-field redaction works on a hex value to prove encoding-independence; a new simple-rpc test drives real sockets with an unknown-type frame and a truncated init frame each carrying a key and asserts no key material reaches the console.

Verified with npm run lint, npm run build, npm run test (78 passed), npm run backend:test (97 passed), plus a generative check: 1,000 random 16-byte keys through the logged-frame and inspected-object shapes — 0 leaks.

🤖 Generated with Claude Code

https://claude.ai/code/session_01F1HTHPYkoyjjcvLgsUpvMk


Generated by Claude Code

Replaces the proposed bare-token base64-22 value rule (#196) with
key-based filtering, and closes the gaps it was compensating for:

- The rootKey marker regex now consumes an optional quote after the
  separator, so the two realistic leak shapes — a logged init frame
  ({"rootKey":"…"}) and a console-formatted message object
  (rootKey: '…') — redact. Previously both passed through untouched.
- Object fields keyed rootKey/root_key/root-key are redacted by the
  walker regardless of value type or encoding, matching what the
  scrubber already did for lat/lng keys. A key-based rule keeps working
  if the wire encoding ever changes (the legacy app stored the key as
  hex — see LegacyRootKeyDecoder).
- The IPC servers no longer log frame payloads: simple-rpc logs only
  the frame type for invalid messages, and both simple-rpc and
  comapeo-rpc log only the parse error NAME on messageerror (V8's
  JSON.parse SyntaxError embeds a snippet of the raw input, which for
  a mangled init frame includes rootkey bytes).

There is deliberately no value-shape rule for bare unmarked tokens: the
key exists as a base64 string only inside the init frame, always next
to its field name (it never enters the RN JS layer); everywhere else it
is a Buffer whose accidental serialisations (hex dump, byte array) a
base64 rule would not match anyway. Notes in both scrubber copies and
docs/sentry-integration.md §8 document the decision.

Closes #77

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F1HTHPYkoyjjcvLgsUpvMk
@github-actions github-actions Bot added the fix Bug fix (changelog) label Jul 11, 2026
@gmaclennan
gmaclennan added this pull request to the merge queue Jul 16, 2026
Merged via the queue into main with commit de8953e Jul 16, 2026
21 checks passed
@gmaclennan
gmaclennan deleted the claude/root-key-assumptions-review-vxeafa branch July 16, 2026 15:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix Bug fix (changelog)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sentry: narrower scrub rule for bare rootkey-shaped tokens (base64-22)

2 participants