Repository navigation
fix: keep UUIDs intact in scrubbed text - #7
Merged
Merged
Conversation
The catch-all scrub scanned inside UUIDs, so a group of digits in an id was taken for a phone number: `409cd08e-512e-4077-825e-001030608345` became `409cd08e-512e-4077-825e-[REDACTED]`. With the current patterns about 0.04% of random UUIDs are damaged; a damaged id no longer resolves or matches the same id elsewhere. scrubPlain now swaps every complete UUID for a private-use marker before the detectors run and restores it afterwards. A UUID cannot hold PII, and PII next to it is still found. Running per plain chunk keeps URLs working: components are decoded before they are scanned. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E3AAifuwHuKGdoVpqZoQAo
Only the IBAN and phone patterns can match digit runs inside a UUID, and none of them runs without a NUMBER_CANDIDATE hit. Masking now happens inside that branch, behind a cheap UUID hint, so most strings (labels, timestamps, bare ids) never reach it. Emails are matched on the unmasked text again, so a UUID used as an email's local part is pseudonymized with the email. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E3AAifuwHuKGdoVpqZoQAo
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E3AAifuwHuKGdoVpqZoQAo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The catch-all scrub (
scrubText) finds phone numbers inside UUIDs. A run of digits in an id matches the international phone pattern:About 0.04% of random UUIDs are affected with the current patterns; 0.2.x affected about 0.2%. A damaged id no longer resolves and no longer matches the same id elsewhere in the data.
This PR keeps complete UUIDs (
8-4-4-4-12hex, any case, also inside longer ids such asloop-edge-<uuid>) out of the IBAN and phone patterns:scrubPlain, the IBAN and phone replacements run with each UUID swapped for a private-use marker. The UUIDs are restored afterwards.Limits:
Performance
Added work. It happens only for strings that pass the existing
NUMBER_CANDIDATEcheck (an IBAN or phone candidate):UUID_HINT(no lookbehind).UUID_TOKEN(with lookbehinds) that builds a masked copy of the string.That is two to three extra full passes over the string, plus one extra string and a small array per string that contains a UUID. Strings without a candidate (most labels, timestamps and bare ids) run the same code as before.
Measured. Each variant ran in its own process; the numbers are the median of 5 runs. Node 22, one machine, synthetic strings plus 25 real stored configs.
mainscrub, 100k labels without hyphenscrub, 100k ISO timestampsscrub, 100k bare UUIDsscrub, 100k texts with a UUID and a phone numberanonymizeResponse, 16k mixed strings (as inperformance.test.ts)scrub, 25 real stored flow-template configs, 200 timesHow to read the numbers:
main, measured the same way, differed by −15% to +4% on the small workloads. Differences of about ±15% on the 30–40 ms rows are not distinguishable from noise.Test plan
npm run lint,npm test(99 existing + 5 new tests),npm run builduuid-protection.test.ts:mainon 200,000 random strings (UUIDs, phones, IBANs, emails, streets, timestamps, URLs, numbers, glued and separated):main;main's output for the same text with each UUID replaced by a neutral character;main.🤖 Generated with Claude Code
https://claude.ai/code/session_01E3AAifuwHuKGdoVpqZoQAo