feat: auto-redact detected PPI on send + standard fake values
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
This commit is contained in:
+35
-23
@@ -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}
|
||||
<div class="ss-ad-footer">
|
||||
${settings.autoAddDetected !== false ? 'Click + to auto-add a mapping.' : ''}
|
||||
Add to Identity or Mappings to protect this data.
|
||||
${settings.autoRedactDetected !== false ? 'Auto-redacted with standard placeholders.' : 'These were sent as-is.'}
|
||||
${settings.autoAddDetected !== false ? ' Click + to add a permanent mapping.' : ''}
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ const DEFAULT_SETTINGS = {
|
||||
revealMode: false,
|
||||
secretScanning: true,
|
||||
autoDetect: true,
|
||||
autoRedactDetected: true,
|
||||
autoAddDetected: true,
|
||||
maxLogEntries: 200,
|
||||
customDomains: [],
|
||||
|
||||
@@ -67,6 +67,16 @@
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<div>
|
||||
<label>Auto-redact detected PPI on send</label>
|
||||
<p class="setting-desc">Automatically replace detected PPI with generic placeholders (192.0.2.1, 123 Example Street, etc.) when sending</p>
|
||||
</div>
|
||||
<label class="toggle">
|
||||
<input type="checkbox" id="autoRedactDetected" checked>
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<div>
|
||||
<label>Offer to auto-add detected PPI</label>
|
||||
|
||||
@@ -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 });
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user