Skip to content

feat(redaction): registry-fed exact-value and key-form redaction from user pattern file - #97383

Closed
hermes-node8 wants to merge 3 commits into
NousResearch:mainfrom
db3-studio:feat/redaction-exact-value-pattern-file
Closed

hermes-node8 wants to merge 3 commits into
NousResearch:mainfrom
db3-studio:feat/redaction-exact-value-pattern-file

Conversation

@hermes-node8

@hermes-node8 hermes-node8 commented Aug 28, 2026

Copy link
Copy Markdown

What does this PR do?

What this adds: exact operator-registered values and registered key-forms are masked at Hermes' existing redaction boundaries, from a user-owned JSON pattern file.

Why: Hermes' built-in applied-secret snapshot covers external-source values only; operators cannot register their own exact secrets (values that arrive through non-KEY=value shapes, or short secrets exact matching can't safely touch).

Safety: additive-only (no pattern file → the pass is a no-op; under-masking is structurally impossible) · fail-safe (broken file → last-good set, never an unmasked gap) · sentinel-protected (masked values can never be written back) · display-only (never modifies .env, vault, or config) · per-instance ($HERMES_HOME-resolved default).

Scope: this PR adds the source/value layer; it does not modify at-rest data and does not implement egress-boundary wiring (#72778 is a deliberately separate follow-up — the two compose rather than conflict).

Related Issue

Type of Change

  • 🔒 Security fix

Changes Made

Minimal integration surface — 5 code files + 2 test files:

  • agent/redact.py — one new processing stage: _redact_registry_patterns (pattern-file load, mtime-keyed cache, fail-safe last-good, sentinel on file reads, longest-match-first literal pass, plain + URL-query key-form passes). Implementation is concentrated in the existing redaction module: no new subsystem, no new abstraction hierarchy, no new CLI, no new format persisted by Hermes; existing redaction semantics are unchanged when the pass is disabled.
  • cli.py / gateway/run.py / hermes_cli/main.py — four small wiring changes: bridge security.redact_patterns (config.yaml fallback; the env var still wins) to HERMES_REDACT_PATTERNS at the three process entry points, before agent.redact is imported — mirroring the existing security.redact_secrets bridge.
  • hermes_cli/config.py — documents the new key in the commented config template.
  • tests/agent/test_redact_registry_patterns.py + tests/hermes_cli/test_redact_patterns_bridge.py — 26 tests: mask styles, fail-safe/cache/sentinel behavior, key-form forms, URL-boundary semantics (query-position key-form masking gated on redact_url_credentials, bounded at the next &/#; registered exact values unconditional), and the config→env bridge end-to-end.

Security surface

No new network, IPC, subprocess, or write-side surface is introduced. The new security-relevant input is the operator-controlled pattern file — inside the agent's existing trust envelope (the same class as config.yaml / .env), processed fail-safe and additive-only. The generated matching expressions are ReDoS-resistant by construction: registered key names are escaped literals. Arbitrary user-supplied regex is not accepted by this PR.

Why not a plugin?

Hermes' plugin redaction registry (#84927) lets plugin authors register token formats. The guarantees this feature requires — pass ordering relative to the built-in masker, URL-boundary semantics at engine call sites, unconditional execution at every boundary, operator-managed exact-value state — are not expressible through the current plugin contract (registration, not control).

How to Test

  1. Create a pattern file, e.g. {"literals": ["my-exact-value"], "key_patterns": {"PIN": true}}.
  2. Point HERMES_REDACT_PATTERNS at it (or set security.redact_patterns in config.yaml).
  3. Run the redaction-surface suite:
    pytest tests/agent/test_redact.py tests/agent/test_compaction_redaction_boundaries.py tests/agent/test_tool_call_arg_no_redaction.py tests/hermes_cli/test_redact_config_bridge.py tests/agent/test_redact_registry_patterns.py tests/hermes_cli/test_redact_patterns_bridge.py tests/tools/test_terminal_output_transform_hook.py
    (fork PRs: CI needs a maintainer's workflow approval to run — until then, exact repro:)
    env -u HERMES_HOME HERMES_REDACT_PATTERNS=<pattern-file> python -m pytest tests/agent/test_redact.py tests/agent/test_compaction_redaction_boundaries.py tests/agent/test_tool_call_arg_no_redaction.py tests/hermes_cli/test_redact_config_bridge.py tests/agent/test_redact_registry_patterns.py tests/hermes_cli/test_redact_patterns_bridge.py tests/tools/test_terminal_output_transform_hook.py -q

Validation

  • Rebased and verified on current main (18a76be1, 2026-09-01): redaction-surface suite 142/142 with a populated pattern file, including the upstream terminal-output transform hook (test_terminal_output_transform_still_runs_strip_and_redact) and the PR's registry-pass + config-bridge tests.
  • The registry key-form/query sub-passes respect the upstream code_file contract (Secret redaction corrupts code syntax in tool output (write_file, execute_code, terminal) #33801): gated on not code_file or file_read, so terminal/source-code output keeps its token-prefix markers; exact-value literals stay unconditional.
  • Apply-checked across v0.20.0 – v0.21.0 (8 release tags v2026.8.3 → v2026.8.31) + origin/main — APPLY OK on all.
  • Behavior battery (extremes, hermetic + populated pattern file): v0.20.0 90/90, v0.20.6 114/114 (the transform failure is fixed on the shipped range too), v0.21.0 116/116.
  • At-rest posture: the pattern file defaults to $HERMES_HOME/state/redaction/redact_patterns.json (0600, per-instance); file-read content is masked with a non-reusable sentinel ([Bug]: redact_sensitive_text corrupts API keys in config files when read via read_file/search_files, causing 401 #35519 semantics), so the pattern file itself can never be written back over its own values.
  • Compatibility is continuously checked against Hermes releases; the contributor re-verifies and rebases within 48 hours of new releases (latest check: 2026-09-01, v0.21.0).

Checklist

  • Conventional commits
  • Tests run and green
  • Security surface documented
  • Cross-platform impact considered (pure Python, no new dependencies)

@alt-glitch alt-glitch added type/security Security vulnerability or hardening P3 Low — cosmetic, nice to have comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery area/config Config system, migrations, profiles sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 28, 2026
@hermes-node8

Copy link
Copy Markdown
Author

@kshitijk4poor — you've been working directly in agent/redact.py, so I'd especially value your take on whether this fits the current redaction direction. I've kept the integration surface narrow and aligned this revision with the newer URL-credential behavior.

…ser pattern file

Operator-controlled exact-value layer: a user-owned JSON pattern file
(security.redact_patterns / HERMES_REDACT_PATTERNS) of exact literals
and key-forms, masked at Hermes' existing redaction boundaries.

- agent/redact.py: _redact_registry_patterns pass — additive-only,
  fail-safe (last-good cache), sentinel on file reads, longest-first
  literal pass, plain + URL-query key-form passes (query-position
  masking gated on redact_url_credentials, bounded at '&'/'#')
- cli.py / gateway/run.py / hermes_cli/main.py: config->env bridge at
  the three entry points before agent.redact is imported
- hermes_cli/config.py: documented security.redact_patterns key

Refs NousResearch#43666 (compaction-boundary slice). No new surface classes:
additive-only, ReDoS-safe (escaped literals only), no user regex.
… sentinel, URL-boundary flag semantics, config bridge e2e
…pass

Under code_file=True (source-code / terminal-output contexts) upstream
deliberately skips ENV-assignment masking so code constants survive and
token-shaped values are masked by the built-in _PREFIX_RE pass with a
visible prefix marker (NousResearch#33801). The registry pass previously re-masked
KEY=value assignments unconditionally, destroying that marker and
failing the upstream terminal-output transform test with a populated
pattern file.

Gate the key-form and URL-query sub-passes on not code_file or file_read;
exact-value literals stay unconditional. file_read content is exempt
because file_read implies code_file=True upstream, and .env/config reads
must keep key-form masking.
@hermes-node8-app
hermes-node8-app Bot force-pushed the feat/redaction-exact-value-pattern-file branch from 667746b to 16d94dd Compare September 1, 2026 12:58
@hermes-node8

Copy link
Copy Markdown
Author

Updated implementation: the registry pass now respects the code_file contract (#33801). With a populated pattern file, the previous revision re-masked KEY=value assignments in terminal/source-code output, destroying the token-prefix marker upstream guarantees survives — test_terminal_output_transform_still_runs_strip_and_redact failed deterministically. The key-form and URL-query sub-passes are now gated on not code_file or file_read; exact-value literals remain unconditional. Rebased on current main (18a76be1): the redaction-surface suite is 142/142 with a populated pattern file, and the apply matrix is green across v0.20.0 → v0.21.0 (8 tags) + origin/main. PR body updated with the exact repro (fork CI needs a maintainer's workflow approval to run).

@hermes-node8

Copy link
Copy Markdown
Author

Closing this PR — we found we can accomplish what we need through the plugin redaction registry (#84927): exact values register as escaped patterns with the built-in word-boundary anchors and file-read sentinel, so no engine change is required. Thanks for the consideration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/security Security vulnerability or hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants