All sensitive data (identity, mappings, activity log) is now AES-256
encrypted in browser.storage.local when sync encryption is enabled.
TOTP secret is also encrypted at rest using the derived key.
Vault unlock flow:
- On browser restart, extension detects locked state (encrypted data,
no cached CryptoKey) and shows LOCK badge in red
- Popup shows a full-screen unlock prompt with password field,
optional TOTP, and biometric button
- After unlock, background decrypts and broadcasts data to all tabs
- Content scripts start with empty config when locked; receive
decrypted config via vault:unlocked message after unlock
- Injector skips encrypted blobs in storage change events
Storage module changes:
- _readSecure / _writeSecure transparently encrypt/decrypt
- encryptExistingData() migrates plaintext → encrypted on setup
- decryptAllData() restores plaintext when encryption is disabled
- isLocked() checks for encrypted data + missing key
https://claude.ai/code/session_01SWSwDfMVij53bCTNSCLMwn
Sync encryption:
- AES-256-GCM encryption for all sync channels (browser sync, gist,
custom URL, folder sync, sync codes)
- Password with optional TOTP (RFC 6238) second factor
- Configurable auth TTL: session, 30/90/180/365 days, or never
- CryptoKey cached in IndexedDB — auth only needed when cache expires
AND new data exists (lastModified check runs before auth prompt)
- WebAuthn (biometric/PIN) as low-friction re-authentication gate
- Full options UI for setup, password change, and inline auth prompt
Smart reveal:
- Track which substitute values were actually sent outbound per session
- Reveal mode only replaces values that were genuinely substituted,
preventing false positives (e.g. AI using the word "user" won't be
replaced with a real username that maps to "user")
https://claude.ai/code/session_01SWSwDfMVij53bCTNSCLMwn
PPI + button fix:
- After adding a mapping, the real PPI value is now immediately replaced
with the fake value in the input/contenteditable element via the new
replaceInInput() helper (handles both <textarea>/<input> and
contenteditable divs by walking text nodes).
- Triggers a re-scan 150ms later so the pre-send warning updates or
dismisses itself if no more PPI remains.
Auto-sync folder (File System Access API):
- User picks a folder once per browser via "Choose Sync Folder".
Any settings/mappings/identity change writes silent-send-sync.json
to that folder automatically (via api.storage.onChanged listener).
- On options page open and every time the page regains focus, the file
is read back; if its lastModified is newer than local data, settings
are imported immediately and the UI refreshes.
- File handle is stored in IndexedDB (ss_sync_handles) so it persists
across browser sessions without repeated permission prompts.
- Pick the SAME folder in each browser (or a synced cloud folder for
cross-computer sync) — fully automatic after that, no copy-paste.
- sync.js gains saveSyncDirHandle / loadSyncDirHandle / clearSyncDirHandle
helpers backed by IndexedDB.
https://claude.ai/code/session_01TKpSR9M8JgHLXCp5CeDsQP
Bug fixes:
- Date (possible DOB) pattern now requires context words (born, birthday,
dob, etc.) before firing — prevents spurious warnings on page-load API
calls that happen to contain ISO dates in conversation history.
- Highlight regex now uses word boundaries (\b) so short substitute values
(e.g. "aud") no longer match inside unrelated words like "Claude".
- Both TreeWalkers in content.js now skip the extension's own UI elements
(.ss-autodetect-warning, .ss-presend-warning, .ss-reveal-badge) to
prevent the highlight API from marking text in the extension's banners.
Settings sync:
- New src/lib/sync.js: exportSyncCode / importSyncCode (base64 JSON) for
manual copy-paste across any browser combination. Newest lastModified
timestamp wins; force flag available to override.
- browser.storage.sync support: when "Browser account sync" is enabled the
extension automatically pushes/pulls via Firefox Sync or Chrome account,
chunked to stay within per-item quota limits.
- storage.js now writes ss_lastModified on every save so conflict resolution
has an accurate timestamp.
- service-worker.js listens for both local and sync storage changes to keep
all copies in sync.
- New "Sync Between Browsers" section in options.html with Generate/Copy/
Import Sync Code UI and the browser sync toggle.
https://claude.ai/code/session_01TKpSR9M8JgHLXCp5CeDsQP
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
Like spellcheck for privacy. Scans text as you type and paste
into chat inputs (debounced 800ms). Shows a dark floating warning
panel listing detected PPI BEFORE you hit Enter.
Each detected item has a green [+] button that instantly:
1. Generates a plausible fake value (random IP, fake address, etc.)
2. Adds it as a mapping to storage
3. Shows a checkmark to confirm
The warning disappears when you clear the text or when all
detected items have been addressed.
Three new Options toggles:
- Auto-detect unconfigured PPI (on by default)
- Offer to auto-add detected PPI (on by default)
Also adds a storage bridge (postMessage) so the page-world
content script can read/write chrome.storage through the
injector.
https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw
Scans outbound messages AFTER all substitutions for personal data
the user forgot to configure:
- Private/public IP addresses (skips 127.0.0.1, 8.8.8.8, etc.)
- MAC addresses
- Street addresses ("123 Main St")
- GPS coordinates
- Dates (possible DOBs)
- EIN/tax IDs
- Home directory paths not caught by smart patterns
- Shell prompts (user@host)
- Git remotes (reveals username/org)
- Environment variable assignments (HOME=, USER=, etc.)
Shows a floating dark warning banner (top-right, auto-dismisses
after 15s) listing each detected item with its type, value, and
hint. Skips values already in the user's identity config.
Also shows PPI warnings in the popup Test tab and adds toggle
in Options to disable auto-detect.
https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw
Two visual modes using the Highlight API (zero DOM modification):
- Yellow highlight: fake/substituted values the AI received.
Shows automatically in all AI responses, even without reveal mode.
"The AI sees these yellow values, not your real data."
- Terminal style (black bg, green text): your real data shown
in reveal mode. "This is YOUR data — the AI never saw this."
Uses CSS.highlights with ::highlight() pseudo-elements — no
spans, no DOM changes, no copy/paste artifacts. Falls back to
CSS class-based styling if Highlight API is unavailable.
Highlights are debounced (500ms) to handle streaming responses
without excessive reflows.
https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw
Revealed values are now wrapped in <span class="ss-revealed">
with a blue underline and subtle blue background, making it
obvious which parts are your real data vs what the AI said.
Hover shows tooltip "Substituted value: [fake]" so you can see
what the AI actually received. Un-reveal properly removes the
spans and normalizes text nodes.
https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw
After the multi-profile migration, ss_identity changed from a flat
object { names, emails, ... } to { profiles: [...] }. The injector
was passing the raw profiles wrapper to the content script, which
expected the flat format.
Now the injector merges active profiles into a flat identity object
before injecting into the page world, and also merges on storage
change events. Also handles legacy format (pre-profile data) for
backward compatibility.
https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw
Storage issue: Chromium/Brave keeps storage.local data even when
an unpacked extension is removed and reloaded. Added "Reset
Everything" button in Options → Danger Zone that clears all data
(double-confirm to prevent accidents).
Reveal mode: Now re-runs revealAllResponses() every 2 seconds
while active to catch streamed content and dynamically loaded
responses. Adds console logging for reveal toggle state changes
to aid debugging. Cleans up interval when reveal mode is turned off.
https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw
Interception is now completely inactive until the user configures
at least one identity field or explicit mapping. Before that:
- Icon shows gray (unconfigured)
- No fetch/XHR hooks fire
- First-run banner tells user to set up
Custom domains: clicking "Add Domain" in Options now triggers
the browser's native permission prompt via permissions.request().
No more manual chrome://extensions site access step.
Icon states are now:
- Gray = unconfigured (nothing will happen)
- Black = active and protecting
- Blue = reveal mode on
- Red = manually disabled
https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw
Activity log fix:
- Injector now writes directly to storage.local in addition to
sending runtime messages to the background worker. This fixes
the issue where MV3 service worker sleep caused messages to be
silently dropped.
Dynamic icon colors:
- Black "SS" = active, normal
- Blue "SS" = reveal mode on
- Red "SS" = Silent Send disabled
- Icons generated via OffscreenCanvas in the service worker
- Updates on every settings change and keyboard shortcut toggle
Also adds keyboard shortcuts section to Options page showing
current bindings and how to customize them per browser.
https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw
Adds a secret scanning layer that runs after identity/explicit
substitutions. Catches secrets the user didn't configure:
- API keys: OpenAI (sk-), Anthropic (sk-ant-), Google (AIza),
AWS (AKIA), GitHub (ghp_), GitLab (glpat-), Slack (xox),
Stripe (sk_live/test), SendGrid (SG.)
- Auth: Bearer tokens, key=value assignments (password=, secret=,
api_key=, token=), private key blocks (-----BEGIN PRIVATE KEY-----)
- Connection strings: mongodb://, postgres://, mysql:// with creds
- PII: SSN (xxx-xx-xxxx), credit card numbers (Visa/MC/Amex/Discover)
Redacted values shown in red in the Test tab. Secrets are truncated
in the activity log (first 8 chars + "...") to avoid logging the
full secret. Enabled by default, toggle in Options.
https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw
Replace URL-pattern and body-shape matching with universal approach:
Outbound (substitution):
- Hooks ALL POST/PUT/PATCH fetch and XHR requests, not just known
API endpoints. Skips static assets and analytics.
- Deep-walks any JSON structure recursively to find and substitute
all string values. Skips metadata keys (model, id, token, etc.).
- Falls back to raw string substitution for non-JSON bodies.
Inbound (reveal):
- Walks ALL text nodes in document.body, not just specific CSS
selectors. Skips SCRIPT, STYLE, INPUT, TEXTAREA tags.
- Handles streaming by observing characterData mutations globally.
This makes Silent Send survive any API restructuring — the only
thing that could break it is a site encrypting request bodies in
JS before fetch, which would also break their own dev tools.
Performance: reveal pairs are cached and only rebuilt on config
change. Deep walk skips known non-content keys to avoid touching
auth tokens or request metadata.
https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw
Reveal mode (eye icon) now works as intended:
- Toggle ON: all existing responses on the page get fake→real
substitution applied immediately (paths, names, emails, etc.)
- Streaming responses are revealed in real-time as they arrive
- Toggle OFF: original text is restored from saved state
- Covers code blocks, artifacts, pre tags, and all response
containers across all supported services
- Blue floating badge shows "Reveal Mode — showing real data"
when active so user knows what they're seeing
The workflow is now: type /home/jsmith/... → Claude sees
/home/ademo/... → Claude responds with /home/ademo/... →
reveal mode shows /home/jsmith/... → user copies real path.
Also adds privacy note in popup footer: data stays in local
browser storage, no servers, no tracking, no analytics.
https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw
Test tab now has two modes:
- Strip (real → fake): paste text with real data, see what gets sent
- Reveal (fake → real): paste AI output with fake data, get back
real data with a "Copy to Clipboard" button
Also fixes:
- content.js smartSubstitute bailing when identity.enabled was
undefined (defaulted enabled to all-true instead of returning)
- Test tab now reloads identity from storage on tab switch so
changes saved in the Identity tab take effect immediately
- Shows yellow warning when identity fields are missing
https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw
- Add custom domain support in Options page so users can add
self-hosted AI services (e.g. https://ai.myserver.com)
- Background worker dynamically injects content scripts on
custom domains using scripting.executeScript
- Add optional_host_permissions so Chrome can grant per-domain access
- Rewrite README: add clone step to Firefox instructions, clarify
what "credentials" means in step 3, add Windows commands alongside
Mac/Linux for every terminal step
- Bump version to 0.2.0
https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw
Extend Silent Send to intercept API requests on all major AI chat
services. Each service has different API shapes:
- ChatGPT: /backend-api/conversation with content.parts arrays
- Grok: GraphQL + /2/grok/add_response with message field
- Gemini: form-encoded f.req with nested arrays (+ generateContent)
- OpenWebUI: /api/chat and /ollama/api/chat (self-hosted)
All services share the same substitution pipeline. Manifests updated
for both Chrome and Firefox with host_permissions for all domains.
OpenWebUI supported via localhost/127.0.0.1 for self-hosted instances.
https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw
jsmith@macbook-pro now becomes ademo@mycomputer when both username
and hostname are configured in the Identity tab. Hostnames are also
caught standalone (e.g. just "macbook-pro" in text).
Also rewrites README with detailed step-by-step Mozilla API key
setup instructions for Firefox signing.
https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw
Instead of requiring explicit mappings for every variation, users
now configure their identity once (Identity tab) and Silent Send
auto-catches:
- Emails: any address @gmail, @yahoo, @outlook, etc.
- Names: first/last, full name, reversed, possessives, case variants
- Usernames: user@host, ~user, /home/user, C:\Users\user
- Phones: all common formats ((555) 123-4567, 555.123.4567, etc.)
Smart patterns run before explicit mappings, so explicit rules
can override smart catches when needed.
https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw
Add manifest.firefox.json for Firefox MV3 (gecko ID, background
scripts instead of service_worker, options_ui). Introduce
browser-polyfill.js shim so all modules use whichever API is
available (browser.* or chrome.*). Add build.sh to target
chrome, firefox, or both.
https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw
Chrome Manifest V3 extension that intercepts personal data and
substitutes it with user-defined replacements before sending to
Claude.ai. Hooks fetch() in the page's main world to catch API
requests, with bidirectional substitution (real→fake on send,
fake→real on display via reveal mode).
Includes popup UI with mapping management, live test/diff view,
activity log with badge count, options page with import/export,
and Shadow DOM traversal for Claude.ai compatibility.
https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw