@dynamic-labs/redaction
v1.1.0
Published
Credential and key-material redaction shared across Dynamic services and browser clients: a key denylist, credential-shaped free-text patterns, a non-mutating deep redactor, and Datadog RUM/Logs beforeSend scrubbers. No pino, no node built-ins — browser-s
Readme
@dynamic-labs/redaction
Credential and key-material redaction shared by Dynamic backends and browser
clients: a key denylist, credential-shaped free-text patterns, a non-mutating
deep redactor, and Datadog RUM/Logs beforeSend scrubbers.
Imports nothing — no pino, no node built-ins — so it is safe in a browser
bundle. @dyn-observability/logger applies these rules to every record it
emits; use this package directly when the sink is not pino.
Public API
| Export | Purpose |
| --------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| redact(value, keys?, options?) | Non-mutating deep redaction of a structured value |
| redactSecretsFromText(text, extraPatterns?) | Scrub credential-shaped runs from a string |
| DEFAULT_REDACT_KEYS | Key substrings redacted at any depth |
| DEFAULT_REDACT_KEY_PATTERNS | Key patterns a substring match misses (private keys, key shares, EACs, axios branches) |
| KEY_MATERIAL_TEXT_PATTERNS | Opt-in text patterns for long hex / base58 runs |
| OPAQUE_RUN_TEXT_PATTERNS | Opt-in text pattern for any 32+ run of [A-Za-z0-9+=_] |
| REDACTED | The replacement token |
| RedactOptions, TextPattern | Option and pattern types |
| scrubRumEvent, scrubLogEvent | Datadog RUM / Logs beforeSend scrubbers |
| BROWSER_REDACT_OPTIONS | Defaults the scrubbers apply on the UI thread |
| redactSensitiveActionTargets, downgradeNetworkErrors | Individual scrubber steps |
| isExtensionNoise, isNetworkError | Event classifiers for callers filtering events themselves |
| RedactableLogEvent, RedactableRumEvent | Structural event types the scrubbers accept |
Structured redaction
import {
DEFAULT_REDACT_KEYS,
KEY_MATERIAL_TEXT_PATTERNS,
redact,
} from '@dynamic-labs/redaction';
const safe = redact(context, DEFAULT_REDACT_KEYS, {
textPatterns: KEY_MATERIAL_TEXT_PATTERNS,
maxDepth: 4,
maxArrayLength: 20,
});- Keys: case-insensitive substring match over
DEFAULT_REDACT_KEYS—authorization,cookie,token,password,secret,api-key/apikey,jwt,passphrase,credential,mnemonic— at ANY depth.DEFAULT_REDACT_KEY_PATTERNScovers the shapes a substring misses:private_key/privateKey,seedPhrase,session-signature,encrypted*Share/*Backup/*Data, key-share and EAC material under any owner prefix (*keyShare(s),*eac(s)— end-anchored, sokeyShareIdandexternalKeyShareIdstay legible), and theconfig/headers/requestbranches an axios error carries. - Free text: surviving strings, error messages and stacks are scrubbed of
credential-shaped runs —
Authorization:values,Bearer/Basiccredentials, JWTs anddyn_*keys. - Boolean values survive a matching key name:
hasPassword,passwordEncryptedand friends stay queryable, since a boolean carries no credential material. An explicitpathsrule still redacts them. - Errors become
{ type, message, stack }plus their redacted enumerable own-properties, matching pino'sstdSerializers.errshape. - The input is never mutated; cycles collapse to
[Circular].
RedactOptions beyond paths / allow / patterns:
textPatterns— extra free-text patterns.KEY_MATERIAL_TEXT_PATTERNS(long hex, base58) is opt-in: those shapes are also EVM addresses, tx hashes and block hashes, so they only pay off where chain identifiers are not logged.OPAQUE_RUN_TEXT_PATTERNS(any 32+ run of[A-Za-z0-9+=_]) is opt-in for the same reason: it catches credentials of unrecognized shape in untrusted text — a dependency's error string — and excludes separators so URLs, hostnames and UUIDs stay legible.maxDepth— depth at which a nested value collapses to[REDACTED]. Unbounded by default.maxArrayLength— number of array entries kept. Unbounded by default.
Datadog browser SDKs
scrubRumEvent and scrubLogEvent scrub an event in place for the
beforeSend hooks, defaulting to BROWSER_REDACT_OPTIONS (key-material text
patterns, depth 4, 20 array entries — the hook runs on the UI thread for every
event).
import { scrubLogEvent, scrubRumEvent } from '@dynamic-labs/redaction';
datadogRum.init({ beforeSend: (event) => scrubRumEvent(event) });
datadogLogs.init({ beforeSend: (event) => scrubLogEvent(event) });scrubRumEvent redacts action target names that carry key material and, for
error events, the error message and stack. scrubLogEvent redacts the message,
the error message and stack, and every caller-supplied attribute (Datadog's
typed message/date/status are handled separately so their shape survives).
Both return false — dropping the event — for an error raised by a browser
wallet extension, whose inpage script runs in the page and otherwise dominates a
catch-all error monitor. scrubLogEvent also downgrades a transient network
failure (blocked or aborted request, EIP-1193 provider disconnect) from error
to warn instead of dropping it. isExtensionNoise, isNetworkError and
downgradeNetworkErrors are exported for callers that classify events
themselves.
