T09 · Insecure Skill Coding Practices
- Location
scripts/china_stock.py:506- Finding
Hardcoded Tushare API Token Transmitted Through a Plaintext Custom Endpoint
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This stock-data skill is mostly purpose-aligned, but it includes unsafe credential handling, insecure transport, overbroad setup guidance, and misleading data behavior that users should review before installing.
Install only in an isolated environment. Rotate or remove the embedded Tushare token before use, avoid the custom plaintext Tushare endpoint and CNINFO HTTP where HTTPS is available, do not run Chromium with --no-sandbox on trusted hosts, avoid proxy/IP-rotation evasion guidance, and treat generated briefing images as demo/static unless the data path is replaced with live verified sources.
scripts/china_stock.py:506Hardcoded Tushare API Token Transmitted Through a Plaintext Custom Endpoint
references/cninfo-pdf-extraction.md:18Instructions Disable the Chromium Security Sandbox for Remote Content
requirements.txt:4Unpinned Third-Party Dependencies Permit Unreviewed Supply-Chain Changes
scripts/china_stock.py:306CNINFO Queries and Announcement Links Use Plaintext HTTP
The description is broadly aligned with the code's main purpose: a China stock market multi-source data skill aggregating several providers. However, there are material mismatches. First, the code uses an additional undeclared source, CNINFO, for announcements. Second, RiceQuant is advertised as an integrated source, but the code only imports/authenticates it and reports status; there is no exposed RiceQuant data query feature. Third, the '8-source automatic fallback' claim is overstated: fallback exists for quote queries (TDX→Tencent→iFinD) and announcements (CNINFO→Tushare→AKShare), but not as a general unified 8-source downgrade mechanism. Finally, the docstring claims TDX supports tick-by-tick trades, but the visible code implements only quote and K-line retrieval, not transaction-level trade data. These are sufficient to flag a description-behavior mismatch.
The declared description presents a broad financial data access skill with many upstream integrations and automatic failover. The supplied code chunk instead is a visual report generator that renders a PNG briefing with preset text and numbers. Its only external interactions are local font discovery and writing an output image file. There is no evidence of real-time quote retrieval, order book access, K-line handling, valuation lookup, hot topic scraping, report/announcement fetching, iWencai search, or quant platform integration. This is a clear description-behavior mismatch, with the code serving a materially different purpose from the declared skill.
The declared description promises a broad China A-share integrated data source with multiple named providers and capabilities centered on stock market data retrieval and fallback across 8 sources. The supplied code instead mainly aggregates financial news from Eastmoney, Tonghuashun, and Sina, and supplements that with limited index data from TDX for a daily briefing. While TDX and Eastmoney appear, the implemented functionality is much narrower than declared: there is no comprehensive multi-source stock data layer, no valuation/fundamental metrics from Tencent, no 5档盘口, no K-line retrieval, no iWencai/JQData/Tushare/RiceQuant integrations, and no automatic 8-source degradation framework beyond simple TDX host rotation. This is a material description-behavior mismatch.
This is a clear description-behavior mismatch. The declared purpose describes a broad Chinese A-share market data aggregation skill using several named Chinese data vendors and services. The supplied code does none of that. Instead, it exclusively interfaces with SEC EDGAR for U.S. public-company filings and institutional holdings, exposing commands for search, 13F, and 10-K retrieval. The primary purpose, data sources, geographic/market focus, and capabilities are materially different from the declaration.
The declared description presents the skill as a broad China A-share integrated data-source connector spanning many vendors and data types. The supplied code chunk instead implements a focused monitoring utility: it checks current prices against thresholds and scans a watchlist for abnormal moves. While it likely relies on a quote abstraction from another module and may indirectly use some stock data providers, this code does not evidence the claimed primary purpose of multi-provider comprehensive data aggregation, nor the listed capabilities such as 5-level order book, K-line retrieval, reports/announcements, iWencai search, or quant platform integrations. The actual triggers/usage are CLI monitor commands, which materially differ from the declared capability framing.
The code embeds a live Tushare Pro API token directly in source, which exposes credentialed third-party access to anyone who can read the file and causes undisclosed outbound use of that account. Hard-coded secrets are routinely leaked via source control, logs, packaging, or redistribution and can be abused to consume quota, impersonate the account, or access paid data under the owner's identity.
A hard-coded API token in source is a real secret exposure and also means the skill silently uses a third-party account without requiring user configuration or consent. In a skill context that performs many network requests, this is especially risky because the credential may be redistributed widely and abused at scale.
The skill advertises capabilities that inherently require network, shell, environment-variable access, and likely local file writes, but it does not declare any explicit tool scope or permission boundaries. That creates an over-broad execution surface where a host agent may grant more access than users expect, increasing the risk of unintended command execution, credential exposure, or filesystem modification.
The trigger guidance is extremely broad, effectively allowing almost any A-share-related natural language input to activate a skill that can use shell, network, and credentials-backed third-party services. Over-broad invocation criteria increase the chance of accidental execution, unintended external data disclosure, and confusing tool selection in multi-skill environments.
The skill instructs users to configure multiple tokens, usernames, and passwords in environment variables or local files, but it does not clearly warn that queries and potentially sensitive watchlists or research terms will be sent to third-party services. In a credentialed, networked skill, lack of disclosure around secret handling and outbound data sharing can lead to credential misuse, privacy leakage, and unsafe deployment in shared environments.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
bash 示例:
curl -s "http://www.cninfo.com.cn/new/fulltextSearch/full" \
-H "User-Agent: Mozilla/5.0" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "searchkey=000001&pageNum=1&pageSize=5&sortName=pubdate&sortType=desc"
This markdown file contains end-user instructions exclusively in Chinese, including headings, steps, and warnings, but does not indicate that the skill is region-specific or that users may choose another language. That can violate a language/locale policy when a skill forces a specific language without user opt-in.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
## 问题
巨潮公告详情页中的 PDF 地址是 **动态生成 + 有时限** 的。直接构造 URL(如 `https://disc.static.szse.cn/download/...`)返回 404。通过静态 curl 抓取 HTML 也拿不到真实 PDF 链接(页面纯 JS 渲染)。
## 解决方案:用 Hermes browser 工具
The document goes beyond describing data retrieval and instructs users to patch Hermes browser tooling so environment variables are injected into subprocess execution. Modifying shared tool code and forcing browser launch flags expands the skill's operational scope and weakens platform safety boundaries, creating a path for broader tool manipulation than is necessary for fetching stock disclosures.
The document explicitly recommends using a proxy pool and rotating multiple IPs after an upstream service has temporarily banned the server IP. That is guidance for bypassing rate limits and access restrictions imposed by a third party, which creates legal, policy, and abuse risk and could encourage operators to continue prohibited scraping rather than reduce request volume or obtain authorized access.
The specific recommendation to use a proxy pool with multiple IP rotation normalizes evasion of upstream controls without any warning about terms-of-service violations, account suspension, network abuse, or possible legal consequences. In a stock-data aggregation skill, this is not necessary for legitimate function and increases the chance the skill will be used to continue scraping after a ban.
These protocol notes go beyond normal API usage and provide explicit anti-rate-limit, anti-blocking, host-rotation, jitter, and batching guidance intended to reduce detection and avoid IP bans. In a stock-data aggregation skill, this materially enables evasion of provider controls and could facilitate abusive scraping or unauthorized use of third-party infrastructure, especially because it recommends rotating among multiple verified servers to lower per-host detection.
Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.
global _LAST_TDX_TIME
elapsed = time.time() - _LAST_TDX_TIME
if elapsed < 0.5:
time.sleep(round(0.5 - elapsed + __import__('random').random() * 0.2, 3))
_LAST_TDX_TIME = time.time()
pass
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
at = IF.get("access_token","")
if not at: return {"errorcode":-9999,"errmsg":"未配置iFinD token"}
try:
r = requests.post(f"{IFIND_URL}/{ep}", headers={"Content-Type":"application/json","access_token":at}, json=params, timeout=30)
d = r.json()
if d.get("errorcode") in (-1010,-1300,-1302) and retry and IF.get("refresh_token"):
r2 = requests.post(f"{IFIND_URL}/get_access_token", headers={"Content-Type":"application/json","refresh_token":IF["refresh_token"]}, timeout=15)
The skill refreshes an iFinD access token and writes the updated credential back to disk in a predictable local file without any user-facing warning or protection. Persisting bearer tokens to plaintext config increases the chance of credential theft from source directories, backups, multi-user systems, or accidental inclusion in artifacts.
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
r = requests.post(f"{IFIND_URL}/{ep}", headers={"Content-Type":"application/json","access_token":at}, json=params, timeout=30)
d = r.json()
if d.get("errorcode") in (-1010,-1300,-1302) and retry and IF.get("refresh_token"):
r2 = requests.post(f"{IFIND_URL}/get_access_token", headers={"Content-Type":"application/json","refresh_token":IF["refresh_token"]}, timeout=15)
d2 = r2.json()
if d2.get("errorcode")==0:
IF["access_token"]=d2.get("access_token","")
The manifest advertises '8大来源自动降级' including JQData, Tushare Pro, and RiceQuant. In the code, smart fallback is only TDX → Tencent → iFinD, announcement fallback is CNINFO/Tushare/AKShare, and RiceQuant is merely initialized without any exposed data retrieval path. This overstates the implemented coverage and fallback behavior compared with actual operations.
The script is presented as generating a real-time A-share market briefing from live data sources, but it actually renders entirely hardcoded prices, market breadth, and headlines. In a financial-data skill, this is dangerous because users may rely on fabricated or stale market information for trading or reporting decisions while believing it is live and authoritative.
The module docstring and CLI description present the skill exclusively in Chinese and define it specifically as an A-share market briefing generator, with no indication that language choice is optional. Under the policy, forcing a specific language without user opt-in is a natural-language locale violation unless the constraint is explicitly documented and justified.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
if os.path.isfile(fp):
return fp
try:
r = subprocess.run(['fc-list', ':lang=zh'], capture_output=True, text=True, timeout=5)
for line in r.stdout.split('\n'):
path = line.split(':')[0].strip()
if path and os.path.isfile(path):
No suspicious patterns detected.