T09 · Insecure Skill Coding Practices
- Location
scripts/fetch_articles.py:118- Finding
TLS Certificate Verification Is Explicitly Disabled for Authenticated API Requests
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill has a coherent article-lookup purpose, but it handles the API key and generated reports in ways that could expose credentials or unsafe web content, so it needs review before installation.
Install only if you trust the RedFox API integration and can accept local report generation. Before using it with a real API key, the publisher should restore normal TLS verification, escape and validate all article fields and URLs before Markdown/HTML output, avoid mandatory verbatim display of remote data, and make HTML/PDF generation and subscription behavior explicit and user-controlled.
scripts/fetch_articles.py:118TLS Certificate Verification Is Explicitly Disabled for Authenticated API Requests
scripts/generate_hot_html.py:34Untrusted API Fields Are Embedded into HTML Without Escaping
scripts/generate_hot_html.py:132Generated Reports Execute a Mutable Third-Party CDN Script Without Integrity Protection
SKILL.md:138Skill Instructions Require Unsanitized Remote Output to Bypass Agent Review
This is a real security issue, though the root cause is not merely that an environment-derived value is sent over the network. The dangerous behavior is that HTTPS certificate and hostname verification are explicitly disabled before sending a request that includes the API key in the X-API-KEY header. An attacker able to intercept traffic could perform a man-in-the-middle attack, capture the credential, and tamper with article data returned to the script.
ssl_ctx.verify_mode = ssl.CERT_NONE
try:
with urllib.request.urlopen(req, context=ssl_ctx, timeout=timeout) as resp:
result = json.loads(resp.read().decode("utf-8"))
except urllib.error.HTTPError as e:
raise Exception(f"HTTP请求失败: {e.code}, {e.read().decode('utf-8', errors='replace')}")
Line L049 explicitly states 'Describe what you need in plain language — no fixed commands to memorize,' which broadens activation beyond a clearly bounded set of phrases. Although examples follow, the description does not define clear trigger constraints or exclusions, increasing the risk of unintended invocation from everyday speech.
The quick phrase reference includes phrases that are partly generic and could overlap with ordinary requests, especially 'viral recommendations.' The README does not pair these examples with negative examples or explicit boundaries showing when the skill should not activate.
The README instructs users to invoke the skill with unrestricted natural language, which increases the chance of accidental or overly broad activation from ordinary conversation. In a conversational system, this can cause the skill to trigger without clear user intent and perform external data retrieval or subscription-related actions unexpectedly.
The example phrases are common everyday requests like '最新原创爆文' or '爆文推荐', which are broad enough to overlap with normal chat and increase accidental invocation risk. Because the skill can fetch external content and steer users into subscription flows, ambiguous triggers can lead to unintended actions or confusing context switches.
The skill directs the agent to use environment variables, read and write local files, and make outbound network requests, but it does not declare any explicit tool scope or permissions. This weakens least-privilege controls and can allow broader-than-expected access if the runtime permits those capabilities by default, especially because the skill also instructs automatic file generation and external API access.
The trigger phrases are broad and include common terms like 'latest' and 'recent', which can cause the skill to activate for general content requests not specifically asking for this capability. Unintended activation can lead to unnecessary external API calls, unexpected disclosure of fetched content, or subscription-oriented follow-up behavior the user did not explicitly request.
L140-L146 明确要求智能体必须原样展示脚本 stdout,且不得省略、修改、重新格式化。但 L148-L176 又规定了固定的 Markdown 表格、说明文案和展示模板,这意味着智能体需要对脚本输出进行再组织或格式化。该文档内部对技能应如何实际输出存在直接冲突,属于意图与实际执行要求不一致。
The skill instructs automatic HTML generation and opening after outputting article data, but it does not require clear user consent for creating local files or launching/opening content. Silent file creation and auto-open side effects can surprise users, overwrite files, or expose them to locally rendered active content, especially since the HTML is built from externally sourced article data.
The entire skill reference is written only in Chinese and all example user inputs and category names assume Chinese-language interaction, with no indication that users may choose another language or locale. Under the policy, forcing a specific language without user opt-in can be a natural-language policy violation unless the locale restriction is explicitly documented and justified.
This markdown file defines activation/matching keywords using very broad everyday terms such as “知识”, “生活”, “娱乐”, “工作”, “学习”, “全部”, and “所有分类”. The matching rules at L35-L37 then allow keyword-based invocation without documenting exclusions or negative examples, which can cause ordinary user requests to be mapped to categories unexpectedly.
The file’s user-facing documentation and runtime output are entirely in Chinese, and the skill does not indicate that this locale restriction is intentional or configurable. Per the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is explicitly justified.
The function is explicitly documented and implemented to use HTTPS with certificate verification disabled. In this skill, the request carries an API key and trusts remote JSON content, so bypassing TLS verification enables interception, credential theft, and response tampering by a network attacker. The skill context makes this more dangerous because it is a network-fetching integration handling authenticated requests.
def fetch_articles_api(url: str, params: dict, api_key: str, timeout: int = 30) -> dict:
"""
使用原生 urllib.request 发 HTTPS POST 请求(verify=False)
Args:
url: API 地址
L368 的提示写明“输出生成HTML榜单页面,表格内容支持导出 PDF 格式,自动生成并打开”,这描述了文件生成与自动打开的行为。但当前文件中并无任何 HTML 生成、PDF 导出或打开本地文件/浏览器的实现,文案与实际代码行为直接矛盾。
技能描述强调持续收录并向用户提供/推送公众号原创热门文章,按该表述更像是查询与展示能力。这里代码在本地额外持久化完整文章列表到 temp_file,属于数据落盘行为,清单描述中并未体现这一存储副作用,也不是向用户展示榜单所必需的显式能力。
This code file embeds a fixed lang="zh-CN" locale and throughout the generated page presents only Chinese UI text, effectively forcing a specific language experience. Under the policy, language/locale constraints should either be optional for users or clearly justified as region-specific, which is not present here.
The script writes fetched data to a user-controlled path without any safety guardrails or explicit warning. In an agent/skill setting, hidden file-write side effects are more dangerous because they can overwrite arbitrary writable files, leak data into unexpected locations, or leave residual local artifacts contrary to a read-only user expectation. The impact is limited here because the content is article data rather than credentials, but arbitrary path writes are still a real risk.
Detected: suspicious.insecure_tls_verification