T tomlkit·org
Inspect Formatter Validator Lint Stats Keys Query Convert TOMLJSON JSONTOML TOMLYAML YAMLTOML INITOML TOMLINI .envTOML TOML.env TOMLTS TOMLCSV CSVTOML TOMLXML TOML.properties .propertiesTOML Transform Sort keys Flatten Unflatten Redact Minify Generate Go struct Rust struct Python types JSON Schema Compare Diff Merge

TOML Redact

updated 20 August 2026

Paste a config, get the same config back with every credential-looking value replaced by ***. Use it before attaching a config.toml to a bug report, sharing a snippet in a chat, or pasting into an AI prompt — the structure survives, the secrets do not.

key-name matching, case-insensitive

What this tool does

It parses the document, looks at every key name, and replaces the value of any key whose name contains one of your match words. Matching is case-insensitive and substring-based, so API_KEY, api_key, and stripe_secret_key all match the default list. When a matched key holds a whole table, every leaf inside that table is masked too — so [auth.tokens] is emptied in one go.

The intent it closes: "I need to show someone this config without showing them our credentials." The shape, the key names, the ports, the hostnames, and the comments-free structure all stay intact, which is exactly what a person debugging your file needs to see.

It is a key-name filter, not a secret scanner: it does not look at values, so a high-entropy string parked under an innocuous key name (note = "sk-live-…") is not caught. Add the key name to the match list, or check the output before you send it.

When you'd reach for it

  • Filing a bug report. Attach the redacted file so maintainers can reproduce the structure without holding your keys.
  • Pasting into a chat or an AI prompt. Third-party services log what you paste; masking first means the log holds nothing useful.
  • Writing documentation. Produce an example config from a real one and be sure no live token slipped through.
  • Committing an example file. Generate config.example.toml from your working config, so it never drifts from the real key set.
  • Screen sharing. Open the redacted copy instead of the original before you present.

How it works

Redaction happens in three steps, all inside the page.

1. Parse the document

The TOML is parsed into a value tree. That is what makes the mask reliable — the tool knows which text is a key and which is a value, so a word like password appearing inside a URL is not mistaken for a key.

2. Match key names

Every key is lower-cased and tested against each comma-separated word in your list. A hit whose value is a scalar has that value replaced by the mask. A hit whose value is a table or an array is walked recursively and every leaf inside it is masked, which is how a whole [credentials] section disappears at once.

3. Re-emit canonical TOML

The redacted tree is written back out through the canonical emitter. Spacing and quoting come out normalised as a side effect of parse-and-re-emit, and comments are not preserved — the parser does not carry them into the tree. The mask itself is written as a plain string.

Options reference

Match keys containing

A comma-separated list of substrings. A key matches when its lower-cased name contains any of them, so token catches refresh_token and TOKEN_URL alike. Trim the list to be surgical, or extend it with your own names — dsn, connection_string, webhook, salt, seed are common additions.

Mask

The replacement string. *** reads as obviously-removed; REDACTED or <set-in-env> are useful when the output doubles as an example file. It is emitted as a TOML string, so a masked integer becomes a quoted value — expected, since the point is that the real number is gone.

Example

Input:

[database]
host = "db.internal"
password = "s3cr3t-pg-pw"

[auth.tokens]
refresh = "rt_9a8b7c"
access = "at_1d2e3f"

Output (default match list):

[database]
host = "db.internal"
password = "***"

[auth.tokens]
refresh = "rt_9a8b7c"
access = "at_1d2e3f"

password matched on its own name. The two token values did not — their key names are refresh and access, which contain none of the match words; it is the parent table that is called tokens. Add tokens to the list and the whole table is masked, because a matched key holding a table has all of its leaves replaced.

Limits and notes

  • Key names, not values. Nothing is entropy-scored. A secret stored under a bland key name survives — read the output before sharing.
  • Comments are dropped. Parse-and-re-emit loses them, so a comment holding a credential disappears too, but so does your documentation.
  • Structure is still revealing. Hostnames, internal service names, bucket names, and usernames are not credentials by these rules and stay visible. Redact them by adding their key names.
  • Rotate anything already leaked. Masking a copy does not undo a secret that has been pushed, pasted, or logged elsewhere.

FAQ

Does it detect secrets by looking at the values?

No. It matches on key names only, which keeps it predictable and fast but means a token parked under a name like note or comment is missed. Scan the output yourself, and add any key names you care about to the match list.

Will a whole section be masked if the section name matches?

Yes. When a matching key holds a table — [secrets], [api.keys] — every leaf value inside it is replaced, at any depth. That is usually what you want for a credentials block.

Are my comments kept?

No. The TOML parser does not carry comments into the value tree, so re-emission cannot print them. Keep the original file as the source of truth.

Can I use it to build a config.example.toml?

That is a good use for it. Set the mask to something like <set-me>, redact your working config, and commit the result — the example then always has exactly the keys the real config has.

Is anything sent to a server?

No. The parse, the mask, and the re-emit all run in your browser. That matters more here than for most tools: the input is, by definition, the file with your secrets in it.