Skip to content

Redact before an external surface

Any free-form string that leaves the process — a telemetry event, a log line shipped to a third-party sink, an error message attached to a crash report — may have had a secret interpolated into it somewhere upstream. Route it through rtb_redact::string at the boundary:

use rtb_redact::string;

fn emit(event_args: &str) {
    let safe = string(event_args);
    external_sink.send(&safe);
}

string returns Cow::Borrowed when nothing matched, so the common clean-string case costs no allocation. For hot paths that reuse a buffer, string_into appends into a caller-supplied String.

Headers

At DEBUG/TRACE, HTTP headers get logged. Check names against the SENSITIVE_HEADERS set and redact values before they hit the log:

use rtb_redact::{is_sensitive_header, redact_header_value};

for (name, value) in headers {
    let shown = if is_sensitive_header(name) {
        redact_header_value(value)
    } else {
        value.into()
    };
    tracing::debug!(header = name, value = %shown);
}

What not to do

  • Don't redact typed secrets with this crate — those belong in secrecy::SecretString, which prevents them being formatted at all. rtb-redact is the safety net for strings already assembled.
  • Don't build your own per-call-site regex list. The whole point is one hardened, tested, conservatively-ordered rule set (see the toolkit's security stance on centralising foot-guns).