Skip to content

rtb-redact

Strips secrets out of free-form strings before they reach telemetry, distributed logs, or any third-party observability surface. The rule set runs in a fixed order and is deliberately conservative — it errs toward over-redaction.

It works by shape, not by value: it holds no list of your secrets and recognises credentials by what they look like, so it catches the token an upstream error quoted back at you as readily as the one you were holding.

Part of the phpboyscout Rust toolkit; extracted from — and battle-tested by — rust-tool-base.

[dependencies]
rtb-redact = "0.6"

Minimum supported Rust version 1.82. Two runtime dependencies, regex and phf. No unsafe — the crate root carries #![forbid(unsafe_code)].

Public API

use rtb_redact::string;

let scrubbed = string("connect to postgres://app:hunter2@db/mydb");
assert!(scrubbed.contains("[redacted]"));
assert!(!scrubbed.contains("hunter2"));
Item Purpose
string Redact a &str, returning CowBorrowed when nothing matched (no allocation on the common case), Owned otherwise.
string_into Same rules, writing into a caller-supplied String so a buffer can be reused. Clears the buffer first — it replaces the contents, it does not append.
SENSITIVE_HEADERS phf::Set of the ten header names whose values must be redacted at DEBUG/TRACE. O(1) lookup.
is_sensitive_header ASCII-case-insensitive membership test against SENSITIVE_HEADERS.
redact_header_value Mask a single header value: [redacted] for anything non-empty, "" for empty.

Every signature, default and edge case is in the API reference. The rustdoc is on docs.rs/rtb-redact.

There is nothing to configure: no feature flags, no options struct, no way to add a pattern at runtime.

What gets redacted

string strips URL userinfo, common credential query parameters, Bearer/Basic/Token credentials, PEM private-key blocks, well-known provider prefixes (sk-, sk-ant-, ghp_, glpat-, AIza, AKIA, Slack xox…, SendGrid SG.), JWTs of 100 characters or more, and whitespace-bounded opaque runs of 40 characters or more. Everything it replaces becomes the literal [redacted].

A fast pre-check bails out before allocating when no anchor character or keyword is present, so the hot path on clean strings is cheap.

The full catalogue — patterns, order, thresholds, and what each rule does not match — is in Redaction rules.

What it does not do

Worth knowing before you rely on it:

  • It is not a guarantee. A bespoke credential format matches nothing, and a secret shorter than the thresholds slips through.
  • JSON and YAML are not parsed. password=hunter2 is redacted; "password": "hunter2" is not.
  • Header values are not redacted by string. That is a separate, explicit call — see Redact HTTP headers.
  • It over-redacts. A bare git commit hash is 40 characters and becomes [redacted].

The full list, with reasoning, is in What rtb-redact does not do.

Where it's wired

  • rtb-telemetry applies string automatically to an event's args and err_msg before an out-of-process sink serialises them. attrs are not covered — callers own redaction for attribute values.
  • SENSITIVE_HEADERS enumerates the headers to redact at DEBUG and is available for an HTTP-client middleware to apply — until a shared client middleware exists in the framework, redact headers at the call site.
  • Any code emitting free-form strings to an external surface should route through string first — see the how-to.

This crate complements secrecy::SecretString (which prevents typed secrets from being formatted): rtb-redact is the safety net for strings that were assembled and might contain a secret no type system caught.

Where to go next

The documentation follows the Diátaxis framework:

How this differs from the Go module

gitlab.com/phpboyscout/go/redact solves the same problem for the Go toolkit, and the two are not bug-for-bug identical. The differences you are most likely to notice:

rtb-redact go/redact
Opaque-run threshold 40 characters — a git SHA-1 is redacted 41 characters — a git SHA-1 survives
Replacement marker [redacted] everywhere <redacted>, *** and <redacted-token>, by rule
Provider match whole token replaced prefix kept, body masked (sk-***)
Formats covered no github_pat_, glrt-, gldt- all three covered
JSON credential values not matched matched by a dedicated rule
Runtime dependencies regex, phf standard library only

Do not assume a line redacted by one comes out the same from the other.

Further reading

The blog carries a curated route through this subject: Rust, and what survived the port collects everything written about it, ordered so you can start at the beginning rather than newest-first.

Ask phpbotscout

phpbotscout

He answers questions about the projects over on the Discord, citing the docs where they already cover it, and offering to raise an issue where they don't. Bring a bug, an idea, or a questionable engineering decision.

Join the Discord