T09 · Insecure Skill Coding Practices
- Location
index.js:52- Finding
Prompt Injection Through Untrusted Research Inputs
- Content
View full analysis
Vulnerability Details
File Location:
index.js, lines 52–113
Vulnerability Type: Untrusted input embedded directly into LLM instructions
Risk Level: MediumVulnerable Code
javascript async createPlan(topic, depth) { const prompt = `Create a research plan for: ${topic} Depth: ${depth} Include: 1. Key research questions 2. Search terms and queries 3. Types of sources to look for 4. Analysis framework Return structured plan.`; return await this.llm.generate(prompt); } async analyze(topic, sources) { const prompt = `Analyze these sources about: ${topic} Sources: ${sources.map(s => `- ${s.title}: ${s.summary}`).join('\n')} Provide: 1. Key findings 2. Consensus points 3. Conflicting information 4. Trends and patterns 5. Gaps in research`; return await this.llm.generate(prompt); } async generateReport(topic, analysis, sources) { const prompt = `Generate a comprehensive research report: Topic: ${topic} Analysis: ${analysis} Sources: ${sources.map(s => `${s.title} - ${s.url}`).join('\n')} Structure: 1. Executive Summary 2. Key Findings 3. Detailed Analysis 4. Methodology 5. Citations 6. Recommendations`; const content = await this.llm.generate(prompt);Technical Analysis
The
topicvalue originates from the caller ofresearch()and is inserted directly into prompts passed tothis.llm.generate(). It is not validated, length-limited, structurally separated from instructions, or explicitly marked as untrusted data.An attacker can therefore supply a topic containing instruction-like text that tells the model to ignore the surrounding research instructions, alter the requested output, fabricate findings, or suppress citations. The value reaches both
createPlan()andanalyze().The resulting
analysisis subsequently inserted into the report-generation prompt in the same unstructured manner. This creates a sec ...[truncated 2091 chars]- Remediation
View remediation
Remediation Suggestions
- Use an LLM API that supports separately typed system, developer, user, and data messages. Keep application instructions in a higher-trust message and place
topic, source content, and prior model output in clearly identified untrusted-data messages. - Enclose untrusted values in explicit delimiters and instruct the model that content inside those delimiters is data only and that any instructions contained within it must not be followed.
- Apply schema validation to research requests. Require
topicanddepthto be strings from expected formats, enforce conservative length limits, and reject control sequences or unsupported values. - Request structured output using a strict JSON schema and validate every response before passing it to the next stage.
- Do not feed unrestricted model output back into another instruction prompt. Parse the analysis into validated fields and pass only those fields to report generation.
- Treat source titles, summaries, URLs, and fetched web content as untrusted because indirect prompt injection can also originate from external documents.
- Apply least privilege to any tool-enabled LLM integration. Require explicit authorization for consequential operations and never permit model-generated text alone to trigger shell commands, file access, credential use, or external side effects.
- Add adversarial tests covering direct and second-order prompt injection, including attempts to override instructions, suppress citations, fabricate sources, and escape data delimiters.
- Use an LLM API that supports separately typed system, developer, user, and data messages. Keep application instructions in a higher-trust message and place
