T01 · Skill Instruction Hijacking
- Location
runtime/scripts/drift-context.sh:108- Finding
Repository-controlled specification text is injected into the agent instruction context
- Content
View full analysis
Vulnerability Details
File Location:
runtime/scripts/drift-context.sh:108-150, 203-238; secondary instance inruntime/scripts/post-check.sh:92-127
Vulnerability Type: Prompt injection through untrusted hook context
Risk Level: MediumTechnical Analysis
The optional Claude Code hooks read free-form Markdown sections from repository-controlled specification files and place their contents directly into the agent's
additionalContext.Relevant code from
runtime/scripts/drift-context.sh:bash for spec in "$dir"/CONCEPT.md "$dir"/PIPELINE.md "$dir"/SYNCS.md; do if [ -f "$spec" ]; then relative_spec="${spec#"$PROJECT_DIR"/}" found_specs="${found_specs:+$found_specs, }${relative_spec}" purpose=$(extract_section_ci "$spec" "purpose") if [ -n "$purpose" ]; then spec_context="${spec_context} - ${relative_spec}: ${purpose} " else spec_context="${spec_context} - ${relative_spec} " fi case "$spec" in *CONCEPT*) found_concept=true interactions=$(extract_section_ci "$spec" "interactions") if [ -n "$interactions" ]; then boundary_context="${boundary_context} [${relative_spec} ## interactions] ${interactions} " fi dependencies=$(extract_section_ci "$spec" "dependencies") if [ -n "$dependencies" ]; then boundary_context="${boundary_context} [${relative_spec} ## dependencies] ${dependencies} " fi if [ -z "$interactions" ] && [ -z "$dependencies" ]; then boundary_context="${boundary_context} [${relative_spec}: no boundary declarations found] " fi ;; *PIPELINE*) data_boundary=$(extract_section_ci "$spec" "data boundary") if [ -n "$data_boundary" ]; then boundary_context="${boundary_context} [${relative_spec} ## data boundary] ${data_boundary} " fi ;; esac fi doneThe resulting text is emitted through an instruction-bearing hook fi ...[truncated 4669 chars]
- Remediation
View remediation
Remediation Suggestions
- Treat all extracted specification content as untrusted data. Surround it with strong, unambiguous delimiters and explicitly instruct the model that text inside the delimiters is reference data and must never be followed as instructions.
- Replace free-form section injection with a constrained parser and allowlisted schema. For example, accept only normalized module identifiers, dependency identifiers, and structured boundary values rather than arbitrary Markdown paragraphs.
- Reject or neutralize content that contains unexpected headings, role-like directives, tool requests, or other imperative instruction patterns. This should supplement, not replace, structural parsing.
- Apply strict length and line-count limits to each injected field to reduce the ability to bury or amplify hostile instructions.
- Separate trusted hook guidance from repository content in the generated message. Place fixed security guidance first and clearly label repository-derived values with their source file and section.
- Apply the same protections to both
drift-context.shandpost-check.sh; otherwise, the post-edit hook remains an alternate injection path. - Where supported by the hook API, place repository-derived values in a data-only field rather than an instruction-bearing context channel.
- Add regression tests containing adversarial specification text and verify that it is represented only as inert quoted data rather than interpreted as hook instructions.
