Automatically replaces raw secrets in chats with encrypted SecNote links.
A Chrome extension (Manifest V3) that detects passwords, API keys, tokens, and other secrets in web-based messaging apps and replaces the original plaintext with encrypted SecNote links before sending.
Generated SecNote URLs are bearer secrets until first successful view or expiry. When a URL is posted into a chat, the chat platform can store and read that URL, including the fragment key. SMP prevents the original raw secret string from being posted, but it does not hide the generated SecNote link from the messaging platform. With the original unmodified SecNote server software, a viewed note is deleted; forwarding the same URL after that point should not reveal the note again.
| 39 detection patterns | API keys (OpenAI, Anthropic, AWS, GitHub, Stripe, GCP, Azure, and more), JWTs, bearer tokens, private keys, TOTP URIs, connection strings, and high-entropy generic tokens |
| Shannon entropy analysis | Optional statistical detection for secrets that don't match a named pattern; configurable sensitivity |
| Confirmation modal | Intercepts the send action and shows a Shadow DOM dialog listing every detected secret before the original plaintext is transmitted |
| AES-256-GCM encryption | The key lives in the recipient URL fragment — never sent to the SecNote server during note retrieval |
| One-time view | The original unmodified SecNote server software deletes the note on first successful retrieval; configurable TTL (12 h or 24 h) |
| Ed25519 response verification | Signed server responses with TOFU trust model; optional pubkey pinning in every link |
| Proof-of-Work | Client-side PoW (up to 28 bits) required before note creation — mitigates server abuse |
| Custom sites | Extend coverage to any HTTPS site or localhost with a URL pattern and editor selector |
| Auto-replace mode | Skip the confirmation dialog and replace silently on every send |
| Platform | URL |
|---|---|
| Slack | https://app.slack.com/* |
| Discord | https://discord.com/* |
| Telegram Web | https://web.telegram.org/* |
| Microsoft Teams (web) | https://teams.live.com/* |
| WhatsApp Web | https://web.whatsapp.com/* |
| Outlook Web App | https://*/*/owa/* |
| Custom sites | Configurable in Settings |
User types secret → presses Enter / clicks Send
│
▼
interceptor.js (MAIN world)
detects secrets in editor
blocks the send event
fires secnote-guard-send-blocked
│
▼
bridge.js (isolated world)
shows confirmation modal
user clicks "Secure & Send"
│
▼ chrome.runtime.sendMessage
background.js (service worker)
encrypts text with AES-256-GCM
solves Proof-of-Work challenge
POST /api/v1/notes → receives note ID
│
▼
bridge.js
replaces secrets with {SC:0001}, {SC:0002}, …
appends SecNote URL to message
posts pending replacements to interceptor.js
│
▼
interceptor.js
intercepts the real fetch / XHR / WebSocket send
patches request body: plaintext → {SC:…} placeholder
│
▼
App's servers receive no original plaintext secret strings
but they do receive the SecNote bearer URL until it is viewed or expires
┌─────────────────────────────────────────────┐
│ background.js (service worker) │
│ ─ AES-256-GCM encryption │
│ ─ Ed25519 response verification │
│ ─ PoW solver │
│ ─ chrome.storage.sync │
└──────────────────────┬──────────────────────┘
│ chrome.runtime.sendMessage
┌────────────┴───────────────┐
│ │
┌─────────┴─────────────┐ ┌──────────┴────────────┐
│ bridge.js │ │ popup.js │
│ (isolated world) │ │ options.js │
│ ─ secret detection │ │ ─ status display │
│ ─ Shadow DOM modal │ │ ─ settings form │
│ ─ editor patching │ │ ─ trust management │
│ ─ cross-frame comms │ └───────────────────────┘
└─────────┬─────────────┘
│ window.postMessage
┌─────────┴─────────────────────────┐
│ interceptor.js (MAIN world) │
│ ─ fetch / XHR / WS / sendBeacon │
│ ─ request-body secret patching │
│ ─ WhatsApp Lexical editor API │
└───────────────────────────────────┘
| File | World | Role |
|---|---|---|
background.js |
Service worker | Crypto, API client, settings, trust store |
bridge.js |
Isolated (content script) | UI modal, editor detection, send interception, cross-frame coordination |
interceptor.js |
MAIN (page context) | Network interception, request-body patching, Lexical editor integration |
dist/secretDetector.js |
Both | Compiled secret-detection engine (39 patterns + entropy) |
popup.html/js |
Extension popup | Status display, quick-open settings, manual scan |
options.html/js |
Extension options page | Full settings, custom rules, trust management |
# 1. Clone the repository
git clone https://github.com/pwn-all/smp-plugin.git
# 2. Open Chrome and navigate to
chrome://extensions
# 3. Enable Developer mode (toggle, top-right)
# 4. Click "Load unpacked" and select the source/ directoryThe SMP icon will appear in the toolbar.
- Click the SMP icon → Settings
- Enter your SecNote API endpoint and click Test connection
- Accept the server public key fingerprint (TOFU)
- Choose TTL, enable/disable detection patterns, and optionally add custom sites
| Permission | Why |
|---|---|
storage |
Persist settings across sessions via chrome.storage.sync |
scripting |
Dynamically inject content scripts into custom user-defined sites |
https://*/* (optional) |
Required only when a custom site is added |
http://localhost/* (optional) |
Testing against a local SecNote server |
http://127.0.0.1/* (optional) |
Testing against a local SecNote server |
The extension never reads cookies, browsing history, or any content beyond the text fields it protects.
Show all 39 built-in patterns
| Category | Patterns |
|---|---|
| AI / ML | OpenAI API key, Anthropic API key |
| Cloud — AWS | Access key ID, secret access key, session token |
| Cloud — Azure | Connection string, SAS token |
| Cloud — GCP | Service account JSON |
| Version control | GitHub token, GitLab token, npm token |
| Payments | Stripe secret key, Stripe webhook secret |
| Communication | Slack API token, Slack webhook, Mailchimp API key, Docker Hub token |
| Auth | JWT, Bearer token, TOTP URI (otpauth://), magic link |
| Credentials | Inline SSH key, Git clone with credentials, CLI password flag, connection string |
| Cryptography | PEM private key |
| Generic | High-entropy token, password field, license key |
| Setting | Default | Description |
|---|---|---|
| API Endpoint | — | SecNote server base URL |
| TTL | 24 h | Maximum note lifetime before server auto-deletes; first successful view deletes earlier |
| Pin pubkey | on | Embed server public key in every generated link so recipients can verify |
| Auto-replace | off | Skip the confirmation dialog |
| Statistical detection | on | Entropy-based detection for secrets without a named pattern |
| Sensitivity | medium | Entropy threshold — low: 4.0 bit, medium: 3.5 bit, high: 3.0 bit |
| Enabled patterns | all | Toggle individual detection rules |
| Custom sites | none | URL glob + CSS selector for additional sites |
Chrome 137+ (Manifest V3 with service worker and WebCrypto Ed25519). Not tested on other Chromium-based browsers.
GPL-3.0-only. See LICENSE.
Built with ❤️ for people who accidentally paste secrets into Slack.