fix(security): drop caller-controlled author override in kanban_comment

Comments are injected into the next worker's system prompt by
build_worker_context() as '**{author}** (timestamp): {body}'. The
previous code accepted args['author'] as a free-form override and
exposed it on KANBAN_COMMENT_SCHEMA, which let a worker:

  1. Receive a prompt-injection in a malicious task body.
  2. Call kanban_comment with author='hermes-system' (or any other
     authoritative-looking name) on a sibling task.
  3. The next worker assigned to that sibling task sees the forged
     comment in its boot context as what reads like a system-authored
     directive.

Always derive author from HERMES_PROFILE (the dispatcher already sets
this per worker at hermes_cli/kanban_db.py:3718), and remove the
'author' property from the tool schema so the LLM can't see the
override surface.

Cross-task commenting itself remains unrestricted (see #19713) —
comments are the deliberate handoff channel between tasks; only the
author-override surface is closed.

Co-authored-by: kshitijk4poor <82637225+kshitijk4poor@users.noreply.github.com>
This commit is contained in:
memosr 2026-05-09 14:46:27 +05:30 committed by kshitij
parent e3cd4e401d
commit 9bbad3cc10

View file

@ -373,7 +373,16 @@ def _handle_comment(args: dict, **kw) -> str:
body = args.get("body")
if not body or not str(body).strip():
return tool_error("body is required")
author = args.get("author") or os.environ.get("HERMES_PROFILE") or "worker"
# Author is intentionally derived from the worker's own runtime
# identity, NOT from caller-supplied args. Comments are injected
# into the next worker's system prompt by ``build_worker_context``
# as ``**{author}** (timestamp): {body}`` — accepting an
# ``args["author"]`` override let a worker forge a comment from
# an authoritative-looking name like ``hermes-system`` and poison
# the future-worker context with what reads as a system directive.
# Cross-task commenting itself remains unrestricted (see #19713) —
# comments are the deliberate handoff channel between tasks.
author = os.environ.get("HERMES_PROFILE") or "worker"
try:
kb, conn = _connect()
try:
@ -656,13 +665,6 @@ KANBAN_COMMENT_SCHEMA = {
"type": "string",
"description": "Markdown-supported comment body.",
},
"author": {
"type": "string",
"description": (
"Override author name. Defaults to the current "
"profile (HERMES_PROFILE env)."
),
},
},
"required": ["task_id", "body"],
},