T01 · Skill Instruction Hijacking
Error
- Location
- scripts/agent-wake.py:62
- Finding
- Arbitrary Caller-Controlled System Message Injection## Vulnerability Details **File Location**: `scripts/agent-wake.py:62-84` **Vulnerability Type**: System-level instruction injection **Risk Level**: Critical **Vulnerable Code**: ```python def wake(message: str, channel_id: str = "") -> bool: """ Fire a cron wake event into the agent session. If channel_id is provided, targets that specific Discord channel session. Otherwise targets the main session. """ if not GATEWAY_TOKEN: print("ERROR: GATEWAY_TOKEN not set. Check your .env file.", file=sys.stderr) return False event_text = message if channel_id: event_text = ( f"{message} -- Send your response to Discord channel {channel_id} " f"(use message tool, action=send, target={channel_id}). " f"Do not respond anywhere else." ) body: dict = { "tool": "cron", "args": { "action": "wake", "text": event_text, "mode": "now", }, } ``` The privileged nature of the injected content is explicitly documented in `SKILL.md:52-58`: ```markdown ## What the agent receives The event text is injected as a system message. Be specific -- the agent acts on what you write: ``` Build finished -- 3 errors fixed, tests passing. Send your response to Discord channel 1475232925724315740... ``` ``` ### Technical Analysis The first command-line argument is accepted as arbitrary text and copied directly into the `text` property of an immediate `cron` wake event. According to the Skill documentation, this text is injected into the target agent session as a system message rather than as untrusted notification data. No validation, instruction filtering, event-type allowlist, trust boundary, or separation between data and instructions is applied. Consequently, a caller that can invoke the script can submit imperative content designed to alter ...[truncated 2327 chars]
- Remediation
- ## Remediation Suggestions 1. Never place caller-controlled text into a system message or another privileged instruction channel. 2. Deliver external completion notifications as explicitly untrusted event or user data, accompanied by an immutable instruction that the content must not be treated as commands. 3. Replace free-form messages with a strict schema containing allowlisted fields such as task identifier, status, timestamp, and a length-limited summary. 4. Reject imperative control fields and validate message length, encoding, and permitted event types. 5. Authenticate each event producer independently and bind its credential to approved agents, sessions, event types, and Discord channels. 6. Do not derive session routing or message-tool destinations directly from caller-controlled channel IDs. Use a server-side allowlist mapping trusted task identities to fixed destinations. 7. Require explicit user confirmation before the agent performs consequential tool calls in response to an external wake event. 8. Apply least privilege to the gateway token and target agent so that a notification producer cannot invoke unrelated gateway tools. 9. Record and monitor event producer identity, destination session, event type, and resulting tool activity.
