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
| Language | C++20 |
| Build | CMake 3.24 |
| Analysis | clang-tidy and clang-format |
| Optional targets | libFuzzer harnesses and benchmarks |
5
Secret detectors