The early fetch hook was still inside the async init() function,
running AFTER await storage.local.get(). By the time storage
responded, ChatGPT's JS had already loaded and captured the
original fetch().
Moved the inline script injection to the TOP of the IIFE, before
any async operations. The sequence is now:
1. [synchronous] Inject inline <script> that captures fetch/XHR
2. [synchronous] Define mergeProfiles and other helpers
3. [async] Read storage for config
4. [async] Inject content.js with full substitution engine
This guarantees the fetch proxy is installed before any page
JavaScript runs, regardless of how long storage reads take.
https://claude.ai/code/session_01SWSwDfMVij53bCTNSCLMwn
The fetch interceptor was loaded via <script src="content.js"> which
is asynchronous. ChatGPT's Next.js framework stores a reference to
the original fetch() during module initialization — before our script
finishes downloading. By the time content.js patches window.fetch,
ChatGPT is already using its stored copy of the original.
Fixed with a two-step injection:
1. Injector injects a tiny INLINE <script> (synchronous, instant)
that stores the real fetch/XHR references and installs a thin
proxy. This runs before ANY page JavaScript.
2. Content.js loads normally, uses the stored __ssOriginalFetch
reference, and registers __ssInterceptFetch so the proxy can
route future calls through the full substitution engine.
This ensures the fetch hook is in place before frameworks like
Next.js, React, or any SPA framework can save a reference to
the original fetch().
https://claude.ai/code/session_01SWSwDfMVij53bCTNSCLMwn
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
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
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
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
- 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
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