A Python tool that strips sensitive data from MongoDB log files and FTDC diagnostic files while preserving structure and analytical value. Produces obfuscated output safe for sharing with support teams, vendors, or public bug reports, plus a private mapping file to decode values when needed.
Supports all MongoDB deployment types: standalone, replica set, and sharded cluster (including mongos, config servers, shard servers, and balancer operations).
The tool processes all files at once — logs and FTDC alike — using a single shared mapping, guaranteeing that the obfuscation is coherent across every file:
- If
mongo-prod-01.acmecorp.comappears in the primary's log, a secondary's log, and an FTDCserverStatusreference document, it becomeshost1.example.comin all of them. - If
shard-east-01is referenced by the balancer on the config server and by the migration coordinator on the shard, it becomesshard1everywhere. - The same database name, collection name, replica set name, IP address, username, or any other sensitive value always maps to the exact same replacement regardless of which file or file type it appears in.
This means you can still correlate events across nodes, trace replication chains, and follow chunk migrations in the obfuscated output — the relationships between nodes are preserved, only the real names are gone.
How it works: Pass 1 scans all input files (logs line-by-line, FTDC via BSON decoding and metric chunk decompression) into one shared registry before any replacement happens. Pass 2 applies that single registry to every file. No file is replaced until every file has been scanned.
- Quick Start
- Usage
- Output Files
- FTDC Support
- How It Works
- Cross-File Coherence
- What Gets Obfuscated
- What Is NOT Obfuscated
- Replacement Templates
- Recognized Log Attribute Keys
- Log Format Support
- Architecture
- Deployment Coverage
- BSON Document Handling
- Regex Patterns
- Limitations
# Point at a support bundle / cluster dump folder — it does the rest
python3 mongodb_obfuscator.py /path/to/logs/
# Custom output directory
python3 mongodb_obfuscator.py /path/to/cluster_dump/ -o /sanitized/The tool recursively scans the input directory for .log files and FTDC files (anything inside diagnostic.data/ directories), obfuscates everything with a shared mapping, and writes the output to an obfuscated/ subdirectory inside the input, preserving the original directory structure.
- Python 3.6+
- No external dependencies (stdlib only)
Point at the root of a support bundle or cluster dump. The tool recursively finds all log and FTDC files:
python3 mongodb_obfuscator.py /path/to/logs/Input structure:
logs/
mongod-0.log
diagnostic.data/
diagnostic.data/
metrics.2025-12-10T02-44-05Z-00000
metrics.2025-12-10T08-41-34Z-00000
metrics.interim
Output (inside obfuscated/ subdirectory, originals untouched):
logs/
mongod-0.log <-- original, untouched
diagnostic.data/ <-- original, untouched
...
obfuscated/ <-- all obfuscated output here
mongod-0_obfuscated.log
diagnostic.data/
diagnostic.data/
metrics.2025-12-10T02-44-05Z-00000
metrics.2025-12-10T08-41-34Z-00000
metrics.interim
cluster_mapping.json
You can also pass multiple directories, individual files, or glob patterns:
# Multiple directories (e.g., multi-node cluster)
python3 mongodb_obfuscator.py /dumps/node1/ /dumps/node2/ /dumps/node3/
# Mix of files and directories
python3 mongodb_obfuscator.py /dumps/shards/ /dumps/config/ /dumps/mongos.log
# Glob patterns
python3 mongodb_obfuscator.py /dumps/node*/mongod.log /dumps/node*/diagnostic.data/# Custom output directory
python3 mongodb_obfuscator.py /dumps/cluster/ -o /sanitized/
# Custom mapping file path
python3 mongodb_obfuscator.py /dumps/cluster/ -o /sanitized/ -m /sanitized/my_mapping.jsonContinue a prior obfuscation run or merge with another pass:
# Load a mapping from a previous run to maintain coherence
python3 mongodb_obfuscator.py /dumps/node4/ --load-mapping /sanitized/cluster_mapping.json -o /sanitized/node4/usage: mongodb_obfuscator.py [-h] [-o OUTPUT_DIR] [-m MAPPING]
[--load-mapping LOAD_MAPPING]
input [input ...]
Obfuscate sensitive data in MongoDB log files and FTDC diagnostic files with
coherent, consistent replacements across an entire cluster. Recreates the
input directory structure in the output.
positional arguments:
input One or more directories, log files, FTDC files, or
glob patterns. Directories are scanned recursively
for *.log files and diagnostic.data/ FTDC files.
optional arguments:
-h, --help show this help message and exit
-o OUTPUT_DIR, --output-dir OUTPUT_DIR
Root directory for obfuscated output
(default: <input>/obfuscated/)
-m MAPPING, --mapping MAPPING
Path for the shared mapping JSON file
(default: <output-dir>/cluster_mapping.json)
--load-mapping LOAD_MAPPING
Load an existing mapping to continue a prior run
or merge with another obfuscation pass
| File | Purpose | Share? |
|---|---|---|
*_obfuscated.log |
Sanitized log — same format as input, all sensitive values replaced | Safe to share |
FTDC metrics.* |
Sanitized FTDC — same binary format, all sensitive strings replaced, all numeric metrics preserved exactly | Safe to share |
cluster_mapping.json |
Original-to-replacement lookup for all files, grouped by category | Keep private |
The tool includes a pure-Python BSON codec and FTDC chunk decompressor/recompressor to handle MongoDB's Full Time Diagnostic Data Capture files with zero external dependencies.
FTDC files contain three document types:
| Type | Name | Processing |
|---|---|---|
| 0 | Metadata | Full BSON document (e.g., serverStatus output). All sensitive string fields are obfuscated. |
| 1 | Metric Chunk | Compressed reference BSON + delta-encoded numeric time series. The reference document's strings are obfuscated; the numeric delta stream is preserved byte-for-byte. All metric data is intact. |
| 2 | Periodic Metadata | Configuration change deltas. String fields are obfuscated. |
- Decompress the zlib payload
- Extract the reference BSON document and the delta stream
- Obfuscate sensitive strings in the reference document
- Re-compress with the identical delta stream — numeric metrics are untouched
This works because FTDC's delta compression only tracks numeric fields. String fields exist solely in the reference document, so modifying strings and keeping the delta stream byte-for-byte is safe.
In addition to the 130+ log attribute keys, the tool recognizes FTDC-specific fields:
me— the node's own host:port inserverStatusrepl sectionset— replica set name inreplSetGetStatushosts,passives,arbiters— BSON arrays of host:port strings in replication sectionsadvisoryHostFQDNs— array of advisory FQDNsnameinmembers[]arrays — host:port of replica set members
Files are automatically classified:
| Pattern | Classification |
|---|---|
*.log |
Log file |
Files inside diagnostic.data/ directories |
FTDC |
metrics.* or metrics filename |
FTDC |
*.ftdc extension |
FTDC |
| Binary content (null bytes in header) | FTDC |
Archive files (.tar.gz, .zip, etc.) |
Skipped |
The obfuscator uses a two-pass architecture:
Reads every input file and builds a single shared mapping of all sensitive values found across the entire cluster:
For log files:
- Each JSON log line is parsed and recursively walked (
deep_discover) - Every attribute key is checked against categorized key sets (host keys, database keys, shard keys, etc.)
- Values are classified and registered in one shared
ObfuscatorRegistry - Free-text fields (
msg,error, etc.) are scanned with regex for IPs, FQDNs, emails, LDAP DNs, and Java class names - Embedded BSON documents in stringified form are parsed for key-value pairs
- Non-JSON lines (legacy format) are scanned with full regex patterns
For FTDC files:
- Sequential BSON documents are decoded from the binary file
- Metadata documents have their
docfield recursively walked (deep_discover_bson) - Metric chunks are decompressed and the reference BSON document is walked
- Periodic metadata documents have their
docfield walked - BSON arrays (e.g.,
hosts: ["node1:27017", "node2:27017"]) are handled natively
Re-reads every file and performs replacement using the shared mapping:
For log files:
- All replacements are sorted longest-first to prevent partial matches
- Each line is scanned for every known original value and replaced
- Output is written to
*_obfuscated.log
For FTDC files:
- Each BSON document is decoded, string values are replaced, and the document is re-encoded
- Metric chunks are decompressed, the reference document is obfuscated, and the chunk is re-compressed with the identical delta stream
- Output files keep their original names
When processing multiple files, the tool guarantees consistent replacements across all files — both logs and FTDC. This is critical for cluster diagnostics where the same hostname, shard name, or replica set name appears in logs from different nodes and in FTDC diagnostic data.
The mechanism is simple: Pass 1 scans all files into one ObfuscatorRegistry before any replacement happens. Then Pass 2 applies that single registry to every file.
For example, given a 3-node replica set + 1 mongos:
| Original value | Replacement | node1.log | node2.log | node1 FTDC | mongos.log |
|---|---|---|---|---|---|
mongo-pay-01.fintech.internal |
host1.example.com |
host1.example.com |
host1.example.com |
host1.example.com |
host1.example.com |
rs-payments |
replset1 |
replset1 |
- | replset1 |
replset1 |
shard-payments |
shard1 |
- | - | - | shard1 |
payments_prod |
database1 |
database1 |
database1 |
- | - |
The same original value always produces the same replacement, regardless of which file or file type it appears in.
| # | Category | Example Original | Example Replacement | Description |
|---|---|---|---|---|
| 1 | hostname | mongo-prod-01 |
host1 |
Short hostnames (no dots) |
| 2 | fqdn | mongo-prod-01.acmecorp.com |
host1.example.com |
Fully qualified domain names |
| 3 | domain | acmecorp.com |
domain1.example.com |
Domain portions extracted from FQDNs/emails |
| 4 | ip | 192.168.1.100 |
10.0.0.1 |
IPv4 addresses (except localhost/0.0.0.0) |
| 5 | database | myapp_production |
database1 |
Database names (except admin, local, config) |
| 6 | collection | user_profiles |
collection1 |
Collection names (except system.* and $*) |
| 7 | replset | rs-prod-east |
replset1 |
Replica set names |
| 8 | shard | shard-prod-east-01 |
shard1 |
Shard names and shard IDs |
| 9 | user | admin_prod |
user1 |
Usernames (non-email format) |
| 10 | john@acmecorp.com |
user1@example.com |
Email addresses | |
| 11 | path | /data/db/mongo-prod-01 |
/obfuscated/path1 |
File system paths |
| 12 | cert_subject | CN=server.acmecorp.com,O=AcmeCorp,C=US |
CN=cert1.example.com,O=Organization,... |
TLS/SSL certificate subject strings |
| 13 | org | AcmeCorp Inc |
Organization1 |
Organization names from certs/LDAP |
| 14 | location | San Francisco |
Location1 |
Location names from certs (L=, ST=) |
| 15 | java_class | com.mongodb.client.MongoClient |
com.example.app.Class1 |
Java class names (driver stack traces) |
| 16 | appname | PaymentService |
app1 |
Application names from client metadata |
| 17 | data | ACME Corp |
data_1 |
Generic catch-all for business data in BSON documents |
These values are intentionally preserved because they are operational metadata, not PII:
| Category | Examples | Reason |
|---|---|---|
| Internal databases | admin, local, config |
MongoDB system databases |
| System collections | system.sessions, system.profile |
MongoDB internal collections |
| Log envelope fields | t, s, c, id, ctx, svc |
Structural log metadata |
| Numeric metrics | durationMillis, docsExamined, keysExamined |
Performance data |
| FTDC numeric time series | All delta-compressed metrics | Preserved byte-for-byte |
| Version strings | gitVersion, openSSLVersion |
Software versions |
| Numbers | 42, 3.14, -1 |
Pure numeric values |
| Hex strings | 507f1f77bcf86cd799439011 |
ObjectIds, hashes (24+ hex chars) |
| UUIDs | a1b2c3d4-e5f6-7890-abcd-ef1234567890 |
Opaque identifiers |
| BSON type markers | ObjectId(...), Date(...), Timestamp(...) |
Type wrappers |
| Booleans/status | true, false, ACTIVE, COMPLETED |
Operational status values |
| Read/write concerns | majority, linearizable, snapshot |
Consistency levels |
| Country/currency codes | US, USD, EUR |
ISO standard codes |
| MongoDB operators | $set, $match, $group |
Query/update operators |
| Port numbers | 27017, 27018 |
Kept in SKIP_KEYS |
Each category uses a deterministic template that increments per unique value:
| Category | Template | Sequence |
|---|---|---|
| hostname | host{n} |
host1, host2, host3... |
| fqdn | host{n}.example.com |
host1.example.com, host2.example.com... |
| domain | domain{n}.example.com |
domain1.example.com, domain2.example.com... |
| ip | 10.{(n>>16)&0xFF}.{(n>>8)&0xFF}.{n&0xFF} |
10.0.0.1, 10.0.0.2... |
| database | database{n} |
database1, database2... |
| collection | collection{n} |
collection1, collection2... |
| replset | replset{n} |
replset1, replset2... |
| shard | shard{n} |
shard1, shard2... |
| user | user{n} |
user1, user2... |
user{n}@example.com |
user1@example.com, user2@example.com... | |
| path | /obfuscated/path{n} |
/obfuscated/path1, /obfuscated/path2... |
| cert_subject | CN=cert{n}.example.com,O=Organization,L=City,ST=State,C=XX |
Full DN template |
| org | Organization{n} |
Organization1, Organization2... |
| location | Location{n} |
Location1, Location2... |
| java_class | com.example.app.Class{n} |
com.example.app.Class1... |
| appname | app{n} |
app1, app2... |
| data | data_{n} |
data_1, data_2... |
The obfuscator recognizes 130+ MongoDB LOGV2 attribute keys, derived from analysis of all 2,233 unique attribute keys in the Percona Server for MongoDB 8.0 source code ("keyName"_attr patterns in src/mongo/).
Attribute keys whose values contain hostname, host:port, or IP address data:
host, hostAndPort, hostName, me,
syncSource, syncSourceHost, syncSourceCandidate,
candidateNode, candidate, peer,
newSyncSource, oldSyncSource, previousSyncSource,
currentSyncSource, unsupportedSyncSource, syncTarget,
eligibleCandidateSyncSource,
remoteHost, senderHost, donorHost,
addr, address, addressString,
server, serverAddress, serverHost,
endpoint, localEndpoint,
primary, newPrimary, targetPrimary,
closestNode, selectedNode, node, otherMember,
requestTarget, request_target, request_target_host,
target, cursorHost,
failedHost, sniName
remote, local, remoteAddr, remoteSocketAddress,
remoteString, remoteAddress, sourceClient
client
Values matching conn\d+ (connection IDs) are skipped.
Attribute keys whose values contain database.collection namespace strings:
ns, namespace, nss,
sourceNss, targetNss, newNss, oldNss,
sourceNamespace, targetNamespace, destinationNamespace,
originalCollection, outputNamespace, resolvedNs,
fromNs, toNs,
oplogNamespace, oplogNss,
ecocNss, ecocCompactNss, ecocRenameNss,
reshardingTmpNss, lostAndFoundNss,
existingTargetNamespace, newTargetNamespace,
configSettingsNamespace, affectedNamespaces,
dbNss, docNss
database, db, dbName, dbname
Internal databases (admin, local, config, $external) are never obfuscated.
collection, coll, collName,
tempCollection, temporaryCollection, newCollection,
sourceCollection, defragmentCollection
System collections (system.*, $*) are never obfuscated.
replSetName, setName, configServerSetName,
replicaSet, set,
newConfigSetName, oldConfigSetName, localConfigSetName,
commandLineSetName, ourSetName, initiateSetName,
remoteNodeSetName
shard, shardId,
fromShard, fromShardId, toShard, toShardId,
donorShard, donorShardId,
recipientShard, recipientShardId, recipientId,
coordinatorShardId, writeShardId,
dataShard, mergingShardId,
firstShardId, secondShardId
user, userName, queryUser
Values containing @ are treated as emails; others as usernames.
dbPath, dbpath, path, filePath, filepath,
localFilePath, remoteFilePath,
keyfile, cafile, crlFile, CRLFile,
configPath, logPath, newLogPath, oldLogPath,
file, fileName, filename,
dir, directory, dataDirectory,
destFile, srcFile, localFile, remoteFile,
lockFile, jsonConfigPath, remoteDBPath,
_pipeAbsolutePath
peerSubject, peerSubjectName, subjectName,
subject, issuer, dn
Certificate DN strings are parsed to also extract Organization (O=, OU=), Location (L=, ST=), and CN hostnames.
targetClusterConnectionString, connString, connectionString,
replicaSetConnectionStr, shardConnectionString,
newConnString, oldConnString, currentConnString,
newConnectionString, givenConnString,
uri, mongoUri, ldapurl
Connection strings are parsed to extract hosts, database names, and replicaSet= query parameters. Non-MongoDB URIs (ldap://, etc.) are also parsed for host extraction.
appName, clientName
msg, error, errmsg, reason, message, info,
errorMessage, errorMsg, err_msg, description, desc
These are scanned with regex patterns for embedded IPs, FQDNs, emails, LDAP DN components, Java class names, and BSON key-value pairs.
addresses, failedHosts, nodes, configServers,
listenAddrs, attemptedHosts,
hosts, passives, arbiters, advisoryHostFQDNs
Values are split on commas (log files) or iterated as BSON arrays (FTDC files), and each part is processed as a host.
Keys that are never processed (structural/numeric metadata):
t, s, c, id, ctx, svc, tags,
connectionId, connectionCount, durationMillis, millis,
workingMillis, timeAcquiringMicros, numYields, nreturned,
docsExamined, keysExamined, nscanned, cpuNanos, durationMicros, latency,
txnNumber, clientTxnNumber, opId,
version, gitVersion, openSSLVersion, minWireVersion, maxWireVersion,
port, votes, priority, term,
ok, code, codeName, result,
featureCompatibilityVersion,
numMembers, numShards, numChunks, numDocs,
bytesCloned, docsCloned, keysInserted, numRecords, numIndexes
Any key not listed above and not in SKIP_KEYS triggers a light freetext scan -- if the value contains an IP address, email, or FQDN pattern, a full freetext scan is performed. This catches sensitive data in keys that may be added in future MongoDB versions.
Primary format. Each line is parsed as JSON:
{
"t": {"$date": "2024-01-15T10:30:45.123Z"},
"s": "I",
"c": "REPL",
"id": 21392,
"ctx": "replCoord",
"msg": "New replica set config in use",
"attr": {
"config": {
"members": [
{"_id": 0, "host": "mongo-prod-01.acme.com:27017"}
]
}
}
}The attr object is recursively walked. Nested objects and arrays at any depth (up to 20) are processed. Special handling exists for:
membersarrays (replica set member host extraction)optionsobjects (startup configuration: net, replication, storage, security, LDAP)command/cmdObj/originatingCommandobjects (collection name extraction from MongoDB commands includingfind,aggregate,insert,update,delete,findAndModify,count,distinct,getMore,create,drop,renameCollection,createIndexes,dropIndexes,collMod)
Lines that fail JSON parsing are scanned with full regex patterns:
2024-01-15T10:30:45.123+00:00 I NETWORK [listener] connection from 192.168.1.100:45678
IPs, FQDNs, emails, LDAP DNs, and Java class names are extracted via regex.
node1/ node2/ mongos/
mongod.log mongod.log mongos.log
diagnostic.data/ diagnostic.data/ diagnostic.data/
metrics.* metrics.* metrics.*
│ │ │
└───────────────────┴─────┬─────────────┘
│
PASS 1: Discovery
(scan ALL files into ONE registry)
│
┌────────────────▼────────────────┐
│ ObfuscatorRegistry │
│ (shared) │
│ │
│ hostname: {orig: repl} │
│ fqdn: {orig: repl} │
│ ip: {orig: repl} │
│ shard: {orig: repl} │
│ replset: {orig: repl} │
│ ...17 categories total │
└────────────────┬────────────────┘
│
PASS 2: Replace
(apply shared registry to ALL)
│
┌─────────────────────────┼─────────────────────────┐
│ │ │
▼ ▼ ▼
obfuscated/ obfuscated/ obfuscated/
node1/ node2/ mongos/
mongod_obfuscated.log mongod_obfuscated.log mongos_obfuscated.log
diagnostic.data/ diagnostic.data/ diagnostic.data/
metrics.* metrics.* metrics.*
+ cluster_mapping.json
┌────────────────────────┐
│ json.loads(line) │──── fail ──→ _discover_freetext()
└────────────┬───────────┘ (regex scan)
│ success
▼
┌─────────────────────────┐
│ deep_discover(obj) │ ◄── recursive walk, depth <= 20
│ │
│ For each key, val: │
│ ├─ REPLSET_KEYS? │──→ register("replset", val)
│ ├─ SHARD_KEYS? │──→ register("shard", val)
│ ├─ DATABASE_KEYS? │──→ register("database", val)
│ ├─ COLLECTION_KEYS? │──→ register("collection", val)
│ ├─ NAMESPACE_KEYS? │──→ parse db.collection
│ ├─ USER_KEYS? │──→ register("user"/"email", val)
│ ├─ CERT_SUBJECT_KEYS?│──→ parse DN components
│ ├─ PATH_KEYS? │──→ register("path", val)
│ ├─ HOST_KEYS? │──→ parse host:port -> hostname/fqdn/ip
│ ├─ REMOTE_LOCAL_KEYS?│──→ parse host:port
│ ├─ CLIENT_KEYS? │──→ parse host (skip conn\d+)
│ ├─ CONN_STRING_KEYS? │──→ parse mongodb:// URI
│ ├─ APP_NAME_KEYS? │──→ register("appname", val)
│ ├─ HOST_LIST_KEYS? │──→ split comma, parse each host
│ ├─ FREETEXT_KEYS? │──→ regex scan + BSON scan
│ ├─ SKIP_KEYS? │──→ (skip entirely)
│ └─ (other)? │──→ _discover_freetext_light(val)
└─────────────────────────┘
┌─────────────────────────────┐
│ decode BSON documents │
│ from binary file │
└────────────┬────────────────┘
│
┌────────────▼────────────────┐
│ For each FTDC document: │
│ ├─ type 0 (metadata)? │──→ deep_discover_bson(doc)
│ ├─ type 1 (metric)? │──→ decompress chunk
│ │ │ extract reference BSON
│ │ │ deep_discover_bson(ref_doc)
│ └─ type 2 (periodic)? │──→ deep_discover_bson(doc)
└─────────────────────────────┘
Coverage is based on analysis of all 2,233 LOGV2 attribute keys in the Percona Server for MongoDB 8.0 source code.
| Deployment Type | Log Coverage | FTDC Coverage | Notes |
|---|---|---|---|
| Standalone | ~98% | ~98% | Covers connections, auth, commands, paths, TLS, LDAP |
| Replica Set | ~98% | ~98% | Covers member hosts, sync sources, elections, heartbeats, configs |
| Sharded Cluster | ~98% | ~98% | Covers shard IDs, chunk migrations, resharding, balancer, config servers, mongos routing |
| Legacy text logs | ~90% | N/A | Regex-based -- catches IPs, FQDNs, emails; may miss short hostnames in unstructured text |
Embedded BSON documents within free-text fields (like oplog entries in error messages) are parsed generically without hardcoded field names:
- All
key: "value"pairs are extracted via regex - Values are classified by content pattern (namespace, host, shard, email, IP, path, FQDN, Java class)
- Values matching safety checks are skipped:
- Structural BSON keys (
op,ts,$set,filter, etc.) - Known safe values (
true,false,majority, status enums, etc.) - Country codes (ISO 3166-1 alpha-2)
- Currency codes (ISO 4217)
- Pure numbers, hex strings (ObjectIds), UUIDs
- Single characters, BSON type markers
- Structural BSON keys (
- Everything else is registered as generic
data
| Pattern | Purpose | Regex |
|---|---|---|
RE_IP |
IPv4 addresses | \b(?:\d{1,3}\.){3}\d{1,3}\b |
RE_FQDN |
Fully qualified domain names | \b(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.){2,}[a-zA-Z]{2,}\b |
RE_EMAIL |
Email addresses | \b[\w.+-]+@[\w.-]+\.\w{2,}\b |
RE_LDAP_DN_COMPONENT |
LDAP DN parts (DC=, OU=, CN=, O=, L=, ST=) | \b(?:DC|OU|CN|O|L|ST)=([A-Za-z][A-Za-z0-9 ._-]*) |
RE_JAVA_CLASS |
Java class names | \b((?:[a-z][a-z0-9]*\.){2,}[A-Z]\w*)\b |
RE_BSON_STRING_FIELD |
Key-value pairs in stringified BSON | (\w+):\s*"([^"]*)" |
RE_PURE_NUMBER |
Numbers (safe, not obfuscated) | ^-?\d+\.?\d*$ |
RE_HEX |
Hex strings, ObjectIds (safe) | ^[0-9a-fA-F]{24,}$ |
RE_UUID_LIKE |
UUID format (safe) | ^[0-9a-fA-F]{8}-...-[0-9a-fA-F]{12}$ |
-
Two-pass requirement: All input files must be read twice -- once for discovery, once for replacement. The tool cannot stream logs in real-time.
-
Memory: All unique sensitive values and their mappings are held in memory. For very large log sets with millions of unique values, memory usage could be significant.
-
String replacement: Replacement is done via simple
str.replace(), not JSON-aware. In rare cases, a short sensitive value could match a substring in an unrelated context. Longest-first ordering mitigates this. -
Depth limit: Nested JSON/BSON structures are walked to a maximum depth of 20. Extremely deep nesting beyond this limit will not be processed.
-
FQDN heuristics: The FQDN regex filters out entries starting with digits, containing uppercase characters, having more than 4 parts, or matching known non-domains. Some edge-case FQDNs may be missed.
-
Short hostnames in unknown keys: For attribute keys not in any recognized set, the fallback light scan only triggers full freetext analysis if an IP, email, or FQDN pattern is detected. A bare short hostname (e.g.,
"mykey": "prodserver") in an unrecognized key will not be caught. -
Connection string passwords: If a MongoDB connection string contains embedded credentials (
mongodb://user:password@host/db), the password portion is not explicitly handled. The host and database portions are obfuscated, but password handling should rely on MongoDB's own log redaction (--redactClientLogData). -
FTDC schema preservation: When obfuscating FTDC metric chunks, the reference document's field structure (names, types, order) must not change — only string values are modified. This is guaranteed by the current implementation, but adding/removing fields would break the delta stream alignment.