Back to skill

Security audit

ai-news

Security checks for vulnerabilities and agentic risk

Overview

This skill fetches daily news from a disclosed third-party API and does not show hidden persistence, credential access, local data collection, or destructive behavior.

Install only if you are comfortable with news queries being sent to api.cjiot.cc. Treat returned news content as untrusted, and prefer adding request timeouts, response size limits, status/content-type checks, and terminal-output sanitization before heavy use.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/get-daily.js:29
Finding
Unbounded Buffering of Remote API Responses<![CDATA[ ## Vulnerability Details **File Location**: `scripts/get-daily.js:29-35`; `scripts/get-article.js:35-41` **Vulnerability Type**: Unbounded response buffering and missing network resource limits **Risk Level**: Medium ### Vulnerable Code `scripts/get-daily.js:29-35`: ```js https.get(url, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { ``` `scripts/get-article.js:35-41`: ```js https.get(url, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { ``` ### Technical Analysis Both scripts accumulate the complete response from `api.cjiot.cc` in a JavaScript string before parsing it. They do not impose a maximum response size, configure a request timeout, inspect `Content-Length`, or abort slow and oversized responses. The use of HTTPS protects the connection against ordinary network modification when certificate validation succeeds, but it does not protect the client from a compromised, malicious, or malfunctioning API server. A server capable of returning an arbitrarily large response can cause the Node.js process to continue allocating memory until the response ends or the process reaches its memory limit. The scripts also do not reject unexpected HTTP status codes or content types before buffering the body. Consequently, large error pages and other non-JSON responses are subject to the same unbounded buffering behavior. ### Attack Path 1. An attacker compromises the configured API service, its hosting environment, or another trusted component capable of controlling its HTTPS responses. 2. A user invokes `get-daily.js` or `get-article.js`. 3. The controlled endpoint returns a very large response, or sends data continuously without completing the response. 4. Each incoming chunk is appended to the `data` string. 5. Memory and connection resources continue to be consumed until the process is terminated, the host ...[truncated 598 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce a strict maximum response size while processing chunks. Track received bytes and call `request.destroy()` or `res.destroy()` immediately when the limit is exceeded. 2. Configure a short connection and response timeout with `request.setTimeout()`. 3. Validate `res.statusCode` before reading the complete response and reject unexpected redirects or error responses. 4. Validate that the response `Content-Type` is an expected JSON media type. 5. Inspect `Content-Length` when present and reject responses that exceed the configured limit. Continue enforcing the streaming byte limit because this header can be absent or inaccurate. 6. Handle aborted responses and stream errors explicitly. 7. Consider parsing through a bounded stream if responses can legitimately become large. Example hardening pattern: ```js const MAX_RESPONSE_BYTES = 2 * 1024 * 1024; const request = https.get(url, (res) => { if (res.statusCode !== 200) { res.resume(); console.error(`Unexpected HTTP status: ${res.statusCode}`); process.exitCode = 1; return; } const contentType = res.headers['content-type'] || ''; if (!contentType.includes('application/json')) { res.resume(); console.error('Unexpected response content type'); process.exitCode = 1; return; } let received = 0; let data = ''; res.on('data', (chunk) => { received += chunk.length; if (received > MAX_RESPONSE_BYTES) { res.destroy(new Error('API response exceeds the size limit')); return; } data += chunk; }); res.on('error', (error) => { console.error(`Response failed: ${error.message}`); }); res.on('end', () => { // Parse the bounded response. }); }); request.setTimeout(10_000, () => { request.destroy(new Error('API request timed out')); }); ``` ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/get-daily.js:53
Finding
Terminal Control-Sequence Injection Through Untrusted News Content<![CDATA[ ## Vulnerability Details **File Location**: `scripts/get-daily.js:53-64`; `scripts/get-article.js:50-72` **Vulnerability Type**: Unsanitized terminal output **Risk Level**: Low ### Vulnerable Code `scripts/get-daily.js:53-64`: ```js sortedArticles.forEach((article, index) => { const rank = index + 1; const heat = article.heat.toFixed(0); const title = article.title; const summary = article.summary ? (article.summary.length > 50 ? article.summary.substring(0, 50) + '...' : article.summary) : '无摘要'; console.log(`\n${rank}. 🔥${heat} ${title}`); console.log(` ${summary}`); console.log(` [ID: ${article.article_id}]`); }); ``` `scripts/get-article.js:50-72`: ```js console.log('\n' + '═'.repeat(60)); console.log(`\n📄 ${article.title}\n`); console.log('─'.repeat(60)); console.log(`📁 分类:${article.category_name || '未知'}`); console.log(`🔥 热度:${article.heat}`); console.log(`🕐 发布时间:${article.publish_time || article.created_at}`); console.log('─'.repeat(60)); if (article.summary) { console.log('\n📝 新闻摘要:\n'); console.log(article.summary); } if (content.story) { console.log('\n📖 详细内容:\n'); console.log(stripHtml(content.story)); } if (content.impact) { console.log('\n💡 影响分析:\n'); console.log(stripHtml(content.impact)); } ``` The HTML conversion routine does not remove terminal control sequences: ```js function stripHtml(html) { if (!html) return ''; return html .replace(/<p>/g, '\n') .replace(/<\/p>/g, '') .replace(/<br>/g, '\n') .replace(/<br\/>/g, '\n') .replace(/<strong>/g, '**') .replace(/<\/strong>/g, '**') .replace(/<[^>]*>/g, '') .trim(); } ``` ### Technical Analysis Titles, summaries, article metadata, story text, and i ...[truncated 2067 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Sanitize every API-derived value before writing it to an interactive terminal, not only HTML content. 2. Remove ANSI CSI sequences, OSC sequences, C0 control characters, and carriage returns while preserving expected newlines and tabs where necessary. 3. Use a maintained terminal-string sanitization package from a trusted, pinned source if dependencies are acceptable. 4. Validate API response fields against an explicit schema. Require expected primitive types and reject malformed records. 5. Offer a structured JSON output mode for machine consumers so terminal formatting is not mixed with untrusted data. 6. Avoid treating HTML stripping as a substitute for output-context sanitization. A local defensive helper could be applied to all API-derived output: ```js function sanitizeTerminal(value) { return String(value ?? '') // Remove OSC sequences. .replace(/\x1B\][^\x07]*(?:\x07|\x1B\\)/g, '') // Remove CSI and related ANSI sequences. .replace(/\x1B(?:[@-_]|\[[0-?]*[ -/]*[@-~])/g, '') // Remove remaining control characters except newline and tab. .replace(/[\x00-\x08\x0B-\x1F\x7F]/g, ''); } ``` All external fields should then be sanitized before interpolation or output: ```js console.log(`\n${rank}. ${sanitizeTerminal(title)}`); console.log(` ${sanitizeTerminal(summary)}`); console.log(sanitizeTerminal(stripHtml(content.story))); ``` The sanitizer should be tested against CSI color and cursor sequences, OSC hyperlinks and title changes, carriage-return overwrites, malformed escape sequences, and ordinary Unicode news content. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (13)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
代码的核心功能与“每日新闻获取/按日期查询”基本一致:它调用每日新闻 API,支持可选日期参数,并输出新闻摘要列表。因此主目的大体匹配。但声明还包括“新闻详情阅读”和“热点新闻排行”。在实际代码中,没有对单篇新闻详情进行任何请求或展示,只是提示用户可用另一个未提供的脚本 get-article.js 查看详情;因此该能力并未在当前代码块中实现。另外,所谓“热点新闻排行”仅表现为对当天文章列表按 heat 本地排序输出,和通常意义上的独立热点排行榜能力存在差距。故应判定为描述与实际行为存在部分不匹配。

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill sends requests to an external API but does not clearly disclose that user-supplied parameters or derived query data will be transmitted to a third party. This creates a privacy and data-handling risk, especially when user requests may contain dates, preferences, or conversational context that should not leave the platform without notice.

External Transmission

Medium
Category
Data Exfiltration
Content
**接口地址:**
```
https://api.cjiot.cc/api/v1/daily?date={YYYY-MM-DD}
```

**参数说明:**
Confidence
89% confidence
Finding
This skill relies on a third-party endpoint for news retrieval, which means user-request-derived data is transmitted خارج the local environment. The danger is contextual rather than inherently malicious: external requests expand the trust boundary and create privacy, availability, and supply-chain risk if the API is compromised, logs requests, or serves manipulated content.

External Transmission

Medium
Category
Data Exfiltration
Content
**接口地址:**
```
https://api.cjiot.cc/api/v1/articles/{article_id}
```

**参数说明:**
Confidence
89% confidence
Finding
Fetching article details from a third-party API transmits request metadata and depends on untrusted remote content. Because the response includes HTML-rich fields, the external trust boundary is more significant: malicious or malformed content could propagate into downstream rendering if not safely handled.

Vague Triggers

Medium
Confidence
96% confidence
Finding
The trigger conditions are broad and include common words such as “新闻”, “日报”, and “头条”, which can cause the skill to activate on unrelated user messages. In a system with tool execution, this can lead to unintended outbound API calls and unnecessary disclosure of user intent or query context to a third party.

External Transmission

Medium
Category
Data Exfiltration
Content
**处理步骤:**
1. 获取当前日期(格式:YYYY-MM-DD)
2. 调用 API:`curl -s "https://api.cjiot.cc/api/v1/daily?date={当前日期}"`
3. 解析返回的新闻列表
4. 按热度排序展示前 10 条新闻摘要
Confidence
88% confidence
Finding
The documented curl-based workflow performs a network call to an external service whenever the skill is triggered for daily news. In combination with broad triggers, this raises the chance of unintended data transmission and creates dependence on a remote service that could be unavailable, monitored, or manipulated.

External Transmission

Medium
Category
Data Exfiltration
Content
**处理步骤:**
1. 解析用户输入的日期
2. 调用 API:`curl -s "https://api.cjiot.cc/api/v1/daily?date={日期}"`
3. 解析并展示新闻列表

**回复模板:**
Confidence
88% confidence
Finding
The date-query flow sends user-request-derived parameters to an external API without any stated privacy or minimization controls. Even though the transmitted parameter is limited, it still expands the trust boundary and can leak user behavior patterns or conversation-derived details through repeated queries.

External Transmission

Medium
Category
Data Exfiltration
Content
**处理步骤:**
1. 从上下文获取当前新闻列表
2. 提取用户指定的文章 ID
3. 调用 API:`curl -s "https://api.cjiot.cc/api/v1/articles/{article_id}"`
4. 解析并展示新闻详情(标题、分类、热度、正文)

**回复模板:**
Confidence
90% confidence
Finding
The article-detail flow makes an external request based on context-selected article IDs and then displays remote content. This is moderately risky because it combines third-party transmission with rendering of untrusted content, which could expose users to misleading or unsafe HTML/content if not normalized before presentation.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
This file contains natural-language strings that force a specific language for instructions and runtime messaging. Under the policy, language constraints should either offer user opt-in/choice or be clearly justified as region-specific.

External Transmission

Medium
Category
Data Exfiltration
Content
process.exit(1);
  }

  const url = `https://api.cjiot.cc/api/v1/daily?date=${date}`;

  https.get(url, (res) => {
    let data = '';
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
process.exit(1);
  }

  const url = `https://api.cjiot.cc/api/v1/daily?date=${date}`;

  https.get(url, (res) => {
    let data = '';
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Low
Confidence
72% confidence
Finding
文件中的名称说明、触发示例、回复模板和操作说明均固定为中文,没有说明这是面向特定中文用户群体的受限技能,也未提供用户选择语言的方式。按自然语言政策要求,强制单一语言而无用户选择或合理限定,可能构成语言/locale 约束问题。

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The file’s docstring and runtime messages are written only in Chinese, which imposes a specific language on users without offering any choice or opt-in. This matches the language/locale policy violation category because the skill does not document a justified region-specific constraint.

Static analysis

No suspicious patterns detected.