A Chrome extension that scans web pages and network traffic for exposed secrets in real time. Uses a Rust core compiled to WebAssembly for high-performance pattern matching against 50 secret types.
- Real-time scanning of DOM content, fetch, XHR, WebSocket, Server-Sent Events, and cookies
- Detection patterns — AWS keys, GitHub tokens, Stripe keys, JWTs, private keys, database connection strings, and more
- False-positive filtering using Shannon entropy, placeholder detection, code identifier rejection, and context analysis
- JWT decoder in popup — expandable header/payload JSON view for detected JWTs
- SPA-aware — re-scans on pushState, replaceState, popstate, and hashchange navigations
- Fully local — no data leaves your browser
Page loaded → interceptor.js patches fetch, XHR, WebSocket, SSE, and cookies
→ content.js extracts DOM text + structured attributes
→ Text truncated to 2 MB and deduplicated by SHA-256 hash
→ Background service worker runs WASM scanner
→ Rust matches against known-prefix and keyword patterns (RegexSet + memchr pre-filter)
→ False positives filtered (entropy, placeholders, code identifiers, English words)
→ Findings deduplicated in single O(n) pass, merged across scan batches
→ Findings shown in popup (JWTs include a decoder view)
→ SPA navigations trigger re-scan automatically
secrets-spotter/
├── rust-core/ # Rust WASM core
│ ├── Cargo.toml
│ └── src/
│ ├── lib.rs # WASM entry point (scan_text, pattern_count)
│ ├── detector.rs # Detection engine + false-positive filtering
│ ├── patterns.rs # secret regex patterns
│ ├── types.rs # SecretKind enum, Severity, SecretFinding
│ ├── filter.rs # URL/content filtering (skip CDNs, media, etc.)
│ ├── cookies.rs # Cookie parsing utility
│ └── attributes.rs # HTML attribute extraction utility
├── extension/ # Chrome extension (Manifest V3)
│ ├── manifest.json
│ ├── background/
│ │ └── service-worker.js
│ ├── content/
│ │ ├── interceptor.js # Network traffic capture (MAIN world)
│ │ └── content.js # DOM scanning (ISOLATED world)
│ ├── popup/
│ │ ├── popup.html
│ │ ├── popup.js
│ │ └── popup.css
│ ├── icons/
│ └── wasm/ # Compiled WASM output (built artifacts)
Secrets Spotter uses a three-tier detection strategy (50 patterns total):
Match by a fixed prefix or structure baked into the key itself — highest confidence.
| Service | Prefix/Structure |
|---|---|
| AWS Access Key ID | AKIA... |
| AWS Temp Key (STS) | ASIA... |
| GitHub PAT | ghp_ / github_pat_ |
| GitHub OAuth | gho_ |
| GitHub App | ghu_ / ghs_ / ghr_ |
| Private Key (PEM) | -----BEGIN...PRIVATE KEY----- |
| Password in URL | protocol://user:pass@host (incl. redis, mongodb, amqp, smtp) |
| JWT | eyJ...eyJ... |
| Slack | xox[bpors]- |
| Slack App-Level | xapp- |
| Google API Key | AIza |
| Stripe Secret | sk_(live|test)_ |
| Stripe Publishable | pk_(live|test)_ |
| Stripe Restricted | rk_(live|test)_ |
| Stripe Webhook | whsec_ |
| Twilio | SK + 32 hex chars |
| SendGrid | SG. |
| Discord Bot | [MN]...(dot-separated base64) |
| Mailgun | key- |
| npm | npm_ |
| PyPI | pypi- |
| Shopify | shp(at|ss|ca|pa)_ |
| Square | sq0atp- |
| Anthropic | sk-ant-api03- |
| OpenAI (legacy) | sk-...T3BlbkFJ... |
| OpenAI (new) | sk-proj- / sk-svcacct- |
| DigitalOcean | dop_v1_ |
| Linear | lin_api_ |
| PostHog | ph[cx]_ |
| GitLab PAT | glpat- |
| Cloudflare API | cf_ |
| Supabase Service | sbp_ |
| GCP OAuth | ya29. |
| Hashicorp Vault | hvs. |
| Doppler | dp.(st|sa|ct). |
| Vercel | vercel_ |
| Databricks | dapi |
| Grafana | glsa_ |
| Pulumi | pul- |
| Hugging Face | hf_ |
Match by a service name in the variable name (e.g. heroku_api_key=...).
AWS Secret Key, Heroku, Azure Subscription Key, Datadog.
Match by common developer variable names (e.g. api_key=..., authorization: Bearer ...).
Generic API Key, Bearer Token, Generic API Token.
Broad keyword match (key, token, secret, password, etc.) with Shannon entropy validation (min 3.5 bits/char) to catch secrets that don't match any known prefix or service keyword.
- Placeholder detection — skips
YOUR_KEY,example,test,TODO, etc. - Shannon entropy — rejects low-entropy values for entropy-gated patterns (UTF-8-aware, counts chars not bytes)
- Character class diversity — requires mix of uppercase, lowercase, digits, or symbols/non-ASCII
- English word filtering — ignores lowercase hyphenated words like
my-setting - URL / path exclusion — ignores values that look like URLs or file paths
- Code identifier rejection — skips camelCase, PascalCase, snake_case, SCREAMING_SNAKE, kebab-case, and dot-notation values
Controls whether the extension re-fetches external <script src> and <link stylesheet> files to scan their contents. Default: false.
This is disabled by default because the interceptor runs in the page's MAIN world, where fetches are subject to the page's Content Security Policy (CSP). Sites with strict connect-src directives will block these fetches and log console errors. Most secrets in external scripts are already caught indirectly when the script uses them in fetch/XHR calls, which the interceptor captures.
To enable, set SCAN_EXTERNAL_RESOURCES = true in extension/content/interceptor.js.
./scripts/build.shThis compiles the Rust core to WASM and outputs it to extension/wasm/.
- Run the build script
- Open
chrome://extensions/ - Enable Developer mode
- Click Load unpacked → select the
extension/folder
Browse any website. The extension icon badge shows the count of secrets found. Click the icon to view findings grouped by severity, with redacted previews and copy-to-clipboard for full values. JWT findings include an expandable decoder with header and payload JSON.
Secrets Spotter is licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Secrets Spotter by you, as defined in the Apache-2.0 license, shall be dually licensed as above, without any additional terms or conditions.