T09 · Insecure Skill Coding Practices
- Location
references/dependency-tree.md:88- Finding
Untrusted Agent Output Is Injected into Downstream Prompts
- Content
View full analysis
Vulnerability Details
File Location:
references/dependency-tree.md:88-101
Additional Locations:SKILL.md:44-53,SKILL.md:74-84,references/fan-out.md:94-98,references/pipeline.md:19-34
Vulnerability Type: Indirect prompt injection through unsanitized orchestration results
Risk Level: MediumVulnerable Code
references/dependency-tree.md:88-101:python # Spawn ready tasks for task_name in ready: task = state["tasks"][task_name] # Build context from dependencies (fork pattern) dep_context = build_dependency_context(state, task["blockedBy"]) full_task = f"{task['task']}\n\nContext from prior work:\n{dep_context}" sessions_spawn(task=full_task, label=task_name) task["status"] = "running" save_state(state) time.sleep(30) update_running_status(state)references/pipeline.md:19-34:python stages = [ {"label": "stage-1-research", "task": "Research the topic: {topic}"}, {"label": "stage-2-analyze", "task": "Analyze this research and identify key themes:\n\n{prev_result}"}, {"label": "stage-3-write", "task": "Write a report based on this analysis:\n\n{prev_result}"}, ] prev_result = "" for i, stage in enumerate(stages): # Inject previous result into task task = stage["task"].format(topic=topic, prev_result=prev_result) # Spawn and wait sessions_spawn(task=task, label=stage["label"]) wait_for_completion(stage["label"]) # Extract result for next stage prev_result = get_agent_result(stage["label"])references/fan-out.md:94-98:text Phase 2 (Synthesis): └── Agent 6: Synthesize all findings (fork - receives all results)The synthesis agent gets all 5 research results injected into its context.
Technical Analysis
The documented dependency-tree, pipeline, and fan-out patterns place results produced by one agent directl ...[truncated 2722 chars]
- Remediation
View remediation
Remediation Suggestions
- Treat every upstream result as untrusted data, including output produced by another agent.
- Place inherited material in an explicit, clearly delimited data section and instruct the downstream agent that content inside that section is evidence only and must never override its task or system instructions.
- Prefer structured schemas with allow-listed fields over concatenating free-form results into prompts. Reject malformed or unexpected fields.
- Add an intermediate sanitization or constrained summarization stage that identifies and removes imperative instructions, tool requests, credential requests, and attempts to alter the downstream task.
- Preserve provenance for every result so the downstream agent can distinguish user instructions, orchestration instructions, agent conclusions, and externally sourced quotations.
- Minimize the tools and permissions available to synthesis and analysis agents. Use separate, least-privilege agents for any action that changes files, invokes external services, or accesses secrets.
- Require explicit human approval before sensitive downstream actions, including sending data externally, modifying important files, using credentials, or executing commands.
- Limit the size and content types of inherited results and avoid passing complete session histories when a validated summary is sufficient.
- Add adversarial tests in which upstream content contains prompt-injection instructions, ensuring downstream agents ignore those instructions and continue only the declared workflow.
- Record and surface suspicious inherited directives rather than executing them, allowing the orchestrator or a human reviewer to quarantine affected results.
