Back to skill

Security audit

A Stock Watcher

Security checks for vulnerabilities and agentic risk

Overview

This stock-watching skill is mostly purpose-aligned, but it has Review-worthy issues around unauthenticated market data, local storage of portfolio data, and under-scoped notification helpers.

Review this skill before installing if you plan to use it for real investing. Treat its analysis as informational only, avoid entering sensitive portfolio details unless local plaintext storage is acceptable, and be cautious with notifications because message content can be sent to external DingTalk-style endpoints. Its market data is fetched over unauthenticated HTTP, so do not rely on it as an authoritative source for trading decisions.

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
a_stock_watcher.py:115
Finding
Financial Market Data Retrieved over Unauthenticated Plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `a_stock_watcher.py:115-142`, `a_stock_watcher.py:202-235`, `a_stock_watcher.py:293-311`, `historical_data.py:38-45`, `historical_data.py:114-120`, and `health_check.py:18-35` **Vulnerability Type**: Cleartext transmission and missing server authentication **Risk Level**: Medium ### Vulnerable Code #### `a_stock_watcher.py:115-142` ```python """ 接口文档:http://push2.eastmoney.com/api/qt/stock/get ... """ ... fields = "f43,f44,f45,f49,f50,f55,f57,f58,f169,f170" url = f"http://push2.eastmoney.com/api/qt/stock/get?secid={secid}&fields={fields}" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", "Referer": "https://quote.eastmoney.com/" } response = requests.get(url, headers=headers, timeout=5) data = response.json() ``` #### `a_stock_watcher.py:202-235` ```python """ 接口文档:http://qt.gtimg.cn/q=[市场代码] ... """ ... url = f"http://qt.gtimg.cn/q={tencent_code}" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", "Referer": "https://stockapp.finance.qq.com/" } response = requests.get(url, headers=headers, timeout=5) ``` #### `a_stock_watcher.py:293-311` ```python """ 接口文档:http://hq.sinajs.cn/list=[市场代码] """ ... url = f"http://hq.sinajs.cn/list={sina_code}" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" } response = requests.get(url, headers=headers, timeout=10) ``` #### `historical_data.py:38-45` ```python url = f"http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?param={tencent_code},day,,,60,qfq" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", "Referer": "https://stockapp.finance.qq.com/" } response = requests.get(url, headers=headers, timeout=10) ``` #### `historical_data.py:114-120` ```python url = f"http://money.finance.sina.com.cn/quotes_service/api/json_v2.php/CN_MarketData.getKLineData?symbol={sina_code}&scale=24 ...[truncated 3292 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace every market-data endpoint with an HTTPS endpoint whose certificate can be validated. 2. Remove a data source if it cannot provide HTTPS rather than silently falling back to plaintext HTTP. 3. Enforce HTTPS after redirects and reject any redirect that downgrades the connection to HTTP. 4. Call `response.raise_for_status()` before parsing a response. 5. Validate response schemas, field types, required fields, and plausible numeric ranges. 6. Cross-check security-sensitive alerts against at least two independent HTTPS sources before presenting them as confirmed. 7. Reject impossible values such as negative prices, malformed dates, or unreasonable percentage changes. 8. Distinguish stale, incomplete, and unverified data in reports rather than treating all successful parses as authoritative. 9. Add tests that verify all configured URLs use HTTPS and that downgrade redirects are rejected. 10. Invalidate existing cache entries after transport-security changes so previously unverified data is not reused. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
notification.py:17
Finding
Caller-Controlled DingTalk Webhook URL Enables Arbitrary Outbound HTTP Requests<![CDATA[ ## Vulnerability Details **File Location**: `notification.py:17-42` and `notification.py:56-87` **Vulnerability Type**: Server-Side Request Forgery and unintended data disclosure **Risk Level**: Medium ### Vulnerable Code #### `notification.py:17-42` ```python def send_dingtalk_webhook(message: str, webhook_url: str = None) -> bool: """ 通过钉钉机器人 Webhook 发送消息 """ if not webhook_url: print("[钉钉 Webhook] 未配置 Webhook URL") return False try: headers = {'Content-Type': 'application/json; charset=utf-8'} data = { "msgtype": "text", "text": { "content": message } } response = requests.post(webhook_url, headers=headers, json=data, timeout=10) result = response.json() ``` #### `notification.py:56-87` ```python def send_dingtalk_markdown(title: str, text: str, webhook_url: str = None, at_all: bool = False) -> bool: """ 发送钉钉 Markdown 消息 """ if not webhook_url: return False try: headers = {'Content-Type': 'application/json; charset=utf-8'} data = { "msgtype": "markdown", "markdown": { "title": title, "text": text }, "at": { "isAtAll": at_all } } response = requests.post(webhook_url, headers=headers, json=data, timeout=10) result = response.json() ``` ### Technical Analysis Both webhook functions send an outbound POST request to a URL supplied directly by the caller. The URL is not restricted to DingTalk domains and is not checked for: - An HTTPS scheme. - A permitted hostname or path. - Embedded credentials. - Loopback, private, link-local, multicast, or reserved IP addresses. - DNS rebinding. - Redirects to prohibited destinations. If an untrusted value can reach `webhook_url` through a future handler, API wrapper, configuratio ...[truncated 2212 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not accept webhook destinations from ordinary request or command input. 2. Load the webhook URL from trusted, access-controlled configuration or a secret manager. 3. Require the `https` scheme. 4. Allowlist the exact official DingTalk webhook hostname and expected path prefix. 5. Reject URLs containing embedded usernames or passwords. 6. Resolve the hostname and reject loopback, private, link-local, multicast, unspecified, and reserved IP ranges for both IPv4 and IPv6. 7. Repeat destination validation after DNS resolution and immediately before connecting to reduce DNS-rebinding risk. 8. Disable automatic redirects, or validate every redirect destination using the same rules. 9. Apply outbound firewall or proxy restrictions so the process cannot reach metadata services or unrelated internal networks. 10. Avoid logging complete webhook URLs because they may contain secret access tokens. 11. Limit the size and sensitivity of content sent through notification functions. 12. Return failure unless the response is from a validated DingTalk endpoint and matches the expected response schema. ]]>
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 (33)

Vague Triggers

Medium
Confidence
94% confidence
Finding
The trigger phrase "日报" is overly generic and can easily match ordinary user requests for a daily report unrelated to stock monitoring. In an agent environment, this can cause unintended skill activation, leading to confusing behavior, irrelevant financial outputs, or accidental access to portfolio-related features when the user meant something else.

Vague Triggers

Medium
Confidence
86% confidence
Finding
The phrase "风险评估" is ambiguous because it commonly refers to many domains such as health, insurance, cybersecurity, or compliance, not just investment profiling. This increases the chance that the skill intercepts unrelated requests and returns financial-risk questionnaire flows in the wrong context.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The triggers "投资组合" and especially "资产配置" are broad financial terms that may appear in many general conversations, educational queries, or enterprise contexts. Because this skill includes recommendation-style functionality, accidental activation could surface inappropriate investment guidance or portfolio outputs when the user's intent was broader or different.

Vague Triggers

Medium
Confidence
88% confidence
Finding
The trigger phrases are broad natural-language commands such as querying prices, setting holdings, and watch actions, but the document does not define invocation boundaries or disambiguation rules. In an agent setting, this can cause accidental skill activation during ordinary conversation, potentially leading to unintended external API calls, state changes, or monitoring actions without clear user intent.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The skill documents persistent holdings and automated monitoring features, but does not tell users that portfolio data may be stored or that market data requests may be sent to external providers. In a finance context, this creates privacy and consent risks because sensitive investment positions and behavior could be retained or transmitted without explicit notice.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
The top-level documentation presents the skill as an "A 股盯盘技能" and describes data sources in that A-share framing. However, the implementation in `get_stock_tencent` explicitly accepts `hk...` and `us...` symbols and labels them as Hong Kong and US markets, which is a direct contradiction of the stated scope rather than a mere omission.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The module description and all command formats are presented exclusively in Chinese, indicating the skill is designed to operate only in a specific language/locale. The file does not provide any user choice, fallback, or documented justification for this language restriction.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
With no manifest available, the strongest stated purpose comes from the file's own description and handler help text framing it as a stock-watching skill. The code imports and exposes additional capabilities such as daily reports, holdings management, risk profiling, valuation analysis, stop-loss/profit planning, and portfolio optimization, which materially exceed simple quote lookup and alerting.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The handler and help text require Chinese trigger phrases such as “查询”, “盯盘”, and “风险提示”, and no alternative language option is offered. This is a natural-language policy concern because it forces a specific language for interaction without user choice or an explicit documented constraint.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The script emits user-facing output entirely in Chinese, including the title and section headers, with no option for the user to select another language. This is a natural-language policy concern because it enforces a specific locale without opt-in or explanation.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The module persists sensitive investment data, including holdings and a notification identifier, to a predictable local JSON file in plaintext without any notice, access controls, or minimization. On a shared system or in an agent environment where workspace files may be exposed to other tools, users, logs, backups, or other tenants, this can leak private financial positions and identifiers.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The module’s natural-language documentation and all user-facing messages are hard-coded in Chinese, and the code explicitly configures Chinese font handling. There is no indication that the skill offers a language choice or that this locale restriction is justified as a region-specific tool, which can violate language/locale policy requirements.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The module title, descriptions, questions, and user-facing guidance are all written in Chinese, and there is no indication that users may choose another language or locale. This creates a natural-language locale constraint without opt-in, which matches the policy-violation category for language or locale restrictions.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The function and docstring present the feature as modern portfolio optimization, but the implementation explicitly ignores correlations and uses a simplistic inverse-volatility heuristic. In an investment-advice skill, this can materially misstate diversification and risk, leading users to make unsafe allocation decisions based on false analytical claims.

External Transmission

Medium
Category
Data Exfiltration
Content
}
        }
        
        response = requests.post(webhook_url, headers=headers, json=data, timeout=10)
        result = response.json()
        
        if result.get("errcode") == 0:
