Case study · 2026 to present

Redact

The problem

Every other ecosystem has one of these. .NET ships Microsoft.Extensions.Compliance.Redaction, Python has loggingredactor, PHP has a Monolog processor. C++ has nothing, and spdlog has no such feature, so every service that wants to keep a password out of its logs writes the same three hundred lines in private. Most of them find out they got it wrong the same way everyone does, by reading a credential out of a log file.

Redact takes text on its way to a log and returns it with the secrets masked and nothing else about it changed. Construct a Redactor with the default policy, call redact, and PASSWORD="hunter2" comes back as PASSWORD="***".

Five detectors ship today. Assignments cover KEY=value and its variants, including JSON pairs, against a configurable key list. URL userinfo masks the password in scheme://user:password@host and keeps the user. Known token shapes catch the secrets that arrive with no key beside them, because they are a whole response body or a file: GitHub tokens, AWS access key IDs, Slack and Stripe keys, Google API keys, a JWT whose header segment decodes to JSON naming alg, and PEM private key blocks. Command-line credential flags cover --password value and the rest of the key list. The last detector handles Authorization, Proxy-Authorization, Cookie and Set-Cookie, recognised anywhere in the text rather than only at the start of a line, so a header embedded in a JSON body is caught like any other.

Some of the limits are deliberate rather than unfinished. -p masks only when its value is attached, as in mysql -pHunter2, because that attachment is the one thing separating a password from an unrelated flag spelled -p that takes its own argument. A parameterised authorisation scheme has its parameter names masked along with the values, which over-masks but keeps the structure and avoids parsing every scheme separately for no security gain.

Version 0.1.0, with no tagged release yet.

Stack and tooling

LanguageC++20
BuildCMake 3.24
Analysisclang-tidy and clang-format
Optional targetslibFuzzer harnesses and benchmarks

5

Secret detectors