T09 · Insecure Skill Coding Practices
Error
- Location
- crypto-news-trader-index.js:128
- Finding
- Untrusted News Content Can Manipulate Automated Leveraged Trades<![CDATA[ ## Vulnerability Details **File Location**: `crypto-news-trader-index.js`, lines 128–140, 177–199, and 328–353 **Vulnerability Type**: Prompt injection through untrusted external content controlling a financial action **Risk Level**: High ### Vulnerable Code ```js formatForLLM(articles) { return articles .map( (a, i) => ` [Article ${i + 1}] Source: ${a.source} Author: ${a.author || "Unknown"} PublishedAt: ${new Date(a.publishedAt).toISOString()} Title: ${a.title || ""} Content: ${(a.content || a.description || "").slice(0, 700)} URL: ${a.url || ""} Engagement: likes=${a.likes || 0} retweets=${a.retweets || 0} replies=${a.replies || 0} `.trim() ) .join("\n\n---\n\n"); } ``` ```js async analyze(coin, formattedNews) { const prompt = SENTIMENT_ANALYSIS_PROMPT .replaceAll("{COIN}", coin) .replace("{NEWS_CONTENT}", formattedNews); const resp = await this.openai.chat.completions.create({ model: "gpt-4o", temperature: 0.1, max_tokens: 1200, response_format: { type: "json_object" }, messages: [ { role: "system", content: "Return strict JSON only. No markdown. No extra text." }, { role: "user", content: prompt } ] }); return JSON.parse(resp.choices[0].message.content); } ``` ```js const formatted = monitor.formatForLLM(articles); let analysis; try { analysis = await analyzer.analyze(coin, formatted); } catch (e) { console.error(`[Analyzer] Failed:`, e?.message || e); continue; } console.log(`[Analyzer]`, { sentiment: analysis.sentiment, confidence: analysis.confidence, signal_strength: analysis.signal_strength, action: analysis.recommended_action, summary: analysis.summary }); const signal = analyzer.getTradeSignal(analysis); if (!signal) { console.log(`[Decision] No trade.`); continue; } // Step 3 try { await trader.place(coin, signal.side, analysis); } catch (e) { console.error(`[Trade] Failed:`, e?.message || e); } ``` ### Technical ...[truncated 2928 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Treat all article content as untrusted data** - Clearly delimit article content using a structured format. - Add a system-level instruction that article text is evidence only and that instructions contained within it must never be followed. - Remove unnecessary article fields before sending data to the model. 2. **Detect and reject adversarial content** - Scan titles and content for instruction-like phrases, model directives, forged JSON, and attempts to override the prompt. - Quarantine suspicious articles instead of using them for automated trading. 3. **Apply strict output validation** - Validate the response with a JSON Schema. - Restrict `sentiment`, `signal_strength`, `recommended_action`, and `urgency` to documented enumerations. - Require `confidence` to be a finite number between zero and one. - Validate all score fields and reject missing or unexpected properties. 4. **Require independent corroboration** - Do not trade based on a single social-media post or article. - Require matching reports from multiple independent, approved sources. - Use deterministic source allowlists and assign lower trust to user-generated sources. 5. **Separate analysis from trade authorization** - Require human confirmation before placing a live order. - Alternatively, use a separate deterministic policy engine that considers the LLM response only as one non-authoritative input. - Provide a paper-trading mode as the default. 6. **Enforce exchange-side risk controls** - Use API credentials restricted to trading only, with withdrawals disabled. - Set maximum order size, daily loss, position, leverage, and order-frequency limits. - Verify that stop-loss and take-profit orders are accepted and active before considering the operation successful. ]]>
