Stop Pasting ***REDACTED*** into LLMs: Building a Zero-Latency Reversible Secret Vault in Vanilla JS
Every week, an engineer somewhere highlights a failing Kubernetes manifest, .env file, Terraform plan, or curl trace, pastes it into ChatGPT or Claude to debug an edge case, and realizes half a second too late that a liv
Every week, an engineer somewhere highlights a failing Kubernetes manifest, .env file, Terraform plan, or curl trace, pastes it into ChatGPT or Claude to debug an edge case, and realizes half a second too late that a live sk-proj-... key, AWS AKIA... credential, or production Postgres URI just left their machine.
Most security-conscious developers try to solve this manually by doing a quick find-and-replace to turn credentials into ***REDACTED*** before prompting.
Unfortunately, naive ***REDACTED*** scrubbing silently breaks two critical parts of an AI-assisted debugging loop:
-
Destroying Cross-Variable Identity (Topology Loss): Suppose a distributed trace references two internal nodes (
10.24.8.15and10.24.8.99) and passes a bearer token across three microservices, where service C accidentally receives a stale token. If every IP and token becomes***REDACTED***, the LLM loses equivalence relationshipsβit can no longer tell whether two masked strings were identical or distinct. -
Roundtrip Re-Insertion Friction: When Claude or ChatGPT hands back a 60-line refactored TypeScript or YAML block filled with
***REDACTED***literals, pasting it back into your editor breaks your local build until you manually hunt down and restore every single credential without fat-fingering a quote.
To fix both problems without routing sensitive clipboard contents through any cloud proxy or bloated native binary, I built and open-sourced PasteShieldβa zero-dependency, <1ms reversible secret sanitizer running 100% in local RAM across VS Code / Cursor, Node/Bun CLI pipelines, and an offline browser sandbox.
Here is a look under the hood at the three architectural problems we had to solve: deterministic bidirectional interning, ordered multi-pass regex precedence, and zero-server offline license verification using 32-bit FNV-1a checksums.
1. Designing a Prototype-Safe Bidirectional SessionVault
Instead of destroying entropy with static asterisks, PasteShield maps each unique (category, rawSecret) pair to a numbered semantic token such as <OPENAI_KEY_1>, <DB_URI_1>, <INTERNAL_IP_1>, and <INTERNAL_IP_2>.
Inside sanitizer-core.js, the vault lives strictly in volatile process memory using null-prototype dictionaries (Object.create(null)) so maliciously crafted log strings like __proto__ or constructor can never trigger prototype pollution:
function SessionVault() {
this.secretToToken = Object.create(null);
this.tokenToSecret = Object.create(null);
this.categoryCounters = Object.create(null);
}
SessionVault.prototype.intern = function (category, rawSecret) {
var compositeKey = category + '\u0000' + rawSecret;
if (this.secretToToken[compositeKey]) {
return this.secretToToken[compositeKey];
}
var nextIndex = (this.categoryCounters[category] || 0) + 1;
var candidate = '<' + category + '_' + nextIndex + '>';
while (this.tokenToSecret[candidate] && this.tokenToSecret[candidate] !== rawSecret) {
nextIndex += 1;
candidate = '<' + category + '_' + nextIndex + '>';
}
this.categoryCounters[category] = nextIndex;
this.secretToToken[compositeKey] = candidate;
this.tokenToSecret[candidate] = rawSecret;
return candidate;
};
Notice two subtle invariants here:
-
Referential Stability Across Multi-File Prompts: Because
secretToTokenkeys oncategory + '\u0000' + rawSecret, copying.envfirst anddocker-compose.ymlfive minutes later guarantees that the same Redis password resolves to<DB_URI_1>in both snippets. The LLM sees exact structural isomorphism while never seeing a single character of the credential. -
Collision-Proof Angle-Bracket Syntax: Tokens follow
/^<[A-Z][A-Z0-9_]{1,40}_[1-9]\d*>$/. LLMs naturally treat<DB_URI_1>as an opaque symbolic variable and preserve it verbatim inside refactored string templates, JSON payloads, and TypeScript configs. When you copy the AI's response and pressCmd+Alt+R(Ctrl+Alt+R), a single regex pass over/<([A-Z][A-Z0-9_]{1,40})_([1-9]\d*)>/gswaps every placeholder back to its exact original value in under a millisecond.
2. Why Regex Execution Order Makes or Breaks Secret Scrubbers
If you run 10 independent regular expressions in arbitrary order, smaller patterns will cannibalize larger structured secrets and corrupt restoration!
Consider a production PostgreSQL connection URI:
DATABASE_URL="postgresql://svc_billing:[email protected]:5432/ledger"
If your INTERNAL_IP detector (10.24.8.15) or generic .env key-value detector fires before your DB_URI detector, the URI gets partially mutated into:
postgresql://svc_billing:sk-live-secret99@<INTERNAL_IP_1>:5432/ledger
Now the DB_URI regex fails to match, leaving svc_billing:sk-live-secret99 exposed in plain text!
PasteShield prevents partial-token cannibalization through strict coarse-to-fine pass ordering paired with an idempotency guard (hasExistingPlaceholder):
-
Pass 1 β Multi-Line PEM / OpenSSH / PGP Private Key Blocks: Captures entire
-----BEGIN ... PRIVATE KEY-----blocks across newlines before line-oriented matchers touch base64 lines. -
Pass 2 β Composite Cloud Connection Strings: Matches multi-segment Azure Storage, Service Bus, Cosmos DB, IoT Hub, and SQL connection strings (
DefaultEndpointsProtocol=...;AccountKey=...). -
Pass 3 β Authenticated Database & Broker URIs: Captures full
postgres://,mysql://,mongodb+srv://,rediss://,amqps://, andclickhouse://URIs containinguser:pass@host. -
Pass 4 β High-Prefix Vendor Tokens: Captures
sk-proj-.../sk-ant-...(OpenAI & Anthropic),AKIA.../ASIA...(AWS IAM),ghp_/github_pat_(GitHub), Slackxoxb-, Striperk_live_, and 3-segmenteyJ...signed JWTs. -
Pass 5 β Network & Identity Primitives: Captures RFC1918 (
10.x,172.16-31.x,192.168.x) plus Tailscale/CGNAT (100.64-127.x) private IPv4s and email addresses. -
Pass 6 β Contextual Key-Value Assignments: Captures
.env, YAML, and JSON assignments matching*_SECRET,*_PASSWORD,*_TOKEN, or*_API_KEY, while explicitly skipping benign placeholders (true,false,null,changeme,$ENV_REF,{{handlebars}}, and already-interned<TOKEN_1>markers).
Because every replacement checks if (hasExistingPlaceholder(match)) return match;, already-sanitized regions are completely immune to double-wrapping.
3. Zero-Backend Offline Pro Verification with 32-Bit FNV-1a
A non-negotiable security promise for developer security tools is zero outbound network traffic. If an extension claims to keep secrets local, opening fetch() sockets to a custom licensing server undermines enterprise trust and fails inside air-gapped corporate VPNs.
Our core 10 detectors, bidirectional VS Code commands, and Node/Bun CLI are 100% free and MIT-licensed forever. For teams wanting optional power featuresβlike custom corporate domain redaction (*.corp.acme.internal β <COMPANY_DOMAIN_1>) and multi-file Markdown AI Context Packsβwe needed a purely offline license key format (SHIELDPRO-XXXX-XXXX-XXXXXX) verifiable in 15 lines of dependency-free JavaScript across Node, browsers, and macOS JavaScriptCore (jsc).
We used a 32-bit FNV-1a non-cryptographic checksum with 32-bit unsigned integer multiplication (Math.imul):
function fnv1aHex6(str) {
var h = 0x811c9dc5;
for (var i = 0; i < str.length; i++) {
h ^= str.charCodeAt(i);
h = Math.imul(h, 0x01000193) >>> 0;
}
return ('00000000' + h.toString(16).toUpperCase()).slice(-8).slice(0, 6);
}
Why Math.imul(h, 0x01000193) >>> 0 instead of h * 0x01000193? In JavaScript, standard multiplication uses IEEE-754 64-bit floats with 53 bits of mantissa precision; multiplying a 32-bit integer near 0xFFFFFFFF by the FNV prime 16777619 (0x01000193) can exceed $2^{53} - 1$ and silently drop low bits! Math.imul performs exact C-style 32-bit two's-complement multiplication, and >>> 0 coerces the result back to an unsigned 32-bit integerβproducing byte-for-byte identical hex signatures between Python build scripts and JavaScript runtimes with zero WebCrypto async ceremony.
Try It in Your Workflow (100% Local & MIT Open Source)
Whether you live inside VS Code, Cursor, or terminal pbpaste | ... | pbcopy pipelines, you can wire reversible sanitization into your daily AI loop in 30 seconds:
- π§© Install on VS Code Marketplace: PasteShield β AI Prompt & Clipboard Secret Sanitizer
- β Clone Source & Zero-Dependency CLI on GitHub:
github.com/963239327/pasteshield-secret-sanitizer - π Test Live in Browser (No Install): Interactive Client-Side Playground
- π Support Indie OSS: Optional $9 Lifetime PasteShield Pro Key or $19 CraftLeaf Studio All-Access Pass.
If there is a cloud vendor token format or log pattern your team hits frequently, open an issue or PR on GitHubβhappy to add first-class detectors for it!
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.