From 6697658e19eaa4aca08d83d0ec3eaed00b944dbe Mon Sep 17 00:00:00 2001 From: maxx-GENIUS Date: Sat, 10 Oct 2026 19:49:37 -0700 Subject: [PATCH] feat(security): implement PII and credential scrubbing for telemetry context --- src/lib/redact.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/lib/redact.ts diff --git a/src/lib/redact.ts b/src/lib/redact.ts new file mode 100644 index 0000000..e46a217 --- /dev/null +++ b/src/lib/redact.ts @@ -0,0 +1,33 @@ +const SENSITIVE_KEYS = new Set(['authorization', 'accesstoken', 'refreshtoken', 'token', 'password', 'secret']); + +export function truncateAddress(addr: string): string { + if (typeof addr === 'string' && addr.startsWith('G') && addr.length === 56) { + return ${addr.slice(0, 4)}...; + } + return addr; +} + +export function redactContext(ctx: Record, depth = 0): Record { + if (depth > 4 || typeof ctx !== 'object' || ctx === null) { + return { '[truncated]': true }; + } + + const result: Record = {}; + for (const [key, val] of Object.entries(ctx)) { + if (SENSITIVE_KEYS.has(key.toLowerCase())) { + continue; // Scrub credentials completely + } + if (key.toLowerCase() === 'headers' && typeof val === 'object') { + result[key] = '[redacted]'; + continue; + } + if (typeof val === 'string') { + result[key] = truncateAddress(val); + } else if (typeof val === 'object' && val !== null) { + result[key] = redactContext(val as Record, depth + 1); + } else { + result[key] = val; + } + } + return result; +} \ No newline at end of file