Back to skill

Security audit

中国官方经济资讯

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent Chinese economic-news aggregator, but its fallback script can present unauthenticated or spoofed links as official news.

Review before installing. The skill does not show local persistence or credential access, but its fallback script can weaken the reliability of official-source claims. Use it only if you are comfortable with web access to Chinese news sites and Bing, and treat generated links as unverified unless the script is fixed to require HTTPS, validate certificates, and check parsed hostnames against an exact allowlist.

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/fetch_news.py:78
Finding
TLS Certificate Verification Disabled for Official RSS Retrieval<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch_news.py:42, 78, 279-280` **Vulnerability Type**: Improper certificate validation and use of unencrypted HTTP **Risk Level**: Medium ### Vulnerable Code ```python RSS_FEEDS = [ {"name": "中国政府网·政策", "url": "https://www.gov.cn/zhengce/zuixin/ezine.xml", "icon": "🏛️", "category": "政策"}, {"name": "新华网·财经", "url": "http://www.news.cn/fortune/feed.xml", "icon": "📰", "category": "综合"}, ] ``` ```python resp = requests.get(feed["url"], headers=HEADERS, timeout=10, verify=False) ``` ```python if __name__ == "__main__": import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) ``` ### Technical Analysis The RSS retrieval function explicitly passes `verify=False` to `requests.get`. This disables validation of the remote server's TLS certificate, including certificate authority, hostname, and validity checks. Suppressing `InsecureRequestWarning` further prevents the operator from seeing that server authentication has been disabled. In addition, the Xinhua RSS endpoint is configured with plain HTTP. HTTP provides no cryptographic authentication or integrity protection. Consequently, both configurations permit a network-positioned attacker to alter an RSS response without possessing a valid certificate for the official domain. The parser trusts the returned XML and associates every parsed item with the configured official source: ```python articles.append({ "title": (title_el.text or "").strip(), "url": (link_el.text or "").strip(), "date": (pub_el.text or "").strip() if pub_el is not None else "", "source": feed["name"], "icon": feed["icon"], "category": feed["category"], }) ``` Although this does not provide direct local code execution, it breaks the authenticity guarantee claimed by the Skill and can cause attacker-controlled content to be presented as official economic news. ### Attack Path 1. A victim runs the fallb ...[truncated 1387 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `verify=False` and rely on the default certificate verification behavior: ```python resp = requests.get(feed["url"], headers=HEADERS, timeout=10) resp.raise_for_status() ``` 2. Replace the plain HTTP Xinhua feed with a verified HTTPS endpoint. If no HTTPS endpoint is available, do not treat that source as authenticated official content. 3. Remove global suppression of `InsecureRequestWarning` so that accidental insecure TLS use remains visible. 4. Validate the final response URL after redirects and require HTTPS: ```python from urllib.parse import urlsplit resp = requests.get(feed["url"], headers=HEADERS, timeout=10) resp.raise_for_status() final_url = urlsplit(resp.url) if final_url.scheme != "https": raise ValueError("RSS feed redirected to a non-HTTPS URL") ``` 5. Apply strict hostname allowlisting to both the configured feed URL and the final redirected URL. 6. Consider setting a maximum response size before XML parsing to reduce exposure to unexpectedly large network responses. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch_news.py:128
Finding
Official Source Allowlist Bypass Through URL Substring Matching<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch_news.py:128-137, 176-178` **Vulnerability Type**: Improper URL and hostname validation **Risk Level**: Medium ### Vulnerable Code ```python for site in sites: if site in href: if "gov.cn" in site: source_name, icon = "中国政府网", "🏛️" elif "news.cn" in site or "xinhua" in site: source_name, icon = "新华网", "📰" elif "people" in site: source_name, icon = "人民网", "📢" elif "stats" in site: source_name, icon = "国家统计局", "📊" elif "cctv" in site: source_name, icon = "央视财经", "📺" elif "ce.cn" in site: source_name, icon = "中国经济网", "📈" break ``` ```python # 过滤非官方域名 url = article.get("url", "") if url and not any(site in url for site in OFFICIAL_SITES): return True ``` ### Technical Analysis The script determines whether a URL belongs to an official source by searching for an allowlisted domain string anywhere in the complete URL. A substring match does not establish that the URL's parsed hostname is the allowlisted domain or one of its legitimate subdomains. Examples of attacker-controlled URLs that can satisfy the check include: ```text https://gov.cn.attacker.example/article https://attacker.example/news?source=stats.gov.cn https://attacker.example/people.com.cn/story https://evilce.cn/article ``` The first URL embeds an official domain as a subdomain label beneath an attacker-controlled registrable domain. The next two place an official domain in the path or query string. The final example demonstrates that the short `ce.cn` token may occur within an unrelated hostname. The same unsafe comparison is used for both security filtering and source attribution. Therefore, a crafted URL can survive the official-domain filter and may also receive the name and icon of a trusted media organization. The issue applies to entries parsed from RSS and to links extracted from Bing search HTML. Search-engine query restrictions do not constitute a s ...[truncated 1872 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse every URL and validate only its normalized hostname: ```python from urllib.parse import urlsplit def is_allowed_official_url(url, sites): try: parsed = urlsplit(url) host = (parsed.hostname or "").rstrip(".").lower() except ValueError: return False if parsed.scheme != "https" or not host: return False return any( host == domain or host.endswith("." + domain) for domain in sites ) ``` 2. Replace the current filtering condition with the strict helper: ```python url = article.get("url", "") if not url or not is_allowed_official_url(url, OFFICIAL_SITES): return True ``` 3. Use the parsed hostname for source attribution rather than searching the full URL: ```python host = (urlsplit(href).hostname or "").rstrip(".").lower() for site in sites: if host == site or host.endswith("." + site): # Assign the corresponding source. break ``` 4. Require HTTPS and reject malformed URLs, embedded credentials, unexpected ports, and hostnames that cannot be normalized safely. 5. Revalidate `response.url` after every HTTP redirect. An initially allowed URL can otherwise redirect to an attacker-controlled destination. 6. Keep source attribution and URL authorization in one shared function so that a link cannot be accepted under one rule and labeled under another. 7. Add regression tests covering exact domains, valid subdomains, lookalike domains, query-string injection, user-information confusion, trailing dots, mixed case, malformed URLs, and redirects. ]]>
Vulnerability Patterns
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill instructs use of network-capable tools such as web_search and web_fetch, and even a local script that fetches remote content, but it does not declare any explicit tool scope or allowed-tools boundary. This creates an authorization ambiguity where the runtime may permit broader network access than intended, increasing the risk of unintended external requests or misuse if the skill is triggered in the wrong context.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The trigger phrases are very broad and map to common finance and news queries such as '经济新闻', 'GDP', 'CPI', and '今日财经', so the skill may activate for many ordinary conversations not specifically requesting this skill. That overbroad activation can cause unintended web access, unexpected tool use, and result steering toward this skill when a user may have wanted a general answer instead.