Confidence
80% 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
}
        }
        
        response = requests.post(webhook_url, headers=headers, json=data, timeout=10)
        result = response.json()
        
        if result.get("errcode") == 0:
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
This code performs an outbound HTTP POST to a DingTalk webhook containing the provided message content. Although there is success/failure logging, there is no warning or explanatory comment/docstring that this function transmits user-supplied data to an external service, which is the kind of safety-relevant disclosure required for network operations.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
This function sends title, markdown text, and mention settings to a remote webhook via HTTP POST. The implementation logs only failures and lacks any explicit warning in code comments, docstrings, or visible user disclosure that content is being transmitted off-system.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This file presents its interface, status messages, and reports exclusively in Chinese, including the module description and user-facing strings. Under the policy, forcing a specific language without opt-in or a documented regional constraint is a natural-language policy violation.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
This Python file contains module docstrings, class docstrings, and user-facing output in Chinese, with no indication that another language is supported or that the locale is configurable. Per the policy, forcing a specific language without user opt-in is a natural-language policy violation.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The README is entirely written in Chinese and all invocation examples and output formats assume Chinese input such as “查询 600036 行情” and Chinese-language responses. There is no indication that users may choose another language or that the locale restriction is optional, which creates a natural-language locale policy concern.

Natural-Language Policy Violations

