T01 · Skill Instruction Hijacking
Error
- Location
- scripts/build_checkpoint.py:23
- Finding
- Untrusted checkpoint content can inject automatically dispatched resume instructions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/build_checkpoint.py:23-42`, `scripts/generate_resume_plan.py:17-27`, `scripts/recover_from_latest_checkpoint.py:17-27`, `scripts/pre_resume_verify.py:22-35`, `SKILL.md:115-118, 129-139, 156-159` **Vulnerability Type**: Prompt injection through unsafe serialization and automatic message dispatch **Risk Level**: High ### Vulnerable Code `scripts/build_checkpoint.py:23-42`: ```python for s in sessions: key = s.get("sessionKey", "unknown") agent = s.get("agentId", "unknown") goal = s.get("goal", "(fill)") done = s.get("lastDone", "(fill)") nxt = s.get("nextStep", "(fill)") blockers = s.get("blockers", "none") lines.append(f"## {key}") lines.append(f"- Agent: {agent}") lines.append(f"- Goal: {goal}") lines.append(f"- Last done: {done}") lines.append(f"- Next: {nxt}") lines.append(f"- Blockers: {blockers}") lines.append( f"- Resume message: Continue where you left off. Last completed: {done}. Next: {nxt}." ) lines.append("") ``` `scripts/generate_resume_plan.py:17-27`: ```python fields = {} for ln in lines[1:]: m = re.match(r"-\s*([^:]+):\s*(.*)", ln.strip()) if m: fields[m.group(1).strip()] = m.group(2).strip() msg = fields.get("Resume message") or ( f"Continue where you left off. Last completed: {fields.get('Last done', '(unknown)')}. Next: {fields.get('Next', '(unknown)')}." ) items.append( { "sessionKey": session_key, "agent": fields.get("Agent", "unknown"), "goal": fields.get("Goal", ""), "resumeMessage": msg, } ) ``` `scripts/recover_from_latest_checkpoint.py:17-27`: ```python fields = {} for ln in lines[1:]: m = re.match(r"-\s*([^:]+):\s*(.*)", ln.strip()) if m: fields[m.group(1).strip()] = m.group(2).strip() resume = fields.get("Resume message") or ( f"Continue where you left off. Last completed: {fields.get('Last done', '(unknown)')}. Next: {fi ...[truncated 3593 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace the Markdown checkpoint as the canonical data format with a strictly defined JSON structure. 2. Validate every input field: - Require strings of bounded length. - Reject control characters and embedded newlines where they are not explicitly needed. - Validate session keys against the platform's expected session-key syntax. 3. Never accept a serialized `Resume message` as authoritative. Construct the message from validated, structured fields at send time. 4. Treat checkpoint data and prior session history as untrusted content, not agent instructions. 5. Use a fixed system-authored resume instruction and attach historical fields inside clearly delimited data sections. 6. Replace the keyword denylist with an allowlisted typed-action model. Free-form recovered instructions should require manual confirmation. 7. Bind recovery actions to the current session inventory and verify that each target session is expected before sending. 8. Add security tests covering embedded newlines, forged Markdown fields, duplicate fields, disclosure requests, tool-use instructions, Unicode obfuscation, and destructive-operation synonyms. ]]>
