T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/fundamental.mjs:89
- Finding
- Untrusted Remote News Content Is Passed to the Agent Without an Explicit Trust Boundary<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fundamental.mjs:89-105`, `scripts/fundamental.mjs:267-278`, `scripts/analyze.mjs:196-200`, and `SKILL.md:41-43` **Vulnerability Type**: Indirect prompt-injection exposure through untrusted API content **Risk Level**: Medium ### Complete Code Snippet ```javascript async function fetchNews(symbol) { const s = String(symbol); const url = `https://search-api-web.eastmoney.com/search/jsonp?cb=¶m=%7B%22uid%22%3A%22%22%2C%22keyword%22%3A%22${s}%22%2C%22type%22%3A%5B%22cmsArticleWebOld%22%5D%2C%22client%22%3A%22web%22%2C%22clientType%22%3A%22web%22%2C%22clientVersion%22%3A%22curr%22%2C%22param%22%3A%7B%22cmsArticleWebOld%22%3A%7B%22searchScope%22%3A%22default%22%2C%22sort%22%3A%22default%22%2C%22pageIndex%22%3A1%2C%22pageSize%22%3A5%7D%7D%7D`; try { const response = await fetch(url); if (!response.ok) return []; const text = await response.text(); const json = text.replace(/^[^(]*\(/, '').replace(/\);?$/, ''); const data = JSON.parse(json); const articles = data.result?.cmsArticleWebOld || []; return articles.map(a => ({ title: a.title, date: a.date, url: a.url })); } catch { return []; } } ``` ```javascript export async function analyzeNewsSentiment(symbol) { const news = await fetchNews(symbol); const recentHeadlines = news.slice(0, 5).map(n => n.title).filter(Boolean); const positiveWords = ['涨', '盈利', '突破', '利好', '增长', '超预期', '上调', '创新高', '大涨', '买入', '领涨', '飙升']; const negativeWords = ['跌', '亏损', '下跌', '利空', '下滑', '不及预期', '下调', '创新低', '大跌', '卖出', '暴跌', '减持']; let score = 0; for (const title of recentHeadlines) { for (const w of positiveWords) if (title.includes(w)) score += 0.2; for (const w of negativeWords) if (title.includes(w)) score -= 0.2; } score = Math.max(-1, Math.min(1, score)); return { overall: score > 0.2 ? 'positive' : score < -0.2 ? 'negative' : ' ...[truncated 2248 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Explicitly document that every field received from external APIs is untrusted data and must never be interpreted as an instruction. 2. Add a Skill-level rule requiring the agent to use headlines only as quoted market data and to ignore requests, commands, URLs, or policy statements embedded in them. 3. Wrap remote text in a clearly delimited structure, such as an `untrustedExternalContent` field. 4. Normalize titles by removing control characters, invisible Unicode formatting characters, and excessive length. 5. Consider excluding raw headlines from the agent prompt when only a numeric sentiment score is needed. 6. Apply output-schema validation and enforce maximum lengths and expected primitive types for all remote fields. 7. Ensure the host agent requires independent user confirmation before performing consequential tool calls prompted by retrieved content. ]]>