Low
Confidence
79% confidence
Finding
SQP-3 适用于所有文件类型。该文件的标题、说明、命令示例与注释均仅提供中文,没有说明这是面向特定中文环境的技能,也未提供用户语言选择,存在语言/地区策略上的潜在限制。

Intent-Code Divergence

Low
Confidence
94% confidence
Finding
The document presents a working `StockAnalyzer` unified interface and shows `full_analysis('002892')` as available at L61-L69. However, the roadmap later says `统一分析接口封装` is still in progress at L183-L186, which directly conflicts with the earlier claim that this capability is already implemented.

Intent-Code Divergence

Low
Confidence
92% confidence
Finding
The API reference documents `analyzer.compare(['002892', '600036'])` as an available callable method at L227-L249. But the project status section lists `股票对比功能` as still in progress at L183-L186, so the documentation simultaneously says the feature exists and is not yet finished.

Intent-Code Divergence

Low
Confidence
98% confidence
Finding
The docstring says the function prioritizes Tencent first, then Eastmoney, then Sina, but elsewhere the file declares `DATA_SOURCES = ["eastmoney", "tencent", "sina"]` and multiple comments/documentation sections describe Eastmoney as the primary source. This creates conflicting intent/documentation about which upstream source is authoritative.

Static analysis

No suspicious patterns detected.