Last active
May 18, 2026 10:28
-
-
Save daliborgogic/0cddc4eb6f365e932932b8ef44d4d49b to your computer and use it in GitHub Desktop.
redacted.ts — Hardened, spec-compliant opaque type wrapper for sensitive data in TypeScript/Node.js.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { describe, it, expect } from 'vitest'; | |
| import { Redacted } from './redacted'; | |
| describe('Redacted Production-Grade Safety', () => { | |
| it('unwraps a value correctly', () => { | |
| const secret = { key: 'shhh' }; | |
| const r = Redacted.make(secret); | |
| expect(Redacted.value(r)).toBe(secret); | |
| }); | |
| it('prevents exposure via common methods', () => { | |
| const r = Redacted.make('secret'); | |
| expect(r.toString()).toBe('[Redacted]'); | |
| expect(JSON.stringify(r)).toBe('"[Redacted]"'); | |
| }); | |
| describe('Loud Failure (The Engineering Contract)', () => { | |
| it('throws EXPLICITLY when spreading the object', () => { | |
| const r = Redacted.make('secret'); | |
| // Attempting to spread should throw because ownKeys() or getOwnPropertyDescriptor() throws | |
| expect(() => ({ ...r })).toThrow(/Redacted instances cannot be enumerated/); | |
| }); | |
| it('throws EXPLICITLY when using Object.assign', () => { | |
| const r = Redacted.make('secret'); | |
| expect(() => Object.assign({}, r)).toThrow(/Redacted instances cannot be enumerated/); | |
| }); | |
| it('fails during structuredClone (Platform-level failure)', () => { | |
| const r = Redacted.make({ data: 123 }); | |
| // structuredClone throws DataCloneError for Proxies | |
| expect(() => structuredClone(r)).toThrow(); | |
| }); | |
| it('prevents illegal property access', () => { | |
| const r = Redacted.make('secret'); | |
| // @ts-ignore - testing runtime safety | |
| expect(() => r.someRandomKey).toThrow(/Illegal access to Redacted property/); | |
| }); | |
| }); | |
| describe('Performance & GC Safety', () => { | |
| it('maintains performance under load', () => { | |
| const count = 10_000; | |
| const start = performance.now(); | |
| const items = []; | |
| for (let i = 0; i < count; i++) { | |
| items.push(Redacted.make(i)); | |
| } | |
| const end = performance.now(); | |
| expect(items.length).toBe(count); | |
| expect(end - start).toBeLessThan(500); // Should be very fast | |
| }); | |
| it('passes instanceof checks', () => { | |
| const r = Redacted.make('secret'); | |
| expect(r instanceof Redacted).toBe(true); | |
| }); | |
| }); | |
| describe('Redacted.sanitize()', () => { | |
| it('replaces redacted instances in nested objects', () => { | |
| const secret = Redacted.make('shhh'); | |
| const payload = { | |
| user: 'dalibor', | |
| token: secret, | |
| meta: { | |
| key: secret | |
| }, | |
| list: [secret, 'normal'] | |
| }; | |
| const sanitized = Redacted.sanitize(payload); | |
| expect(sanitized.user).toBe('dalibor'); | |
| expect(sanitized.token).toBe('[Redacted]'); | |
| expect(sanitized.meta.key).toBe('[Redacted]'); | |
| expect(sanitized.list[0]).toBe('[Redacted]'); | |
| expect(sanitized.list[1]).toBe('normal'); | |
| // Original should be untouched (since we returned a new object) | |
| expect(Redacted.value(payload.token)).toBe('shhh'); | |
| }); | |
| it('handles primitive values correctly', () => { | |
| expect(Redacted.sanitize(42)).toBe(42); | |
| expect(Redacted.sanitize('string')).toBe('string'); | |
| expect(Redacted.sanitize(null)).toBe(null); | |
| }); | |
| }); | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const registry = new WeakMap<object, any>(); | |
| const SAFE_PROPS = new Set<string | symbol>([ | |
| "toString", | |
| "toJSON", | |
| Symbol.for("nodejs.util.inspect.custom"), | |
| Symbol.toStringTag, | |
| Symbol.toPrimitive | |
| ]); | |
| const LOUD_FAILURE_MSG = "Redacted instances cannot be enumerated, cloned, or spread. This prevents accidental data loss. Sensitive data must be unwrapped via Redacted.value(instance)."; | |
| /** | |
| * Shared proxy handler to minimize GC overhead. | |
| */ | |
| const REDACTED_HANDLER: ProxyHandler<any> = { | |
| get(target, prop, receiver) { | |
| if (SAFE_PROPS.has(prop)) { | |
| const value = Reflect.get(target, prop, receiver); | |
| return typeof value === 'function' ? value.bind(target) : value; | |
| } | |
| throw new Error(`Illegal access to Redacted property "${String(prop)}". ${LOUD_FAILURE_MSG}`); | |
| }, | |
| getOwnPropertyDescriptor(target, prop) { | |
| // To be spec-compliant, we throw our custom message before the engine | |
| // can throw a generic TypeError for invariant violations. | |
| if (Reflect.has(target, prop)) { | |
| throw new Error(LOUD_FAILURE_MSG); | |
| } | |
| return undefined; | |
| }, | |
| ownKeys() { | |
| // Throwing here short-circuits enumeration (Object.keys, spread, for-in) | |
| throw new Error(LOUD_FAILURE_MSG); | |
| }, | |
| getPrototypeOf() { return null; }, | |
| setPrototypeOf() { throw new Error("Redacted instances are sealed."); }, | |
| set() { throw new Error("Redacted instances are immutable."); }, | |
| defineProperty() { throw new Error("Redacted instances are sealed."); }, | |
| deleteProperty() { throw new Error("Redacted instances are sealed."); }, | |
| preventExtensions() { return true; }, | |
| isExtensible() { return false; } | |
| }; | |
| class RedactedImpl { | |
| // Marker to satisfy Proxy ownKeys requirements if we ever return keys | |
| private readonly "__redacted_lock__" = true; | |
| constructor() { | |
| Object.seal(this); | |
| } | |
| toString() { return "[Redacted]"; } | |
| toJSON() { return "[Redacted]"; } | |
| [Symbol.for("nodejs.util.inspect.custom")]() { return "[Redacted]"; } | |
| get [Symbol.toStringTag]() { return "Redacted"; } | |
| } | |
| /** | |
| * A production-grade container for sensitive values. | |
| * | |
| * DESIGN RATIONALE: | |
| * 1. Proxy-based protection: Any attempt to spread, enumerate, or access properties | |
| * directly on a Redacted instance throws a "Loud Failure" error. | |
| * 2. Identity Resilience: Registers both the target and the proxy in a WeakMap | |
| * to prevent identity mismatches during internal unwrapping. | |
| * 3. Spec-Compliant: Uses property descriptor traps on a sealed target to | |
| * enforce the engineering contract without violating Proxy invariants. | |
| * | |
| * OPERATIONAL WARNING (Terminal Data Type): | |
| * This utility is a "terminal data type." It is designed to crash the process | |
| * if passed to third-party libraries that attempt deep cloning or custom | |
| * serialization (e.g., Winston, Zod). Use Redacted.sanitize() before logging. | |
| */ | |
| export class Redacted<A> { | |
| private constructor() {} | |
| static make<A>(value: A): Redacted<A> { | |
| const target = new RedactedImpl(); | |
| const proxy = new Proxy(target, REDACTED_HANDLER); | |
| registry.set(target, value); | |
| registry.set(proxy, value); | |
| return proxy as unknown as Redacted<A>; | |
| } | |
| static value<A>(self: Redacted<A>): A { | |
| if (!registry.has(self as any)) { | |
| throw new Error("Invalid or uninitialized Redacted reference. The instance may have been cloned, spread, or corrupted."); | |
| } | |
| return registry.get(self as any); | |
| } | |
| /** | |
| * Safely sanitizes an object for logging or validation by replacing | |
| * Redacted containers with a placeholder string. | |
| * Handles circular references to prevent stack overflows. | |
| */ | |
| static sanitize(obj: any, seen = new WeakSet<object>()): any { | |
| if (obj === null || typeof obj !== "object") return obj; | |
| if (obj instanceof Redacted) return "[Redacted]"; | |
| if (seen.has(obj)) return "[Circular Reference]"; | |
| seen.add(obj); | |
| if (Array.isArray(obj)) { | |
| return obj.map(item => Redacted.sanitize(item, seen)); | |
| } | |
| const result: Record<string, any> = {}; | |
| for (const key of Object.keys(obj)) { | |
| result[key] = Redacted.sanitize(obj[key], seen); | |
| } | |
| return result; | |
| } | |
| /** | |
| * Ensures `instanceof Redacted` works for both the proxy and the target. | |
| */ | |
| static [Symbol.hasInstance](instance: any) { | |
| return registry.has(instance); | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Redacted: Terminal Data Type Primitive
An ironclad, defensive utility primitive designed to prevent accidental leakage of sensitive data (API keys, forensic secrets, credentials) into application logs, error traces, and serialization payloads.
Redactedwraps sensitive values at the absolute edge of ingestion and enforces a Loud Failure contract. It is designed to intentionally crash the runtime if passed to third-party libraries that attempt deep cloning, custom serialization, or object spreading.graph TD %% Node Definitions Ingestion(["Edge Ingestion<br>(Env Variables, API Payloads)"]) Make["Redacted.make(secret)"] ProxyTarget["Encapsulated in Proxy<br>& Sealed Target"] %% Crash Pathways Spread["Spread / Clone / Object.assign<br>{...obj}"] Logger["Raw Logger / Serialization<br>(Winston, Zod, JSON.stringify)"] Crash1(["INSTANT CRASH<br>(Loud Failure)"]) Crash2(["INSTANT CRASH<br>(Intercepted)"]) %% Success Pathway Value["Redacted.value(secret)"] Consumption(["Edge Consumption<br>(DB Driver, HTTP Client)"]) %% Flow Connections Ingestion --> Make Make --> ProxyTarget ProxyTarget -->|"Trapped via ownKeys / getOwnPropertyDescriptor"| Spread Spread --> Crash1 ProxyTarget -->|"Trapped via get / safe property checks"| Logger Logger --> Crash2 ProxyTarget -->|"Explicit Identity Match via WeakMap"| Value Value --> Consumption %% Styling style Ingestion fill:#1f1f1f,stroke:#333,stroke-width:2px,color:#fff style Consumption fill:#1f1f1f,stroke:#333,stroke-width:2px,color:#fff style Make fill:#2d3748,stroke:#4a5568,stroke-width:2px,color:#fff style Value fill:#2d3748,stroke:#4a5568,stroke-width:2px,color:#fff style ProxyTarget fill:#2c5282,stroke:#3182ce,stroke-width:2px,color:#fff style Crash1 fill:#742a2a,stroke:#e53e3e,stroke-width:2px,color:#fff style Crash2 fill:#742a2a,stroke:#e53e3e,stroke-width:2px,color:#fffCore Architectural Invariants
{ ...redacted }), or merge (Object.assign) aRedactedinstance throws an explicit runtime exception instantly, blocking downstream data leaks.WeakMapregistry, guaranteeing reliable data retrieval (Redacted.value()) without identity mismatch.Technical Specifications
The Runtime Guard Rail
The proxy handler intercepts the object lifecycle at the engine level:
obj.propget()Illegal access...unless property is inSAFE_PROPS.{ ...obj }/Object.assign()ownKeys()/getOwnPropertyDescriptor()LOUD_FAILURE_MSG(Process Termination).obj.prop = valset()/defineProperty()Redacted instances are immutable.Production Usage Guidelines
1. Ingestion and Immediate Unwrapping (The Edge-to-Edge Rule)
Wrap secrets immediately upon configuration loading or API ingestion. Unwrap them only at the final driver or client boundary.
2. Bypassing the Logging Pipeline
To prevent un-sanitized containers from causing cascading failures in your logging or telemetry layers, the core logger (data/shared/logger.ts) implements a mandatory sanitization phase. However, developers should explicitly pass sanitized payloads to avoid telemetry noise:
Operational Warnings
[!CAUTION]
TERMINAL DATA TYPE: This utility is an active operational gate. It cannot be stored in global shared states (e.g., Express Request context, state managers), passed to validation engines (Zod, ArkType), or fed into third-party loggers (Winston, Bunyan) without being pre-sanitized via Redacted.sanitize(). Failure to adhere to this contract will result in an immediate runtime exception.