Redact secrets from JSON, YAML, TOML or Markdown data
Goal: Before writing a config file, an API response, or a Markdown document into a report, a log, or an LLM prompt, mask the fields or text that might hold a password, API key, or other secret, without hand-writing a recursive walk over the data.
Prerequisites: None. redact is a core builtin.
Query
$ mq -I json -F json 'redact(., [{type: "key", pattern: "api_key|password|secret|token"}])' config.json
Or with an explicit value:
redact(
{"name": "demo", "api_key": "sk-abc123def456", "config": {"db_password": "hunter2"}},
[{type: "key", pattern: "api_key|password|secret|token"}]
)
Output
{
"name": "demo",
"api_key": "[REDACTED]",
"config": {
"db_password": "[REDACTED]"
}
}
Redacting a Markdown document
redact also walks a Markdown document, masking matching secrets inside prose, code blocks, and YAML/TOML frontmatter alike:
$ mq 'redact(., [{type: "value", pattern: "sk-[a-z0-9]+"}])' notes.md
Given notes.md:
---
api_key: sk-abc123def456
---
Run with `sk-abc123def456` set as the key.
the output is:
---
api_key: [REDACTED]
---
Run with `[REDACTED]` set as the key.
Notes
redact(value, rules)walks a dict/array/string/markdown node recursively.rulesis an array of:{type: "key", pattern, replacement = "[REDACTED]", case_insensitive = true}: masks a dict value outright when its key matchespattern, without inspecting the value itself. Since Markdown nodes have no keys,keyrules only ever apply inside dicts.{type: "value", pattern, replacement = "[REDACTED]", case_insensitive = true}: replaces matches ofpatterninside a string or Markdown node’s text viagsub, leaving the rest of the text intact (useful for masking an email address or token embedded in a longer message or paragraph).
patternmatches as a substring by default, so"password"also matchesdb_passwordandPASSWORD_HASH(matched case-insensitively unlesscase_insensitive: false). Anchor with^...$for an exact key-name match instead.- mq’s regex engine has no
(?i)inline flag support, socase_insensitivedowncases the subject before matching. Writepatternitself in lowercase. - Numbers, booleans and
Nonepass through unchanged. Rules run top to bottom forvaluerules on the same string, and akeyrule short-circuits (the value is masked without recursing into it, so a secret nested inside an already-redacted key is never inspected). - For a Markdown node with children (a heading, list, link, table cell, …),
redactrecurses into each child. A leaf node (text, code, code_inline, html, yaml, toml, image, definition, …) hasvaluerules applied directly to its own text.