Tab Anonymizer
Right-click any editor tab to get an unsaved, deterministically anonymized duplicate.
Features
- One Right-Click: Right-click any editor tab title and choose Anonymize & Duplicate Tab. Works on saved files and unsaved (
Untitled-X) buffers alike.
- Never Touches Your Source: The sanitized copy opens in a fresh, unsaved buffer that matches the source language mode and syntax highlighting. The original file on disk is never modified.
- Deterministic & Consistent: Identical tokens map to identical surrogates within a session, so
192.167.2.1 becomes the same safe IP every time it appears — network paths and identifiers stay readable.
- Sequential, Countable Surrogates: IPs, MACs, UUIDs and people are numbered in order of first appearance (
10.0.0.1, 10.0.0.2; 00:00:00:00:00:00, …:01; user.name1, user.name2), so you can see at a glance how many distinct entities a document contains — and repeats reuse their number.
- Secret & Key Redaction: JWTs, Bearer tokens, AWS keys (
AKIA…), GitHub PATs (ghp_…) and credential-bearing database URIs are replaced with <redacted>. PEM / SSH private keys keep their BEGIN/END markers — you still see what was removed — with only the key material redacted.
- Structured Anonymization: IPv4 / IPv6 / CIDR → RFC 1918 & unique-local ranges, plus UUIDs, MAC addresses, Luhn-valid credit cards and SSNs.
- Smart Emails: Role mailboxes survive (
support@contoso.com → support@testltd.com) while people become personas (john.doe@contoso.com → user.name1@testltd.com). Domains follow your keyword dictionary rather than being flattened to example.com.
- Custom Keyword Dictionary: Configurable, case-preserving replacements applied inside larger identifiers (
ew1condc01 → ew1abcdc01).
Usage
- Open any file or unsaved buffer.
- Right-click the editor tab title.
- Select Anonymize & Duplicate Tab.
A new unsaved editor opens containing the sanitized text. The command is also available from the Command Palette (Cmd+Shift+P / Ctrl+Shift+P) as Anonymize & Duplicate Tab.
Configuration
All settings live under the tabAnonymizer.* namespace:
| Setting |
Type |
Default |
Description |
tabAnonymizer.customKeywords |
object |
{} |
Key → value replacements applied inside identifiers, preserving casing. e.g. { "CON": "ABC", "BEE": "DEF" }. |
tabAnonymizer.redactSecrets |
boolean |
true |
Redact tokens, API keys, private keys and credential URIs with <redacted>. |
tabAnonymizer.anonymizeIPs |
boolean |
true |
Map IPv4 / IPv6 / CIDR to deterministic private surrogates. |
tabAnonymizer.anonymizeEmails |
boolean |
true |
Replace emails: personal local-parts become numbered personas, domains follow the keyword / internal-domain rules. |
tabAnonymizer.preserveRoleEmails |
boolean |
true |
Keep role mailboxes (support, info, …) intact instead of replacing them with a persona. |
tabAnonymizer.roleEmailAccounts |
string[] |
(common role names) |
Local-parts treated as role / shared mailboxes rather than people. |
tabAnonymizer.anonymizeUUIDs |
boolean |
true |
Replace UUIDs / GUIDs with deterministic pseudo-UUIDs. |
tabAnonymizer.anonymizeMACs |
boolean |
true |
Replace MAC addresses with documentation MACs. |
tabAnonymizer.anonymizeCreditCards |
boolean |
true |
Mask Luhn-valid card numbers, keeping the last four digits. |
tabAnonymizer.anonymizeSSNs |
boolean |
true |
Mask US SSNs with a test placeholder. |
tabAnonymizer.totalDomainObfuscation |
boolean |
false |
Rewrite whole domains rather than relying on keywords — see Domain handling. |
tabAnonymizer.internalDomainSuffixes |
string[] |
["corp.internal", "corp.local"] |
Internal domain suffixes to rewrite. Only used when totalDomainObfuscation is on. |
tabAnonymizer.replacementDomainSuffix |
string |
example.internal |
Replacement suffix for matched internal FQDNs. Only used when totalDomainObfuscation is on. |
Example
// .vscode/settings.json
{
"tabAnonymizer.customKeywords": {
"CON": "ABC",
"BEE": "DEF"
}
}
ew1condc01 ➔ ew1abcdc01 · BEE_machine01 ➔ DEF_machine01
Domain handling
By default domains are not rewritten wholesale. Keeping corp.internal intact
while your keyword dictionary handles the identifying part keeps the output easy to
follow — a changed TLD tends to obscure which host was which:
# before
primary: db01.corp.internal
cache: redis01.corp.local
# after (default) — unchanged unless a keyword matches
primary: db01.corp.internal
cache: redis01.corp.local
# after, with "tabAnonymizer.customKeywords": { "corp": "acme" }
primary: db01.acme.internal
cache: redis01.acme.local
Set tabAnonymizer.totalDomainObfuscation to true when you need every domain gone
regardless of the dictionary. It rewrites internalDomainSuffixes to
replacementDomainSuffix and sends unrecognised email domains to example.com:
# after, with totalDomainObfuscation enabled
primary: db01.example.internal
cache: redis01.example.internal
owner: user.name1@example.com
Emails
| Input |
Output (with { "contoso": "testltd" }) |
support@contoso.com |
support@testltd.com |
john.doe@contoso.com |
user.name1@testltd.com |
jane.roe@contoso.com |
user.name2@testltd.com |
jdoe@contoso.com |
user1@testltd.com |
Role / shared mailboxes (support, info, noreply, …) are preserved because they
carry no personal data; adjust the list with tabAnonymizer.roleEmailAccounts, or turn
the behaviour off with tabAnonymizer.preserveRoleEmails. A person keeps the same
persona number everywhere they appear, including across different domains.
Requirements
Contributing
We welcome contributions! Please see our Contributing Guide for details on how to build, test, and submit pull requests.
License
This project is licensed under the MIT License.