From 5495024be923dc8dcaeacae0d4e4398154270b31 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 26 Mar 2026 04:50:59 +0000 Subject: [PATCH] feat: auto-redact detected PPI on send + standard fake values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Detected PPI is now auto-redacted in the fetch hook using RFC/standard reserved values — not just warned about: - IPs → 192.0.2.1 (RFC 5737 TEST-NET-1, never routed) - MACs → 00:00:00:00:00:00 - Addresses → 123 Example Street, Anytown, ST 00000 - GPS → 0.000000,0.000000 (Gulf of Guinea) - Dates → 01/01/1970 (Unix epoch) - EINs → 00-0000000 (impossible prefix) - Paths → /home/user - Git → example org These are obviously fake and guaranteed not to be real data, unlike random values which could be confused with actual PPI. New Options toggle: "Auto-redact detected PPI on send" (on by default). When on, PPI is caught in the fetch hook even if the user hits Enter immediately after pasting. Warning banner now says "Auto-redacted with standard placeholders" instead of "These were sent as-is." https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw --- src/content/content.js | 58 ++++++++++++++++++++++++---------------- src/lib/storage.js | 1 + src/options/options.html | 10 +++++++ src/options/options.js | 5 ++++ 4 files changed, 51 insertions(+), 23 deletions(-) diff --git a/src/content/content.js b/src/content/content.js index 443b86c..d109ae7 100644 --- a/src/content/content.js +++ b/src/content/content.js @@ -276,9 +276,27 @@ } // 4. Auto-detect: scan the FINAL text for unconfigured PPI + // Auto-redact if enabled, otherwise just warn if (settings.autoDetect !== false) { const warnings = autoDetectPPI(finalText, identity); if (warnings.length > 0) { + // Auto-redact detected PPI in the outbound text + if (settings.autoRedactDetected !== false) { + for (let i = warnings.length - 1; i >= 0; i--) { + const w = warnings[i]; + const fake = generateFake(w.name, w.value); + const escaped = esc(w.value); + const regex = new RegExp(escaped, 'g'); + finalText = finalText.replace(regex, fake); + allReplacements.push({ + original: w.value, + replaced: fake, + category: 'auto-detect', + pattern: w.name, + }); + } + } + // Still show the warning so user knows what was caught showAutoDetectWarning(warnings); } } @@ -1009,34 +1027,32 @@ // Pre-Send PPI Detection — scans as you type/paste (spellcheck style) // ============================================================ - // Generate plausible fake values for detected PPI + // Generate obviously-fake values using reserved/standard ranges + // These are recognizable as placeholders and guaranteed not to be real function generateFake(type, value) { switch (type) { case 'Private IP': case 'Public IP': - return '10.' + rnd(1,254) + '.' + rnd(1,254) + '.' + rnd(1,254); + // RFC 5737 — reserved for documentation, never routed + return '192.0.2.1'; case 'MAC Address': - return Array.from({length:6}, () => rnd(0,255).toString(16).padStart(2,'0')).join(':'); + return '00:00:00:00:00:00'; case 'Street Address': - const streets = ['Oak', 'Maple', 'Pine', 'Cedar', 'Elm', 'Main', 'Park', 'Lake']; - const types = ['St', 'Ave', 'Dr', 'Ln', 'Rd']; - return rnd(100,9999) + ' ' + streets[rnd(0,7)] + ' ' + types[rnd(0,4)]; + return '123 Example Street, Anytown, ST 00000'; case 'GPS Coordinates': - return (rnd(-90,90) + Math.random()).toFixed(6) + ',' + (rnd(-180,180) + Math.random()).toFixed(6); + return '0.000000,0.000000'; case 'Date (possible DOB)': - return (rnd(1,12) + '').padStart(2,'0') + '/' + (rnd(1,28) + '').padStart(2,'0') + '/' + rnd(1950,2005); + return '01/01/1970'; case 'EIN / Tax ID': - return rnd(10,99) + '-' + (rnd(1000000,9999999) + ''); - case 'Home Path': { - const fakeUser = 'user' + rnd(100,999); - if (value.startsWith('C:\\')) return 'C:\\Users\\' + fakeUser; - if (value.startsWith('/Users/')) return '/Users/' + fakeUser; - return '/home/' + fakeUser; - } + return '00-0000000'; + case 'Home Path': + if (value.startsWith('C:\\')) return 'C:\\Users\\user'; + if (value.startsWith('/Users/')) return '/Users/user'; + return '/home/user'; case 'Shell Prompt': - return 'user@computer:$ '; + return 'user@host:$ '; case 'Git Remote': - return value.replace(/[:/][^/\s]+\//, ':/anonymous/'); + return value.replace(/[:/][^/\s]+\//, ':/example/'); case 'Env Variable': return value.split('=')[0] + '=REDACTED'; default: @@ -1044,10 +1060,6 @@ } } - function rnd(min, max) { - return Math.floor(Math.random() * (max - min + 1)) + min; - } - // Pre-send warning UI let preSendWarningEl = null; let preSendTimer = null; @@ -1082,8 +1094,8 @@ ${items} ${more} `; diff --git a/src/lib/storage.js b/src/lib/storage.js index 9b8a2bc..0e6664e 100644 --- a/src/lib/storage.js +++ b/src/lib/storage.js @@ -20,6 +20,7 @@ const DEFAULT_SETTINGS = { revealMode: false, secretScanning: true, autoDetect: true, + autoRedactDetected: true, autoAddDetected: true, maxLogEntries: 200, customDomains: [], diff --git a/src/options/options.html b/src/options/options.html index 502a00a..facd3e3 100644 --- a/src/options/options.html +++ b/src/options/options.html @@ -67,6 +67,16 @@ +
+
+ +

Automatically replace detected PPI with generic placeholders (192.0.2.1, 123 Example Street, etc.) when sending

+
+ +
diff --git a/src/options/options.js b/src/options/options.js index 24fafcf..3ffe967 100644 --- a/src/options/options.js +++ b/src/options/options.js @@ -15,6 +15,7 @@ document.addEventListener('DOMContentLoaded', async () => { $('#showHighlights').checked = settings.showHighlights || false; $('#secretScanning').checked = settings.secretScanning !== false; $('#autoDetect').checked = settings.autoDetect !== false; + $('#autoRedactDetected').checked = settings.autoRedactDetected !== false; $('#autoAddDetected').checked = settings.autoAddDetected !== false; $('#maxLogEntries').value = settings.maxLogEntries || 200; @@ -47,6 +48,10 @@ document.addEventListener('DOMContentLoaded', async () => { await Storage.saveSettings({ autoDetect: e.target.checked }); }); + $('#autoRedactDetected').addEventListener('change', async (e) => { + await Storage.saveSettings({ autoRedactDetected: e.target.checked }); + }); + $('#autoAddDetected').addEventListener('change', async (e) => { await Storage.saveSettings({ autoAddDetected: e.target.checked }); });