Natural-Language Policy Violations

Medium
Confidence
85% confidence
Finding
The skill is entirely specified in Chinese and describes output behavior for Chinese economic news, but it does not explicitly let users choose another language for the response. Under the policy, forcing a specific language without opt-in can be a natural-language policy violation unless the locale restriction is clearly justified and documented.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
The natural-language description, CLI help text, and output are all hard-coded in Chinese and the search query logic is specific to the zh-CN/CN locale. There is no indication that users can opt into another language or locale, which conflicts with the policy against forcing a specific language without user choice.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
Disabling TLS certificate verification allows man-in-the-middle attackers to intercept and modify HTTPS RSS responses. In this skill's context, that could let an attacker inject fake news items or malicious links while the output still appears to come from trusted official sources.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
def fetch_rss(feed):
    """抓取 RSS 源"""
    try:
        resp = requests.get(feed["url"], headers=HEADERS, timeout=10, verify=False)
        resp.encoding = "utf-8"
        root = ET.fromstring(resp.text)
        articles = []
Confidence
99% confidence
Finding
Using verify=False is an unsafe default because it disables server identity verification for HTTPS connections. Since this skill markets content as authoritative economic news, tampered transport can directly undermine integrity and user trust by substituting attacker-controlled articles or links.

Description-Behavior Mismatch

Medium
Confidence
86% confidence
Finding
The manifest description says the skill fetches news only from specific official media outlets, which implies those outlets are the direct sources. In practice, the code queries cn.bing.com and extracts results from a search engine before filtering by official domains, so the aggregation pipeline depends on an unlisted third-party source rather than exclusively scraping the named media sites directly.

Intent-Code Divergence

Medium
Confidence
89% confidence
Finding
The search parsing code labels results as '官方媒体' before strict allowlist enforcement, and domain checking later relies on substring matching rather than robust hostname validation. An attacker could craft or surface deceptive URLs containing approved-domain strings and have them presented as authoritative, enabling phishing, misinformation, or unsafe link delivery under a trusted label.

Static analysis

No suspicious patterns detected.