hermes-bsd/tools
Teknium ccd899318e
fix(cron): split scanner into two tiers so skill prose stops false-positiving (#32339)
The runtime cron prompt scanner (added in #3968 to plug the
"malicious skill carrying an injection payload" gap) reuses the same
critical-severity patterns as the create-time user-prompt scan against
the *assembled* prompt — which includes loaded skill markdown.

That works fine for narrow patterns like "ignore previous instructions"
which never legitimately appear in prose. It catastrophically false-
positives on command-shape patterns like `cat ~/.hermes/.env`,
`authorized_keys`, `/etc/sudoers`, and `rm -rf /`, which routinely
appear in security postmortems and runbooks as **descriptive prose**
about attacks, not as actual commands.

Concrete failure: the bundled `hermes-agent-dev` skill contains a
security postmortem section saying "the attacker could just
`cat ~/.hermes/.env`". Every PR-scout cron job that loaded this skill
was silently blocked with `Blocked: prompt matches threat pattern
'read_secrets'`. All 11 scout jobs failed for weeks.

Fix: split the scanner into two tiers and route by context:

  - `_scan_cron_prompt` (strict, unchanged behavior) runs against
    the small user-authored cron prompt at create/update and as a
    runtime defense-in-depth when no skills are attached. A legit
    user prompt has no business saying `cat .env`, so the strict
    patterns still apply there.

  - `_scan_cron_skill_assembled` (new, looser) runs against the
    assembled prompt when skills are attached. It only catches
    unambiguous prompt-injection directives ("ignore previous
    instructions", "disregard your rules", "system prompt override",
    "do not tell the user") plus invisible-unicode markers. Command-
    shape patterns are dropped because they false-positive on prose.

This is defense-in-depth, not the only line of defense. Skill bodies
are already scanned at install time by `skills_guard.py`; the runtime
cron scan exists purely as a tripwire for an obvious injection
directive surviving a malicious install. Catching prose mentions of
commands was never the goal of #3968 — the test that planted a skill
containing `cat ~/.hermes/.env` was the wrong shape of test for the
threat model.

Tests:
- `_scan_cron_prompt` strict behavior preserved (56 existing tests
  unchanged: bare `cat .env`, `rm -rf /`, etc. still block).
- New `TestScanCronSkillAssembled` class verifies the looser scanner:
  injection / disregard / system-override / do-not-tell-the-user /
  invisible-unicode still block; descriptive prose about attack
  commands is allowed; GitHub auth-header allowlist still works.
- `test_skill_with_env_exfil_payload_raises` (planted `cat .env`
  in skill body) replaced with `test_skill_with_env_exfil_command
  _in_prose_is_allowed` documenting the new correct behavior with
  the real-world postmortem-style example that triggered the bug.
- All 11 originally-failing PR-scout jobs validated end-to-end via
  `_build_job_prompt` — assembled prompts now build successfully
  with the `hermes-agent-dev` skill attached.

Total: 75/75 tests in cron + cronjob_tools + threat scanner pass;
544/544 across the wider cron / memory / threat-pattern surface.
2026-05-25 18:20:45 -07:00
..
computer_use
environments
neutts_samples
__init__.py
ansi_strip.py
approval.py
binary_extensions.py
browser_camofox.py
browser_camofox_state.py
browser_cdp_tool.py
browser_dialog_tool.py
browser_supervisor.py
browser_tool.py
budget_config.py
checkpoint_manager.py
clarify_gateway.py
clarify_tool.py
code_execution_tool.py
computer_use_tool.py
credential_files.py
cronjob_tools.py fix(cron): split scanner into two tiers so skill prose stops false-positiving (#32339) 2026-05-25 18:20:45 -07:00
debug_helpers.py
delegate_tool.py
discord_tool.py
env_passthrough.py
fal_common.py
feishu_doc_tool.py
feishu_drive_tool.py
file_operations.py
file_state.py
file_tools.py
fuzzy_match.py
homeassistant_tool.py
image_generation_tool.py
interrupt.py
kanban_tools.py
lazy_deps.py
managed_tool_gateway.py
mcp_oauth.py
mcp_oauth_manager.py
mcp_tool.py
memory_tool.py
microsoft_graph_auth.py
microsoft_graph_client.py
mixture_of_agents_tool.py
neutts_synth.py
openrouter_client.py
osv_check.py
patch_parser.py
path_security.py
process_registry.py
registry.py
schema_sanitizer.py
send_message_tool.py
session_search_tool.py
skill_manager_tool.py
skill_provenance.py
skill_usage.py
skills_ast_audit.py
skills_guard.py
skills_hub.py
skills_sync.py
skills_tool.py
slash_confirm.py
terminal_tool.py
threat_patterns.py
tirith_security.py
todo_tool.py
tool_backend_helpers.py
tool_output_limits.py
tool_result_storage.py
transcription_tools.py
tts_tool.py
url_safety.py
video_generation_tool.py
vision_tools.py
voice_mode.py
web_tools.py
website_policy.py
x_search_tool.py
xai_http.py
yuanbao_tools.py