T09 · Insecure Skill Coding Practices
- Location
src/analyzer.ts:36- Finding
Indirect Prompt Injection Through Untrusted Web Content
- Content
View full analysis
`[${i + 1}] ${a.title}\nURL: ${a.url}\n내용: ${a.content}` ).join('\n\n'); const systemPrompt = `트렌드 분석 전문가입니다. 주어진 뉴스 기사들을 분석하여 키워드의 트렌드 신호를 판단하십시오. 반드시 아래 JSON 형식으로만 응답하십시오. 다른 텍스트 없이 순수 JSON만 출력하십시오. 신호 정의: - Rising: 언급량/관심도가 빠르게 증가하는 중 - Peaking: 현재 최고조, 곧 하락 가능성 - Declining: 언급량/관심도가 줄어드는 중 - Insufficient_Data: 판단하기에 데이터가 부족함 응답 형식 (JSON 객체 하나): { "signal": "Rising | Peaking | Declining | Insufficient_Data", "score": 0~100 사이 정수, "reason": "판단 근거를 2문장으로 설명", "evidence": ["근거로 사용한 URL 1", "URL 2"] }`; const userMessage = `키워드: "${keyword}"\n분석 기간: ${timeframe}\n\n기사 목록:\n${articlesText}`; try { const raw = await callLLM(systemPrompt, userMessage); const cleaned = raw.replace(/```json|```/g, '').trim(); const parsed = JSON.parse(cleaned); results.push({ keyword, signal: parsed.signal ?? 'Insufficient_Data', score: typeof parsed.score === 'number' ? parsed.score : 0, reason: parsed.reason ?? '', evidence: Array.isArray(parsed.evidence) ? parsed.evidence : [], }); } ``` ### Technical Analysis Article titles, URLs, and content returned by Tavily are externally controlled data. They are concatenated directly into an LLM user message without explicit boundaries identifying them as untrusted content and without an instruction requiring the model to ignore commands embedded in the articles. An attacker can publish content containing instructions such as requests to disregard the trend-analysis task, return a fabricated classification, or insert attacker-selected evidence. If Tavily indexes and returns that content, the LLM may interpret those instructions as part of the conversation. The JSON response is parsed syntactically but not validated semantically. In ...[truncated 1841 chars]- Remediation
View remediation
