T09 · Insecure Skill Coding Practices
Warning
- Location
- news_aggregator.py:171
- Finding
- Untrusted news content is incorporated into an instruction-bearing AI prompt<![CDATA[ ## Vulnerability Details **File Location**: `news_aggregator.py:171-198` **Vulnerability Type**: Indirect prompt injection through external content **Risk Level**: Medium ### Vulnerable Code ```python item_lines = [ f"{i}. Title: {it.get('title','')}\n Source: {it.get('source','')}\n URL: {it.get('url','')}" for i, it in enumerate(items, 1) ] prompt = ( f"You are a news editor. The date is {today}.\n\n" f"Here are the top stories about \"{topic}\" from {period} ({len(items)} items):\n\n" + "\n".join(item_lines) + "\n\nComplete two tasks — output plain text only (no JSON, no extra commentary):\n\n" "## Task 1: Overview\n" "Write a 150-200 word editorial paragraph summarising the most important developments.\n" "- Natural journalistic prose, no bullet points or lists\n" "- Embed the most important story titles as Markdown hyperlinks: [keyword](url)\n" "- Highlight connections between stories and the overall trend\n\n" "## Task 2: Worth Reading\n" "Pick the 3 most worth-reading items. One sentence each explaining why:\n" "🔖 [Title](url) — reason\n\n" "Output only these two sections." ) try: print(f" [AI] Using provider={provider} model={model or PROVIDER_DEFAULTS.get(provider, '')}") editorial = call_ai(prompt, provider, model) except Exception as exc: print(f" [AI:{provider}] Editorial failed: {exc}") editorial = "\n".join( f"• [{it.get('title','')}]({it.get('url','')})" for it in items[:10] ) ``` ### Technical Analysis Article titles, source names, URLs, tweets, and other metadata obtained from RSS, Tavily, Twitter, and YouTube are externally controlled. The code concatenates these fields directly into the same user message that contains instructions for the AI model. There is no structured separation between trusted application instructions and untrusted source content. There is also no explicit instruction telling the model to treat embedded instructi ...[truncated 1770 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Place external records in a clearly delimited data section and identify every field as untrusted. 2. Use a trusted system message for the editorial policy and keep source data in a separate user message or structured payload. 3. Explicitly instruct the model not to execute, repeat, or follow instructions found inside titles, source names, URLs, tweets, or other retrieved content. 4. Normalize and validate URLs before including them in prompts or Discord messages. Permit only expected `https` or `http` schemes. 5. Escape Discord Markdown in externally supplied titles and source names. 6. Disable Discord mentions by including an `allowed_mentions` policy: ```python payload = { "content": header + chunk, "allowed_mentions": {"parse": []}, } ``` 7. Apply output validation before posting. Reject unexpected link schemes, suspicious mass mentions, and links whose displayed text or host differs from the validated source record. 8. Consider producing a deterministic list of validated links separately from AI-generated prose so that the model cannot introduce arbitrary destinations. ]]>
