Back to skill

Security audit

A Stock Monitor 1.1.2

Security checks for vulnerabilities and agentic risk

Overview

The skill is a plausible A-share stock monitor, but its bundled web app is unsafe to expose because it ships with public admin credentials, a fixed session secret, and debug mode on all network interfaces.

Treat this as a Review item. Do not expose the Flask app to any network until you replace all default accounts, generate a unique SECRET_KEY from an environment variable, disable debug mode, bind to localhost or put it behind real authentication, and verify user persistence works. Review cron jobs and local database paths before enabling automation, and do not rely on its market recommendations without independent validation.

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 (6)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/web_app.py:16
Finding
Authentication Bypass Through a Publicly Known Flask Session-Signing Key<![CDATA[ ## Vulnerability Details **File Location**: `scripts/web_app.py:16-18` **Vulnerability Type**: Hard-coded cryptographic secret enabling session forgery **Risk Level**: Critical ### Complete Code Snippet ```python app = Flask(__name__) app.config['JSON_AS_ASCII'] = False app.config['SECRET_KEY'] = 'your-secret-key-change-this-in-production' # 生产环境请修改 ``` The forged user identifier is resolved through the following loader: ```python @login_manager.user_loader def load_user(user_id): for username, data in USERS.items(): if data['id'] == int(user_id): return User(user_id, username, data.get('role', 'viewer')) return None ``` The administrator has user ID `1`: ```python USERS = { 'admin': { 'password': hashlib.sha256('admin123'.encode()).hexdigest(), 'id': 1, 'role': 'admin' }, ``` ### Technical Analysis Flask uses `SECRET_KEY` to authenticate session cookies. The value is a fixed string committed to the public source code and is therefore not secret. Flask-Login stores the authenticated user identifier in the Flask session and uses `load_user()` to recover the corresponding account. An attacker who knows the signing key can create a valid Flask session containing the administrator's user identifier. Because user ID `1` maps to the `admin` account, the server will accept the forged cookie as an authenticated administrator session without requiring the administrator password. The application does not rotate the key, retrieve it from a protected secret store, or reject startup when the placeholder value remains configured. ### Attack Path 1. The attacker obtains the source code or otherwise learns the fixed Flask secret. 2. The attacker confirms that the Flask service is reachable on TCP port 5000. 3. The attacker constructs a Flask-compatible signed session containing Flask-Login's user identifier for account ID `1`. 4. The attacker sends the forged session cookie to the application. 5. ...[truncated 814 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the secret from source control. 2. Generate at least 32 random bytes using a cryptographically secure generator. 3. Load the secret from a protected environment variable or secret-management service: ```python import os secret_key = os.environ.get("FLASK_SECRET_KEY") if not secret_key or secret_key == "your-secret-key-change-this-in-production": raise RuntimeError("A unique FLASK_SECRET_KEY must be configured") app.config["SECRET_KEY"] = secret_key ``` 4. Use a different secret for every deployment environment. 5. Rotate the exposed key immediately and invalidate all existing sessions. 6. Configure secure cookie properties: ```python app.config.update( SESSION_COOKIE_SECURE=True, SESSION_COOKIE_HTTPONLY=True, SESSION_COOKIE_SAMESITE="Lax", ) ``` 7. Add automated deployment checks that reject known placeholder or low-entropy secrets. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/web_app.py:77
Finding
Remote Administrator Compromise Through Fixed Default Credentials<![CDATA[ ## Vulnerability Details **File Location**: `scripts/web_app.py:77-92` **Vulnerability Type**: Hard-coded default accounts and passwords **Risk Level**: Critical ### Complete Code Snippet ```python # 用户数据(生产环境应该存储在数据库) USERS = { 'admin': { 'password': hashlib.sha256('admin123'.encode()).hexdigest(), # 默认密码: admin123 'id': 1, 'role': 'admin' }, 'developer': { 'password': hashlib.sha256('dev123'.encode()).hexdigest(), # 默认密码: dev123 'id': 2, 'role': 'developer' }, 'viewer': { 'password': hashlib.sha256('view123'.encode()).hexdigest(), # 默认密码: view123 'id': 3, 'role': 'viewer' } } ``` The credentials are also printed when the service starts: ```python print(""" ... ║ 默认账号: admin / admin123 ║ ... """) ``` Password changes are saved to a file: ```python def save_users(): """保存用户到配置文件""" import os config_file = os.path.join(os.path.dirname(__file__), 'users.json') with open(config_file, 'w', encoding='utf-8') as f: json.dump(USERS, f, ensure_ascii=False, indent=2) ``` However, the reviewed startup path only calls `load_watchlist()` and does not load `users.json`, causing the in-memory accounts to be recreated from the fixed source definitions after a restart. ### Technical Analysis The application ships with predictable credentials for all three roles, including the highest-privilege administrator role. The administrator credentials are present in source code and printed to standard output. No first-run enrollment process forces the operator to replace these credentials before the service becomes available. In addition, while changed passwords are written to `users.json`, the inspected startup logic does not reload that file. Consequently, a restart restores the source-defined passwords, undermining password changes made through the API. Because the service binds to all network interfaces, the ...[truncated 1206 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all fixed accounts and passwords from source code. 2. Implement a first-run administrator enrollment flow using a one-time, expiring bootstrap token. 3. Refuse to accept network traffic until enrollment is complete. 4. Require a unique, strong administrator password and prohibit known default values. 5. Store users in a properly protected database and load the persisted records at startup. 6. Restrict the user database file to the service account, for example mode `0600`. 7. Remove credentials from startup output and documentation. 8. Add login rate limiting, failed-login monitoring, and temporary account lockout. 9. Require immediate password reset if any legacy default account must temporarily be retained. 10. Invalidate all sessions and rotate all existing passwords when deploying the corrected version. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/web_app.py:664
Finding
Passwords Stored Using Unsalted, Fast SHA-256 Hashes<![CDATA[ ## Vulnerability Details **File Location**: `scripts/web_app.py:664-680` **Vulnerability Type**: Inadequate password hashing **Risk Level**: High ### Complete Code Snippet ```python data = request.json username = data.get('username', '').strip() password = data.get('password', '').strip() role = data.get('role', 'viewer') if not username or not password: return jsonify({'status': 'error', 'message': '用户名和密码不能为空'}) if username in USERS: return jsonify({'status': 'error', 'message': '用户已存在'}) if role not in ROLES: return jsonify({'status': 'error', 'message': '无效的角色'}) # 创建用户 new_id = max([u['id'] for u in USERS.values()]) + 1 USERS[username] = { 'password': hashlib.sha256(password.encode()).hexdigest(), 'id': new_id, 'role': role } ``` The same construction is used during login and password changes: ```python password_hash = hashlib.sha256(password.encode()).hexdigest() if password_hash == USERS[username]['password']: ``` ```python old_hash = hashlib.sha256(old_password.encode()).hexdigest() if old_hash != USERS[target_user]['password']: return jsonify({'status': 'error', 'message': '原密码错误'}) USERS[target_user]['password'] = hashlib.sha256(new_password.encode()).hexdigest() ``` ### Technical Analysis SHA-256 is a general-purpose fast hash and is not suitable for password storage. The implementation has no per-password salt and no configurable work factor. Equal passwords therefore generate equal hashes, and attackers can test large password dictionaries at GPU speed. The user database is written to `scripts/users.json`. If that file is exposed through a backup, filesystem read, container image, or another application flaw, an attacker can perform offline cracking without triggering login rate limits or audit controls. The six-character minimum imposed by the password-change endpoint is not sufficient to compensate for the use of a fast unsalted hash. ### Attack Path 1. The attacker obtains `users.json` or anot ...[truncated 947 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace raw SHA-256 with Argon2id, scrypt, bcrypt, or Werkzeug's password-hashing helpers. 2. Use a unique automatically generated salt for every password. 3. Configure an appropriate memory and CPU cost and periodically review the parameters. 4. Use constant-time verification through the selected password-hashing library. 5. Migrate existing hashes after successful authentication or require a password reset. 6. Increase password length requirements and screen new passwords against known breached-password lists. 7. Protect `users.json` or its database replacement with restrictive filesystem permissions and exclude it from source packages and backups available to untrusted users. Example using Werkzeug: ```python from werkzeug.security import generate_password_hash, check_password_hash stored_hash = generate_password_hash(password, method="scrypt") if check_password_hash(stored_hash, candidate_password): ... ``` ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/web_app.py:1021
Finding
Flask Development Server and Debugger Exposed on All Network Interfaces<![CDATA[ ## Vulnerability Details **File Location**: `scripts/web_app.py:1021` **Vulnerability Type**: Unsafe production deployment configuration **Risk Level**: High ### Complete Code Snippet ```python app.run(host='0.0.0.0', port=5000, debug=True) ``` ### Technical Analysis Binding to `0.0.0.0` makes the service accessible through every available interface rather than limiting it to the local host described by the normal access instructions. Enabling `debug=True` activates Flask/Werkzeug development behavior, including detailed exception pages and debugger facilities. An attacker who can reach port 5000 may trigger application errors and receive stack traces, local paths, configuration details, source context, and dependency information. Depending on Werkzeug version, runtime conditions, debugger PIN protections, and surrounding deployment controls, debugger exposure can contribute to arbitrary Python execution. Running the development server also lacks the hardening, concurrency controls, and deployment protections expected of a production WSGI server. This exposure substantially increases the severity of the hard-coded credentials and session-signing key. ### Attack Path 1. The application is launched using `python3 scripts/web_app.py`. 2. Flask listens on port 5000 on all network interfaces. 3. A network peer discovers the service. 4. The attacker submits malformed or unexpected requests to routes likely to throw unhandled exceptions. 5. Debug responses expose internal implementation details. 6. Where debugger access can be unlocked or bypassed, the attacker may execute Python expressions in the server process. 7. Even without debugger execution, the attacker can use disclosed details and the fixed credentials or signing key to compromise the application. ### Impact Assessment Confirmed impact includes unnecessary remote exposure and potential disclosure of: - Source-code context and local filesystem paths. - Stack traces and dependency details. ...[truncated 413 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Never enable Flask debug mode outside an isolated development environment. 2. Default to loopback-only binding: ```python app.run(host="127.0.0.1", port=5000, debug=False) ``` 3. Deploy through a production WSGI server such as Gunicorn or Waitress. 4. Place the service behind an authenticated reverse proxy with TLS. 5. Apply host firewall rules and container-network restrictions. 6. Do not expose port 5000 directly to untrusted networks. 7. Configure centralized error handling that returns generic messages while logging details to a protected destination. 8. Separate development and production configuration, and make production startup fail if debug mode is enabled. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/web_app.py:492
Finding
State-Changing Authenticated Routes Lack CSRF Protection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/web_app.py:492-543` **Vulnerability Type**: Missing cross-site request forgery protection **Risk Level**: Medium ### Complete Code Snippet ```python @app.route('/api/watchlist', methods=['POST']) @login_required def api_add_to_watchlist(): """添加股票到监控列表(快速版)""" data = request.json code = data.get('code', '').strip() if not code: return jsonify({'status': 'error', 'message': '股票代码不能为空'}) # 验证代码格式(6位数字) if not code.isdigit() or len(code) != 6: return jsonify({'status': 'error', 'message': '股票代码格式错误(应为6位数字)'}) # 检查是否已存在 if code in WATCHED_STOCKS: return jsonify({'status': 'error', 'message': '该股票已在监控列表中'}) WATCHED_STOCKS.append(code) save_watchlist() return jsonify({ 'status': 'success', 'message': f'成功添加 {code}(请刷新首页查看详情)', 'data': {'code': code, 'name': '待加载'} }) @app.route('/api/watchlist/<code>', methods=['DELETE']) @login_required def api_remove_from_watchlist(code): """从监控列表移除股票""" if code not in WATCHED_STOCKS: return jsonify({'status': 'error', 'message': '该股票不在监控列表中'}) WATCHED_STOCKS.remove(code) save_watchlist() ``` Other sensitive state-changing routes follow the same pattern, including user creation, user deletion, and password changes. Authentication is persistent: ```python login_user(user, remember=True) ``` No CSRF middleware or per-request CSRF token validation is configured in the reviewed application. ### Technical Analysis `@login_required` establishes that a user is authenticated but does not establish that a state-changing request was intentionally initiated by that user. The application relies on browser cookies and creates persistent login sessions, while sensitive POST and DELETE handlers do not validate a CSRF token or request origin. Several routes expect JSON or non-simple HTTP methods, which limits direct exploitation ...[truncated 1600 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enable comprehensive CSRF protection, such as `Flask-WTF`'s `CSRFProtect`. 2. Generate a session-bound token and require it on every state-changing POST, PUT, PATCH, and DELETE request. 3. Send the token in a custom header for JSON API requests and reject missing or invalid tokens. 4. Validate `Origin` and, as a fallback, `Referer` for state-changing requests. 5. Set session and remember-me cookies to `Secure`, `HttpOnly`, and an appropriate `SameSite` policy. 6. Do not enable credentialed CORS for arbitrary origins. 7. Change logout to a CSRF-protected POST operation rather than a GET operation. 8. Add automated tests confirming that state-changing requests without valid CSRF tokens receive an error. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/hybrid_data_source.py:154
Finding
Market Data Retrieved Over Unencrypted HTTP<![CDATA[ ## Vulnerability Details **File Location**: `scripts/hybrid_data_source.py:154-155` **Vulnerability Type**: Unauthenticated and unencrypted external data transport **Risk Level**: Medium ### Complete Code Snippet ```python url = f'http://hq.sinajs.cn/list={symbol}' response = requests.get(url, timeout=3) ``` The batch-fetch path uses the same transport: ```python url = f'http://hq.sinajs.cn/list={symbol_str}' response = requests.get(url, timeout=5) ``` ### Technical Analysis The application retrieves stock-market data through plaintext HTTP. HTTP does not provide server authentication, confidentiality, or integrity. A network-positioned attacker can intercept and modify responses before they are parsed and stored. The inspected requests send stock symbols rather than credentials, tokens, private files, or environment data. Therefore, the static pre-scan warning about sending sensitive information over the network is not supported as credential exfiltration. The actual concern is market-data integrity and limited privacy regarding which stock symbols are queried. Because the retrieved values feed cache updates, monitoring views, sentiment calculations, and stock-selection output, manipulated responses can corrupt the system's analytical results. ### Attack Path 1. The application requests market data from `http://hq.sinajs.cn`. 2. An attacker controls or can observe a network position between the application and the endpoint, such as a hostile Wi-Fi access point, proxy, gateway, or compromised DNS path. 3. The attacker intercepts the plaintext HTTP response. 4. The attacker replaces prices, percentage changes, volume, or other response values. 5. The application parses and caches the modified data as if it came from the legitimate provider. 6. Monitoring displays, sentiment scores, and recommendation calculations consume the attacker-controlled values. ### Impact Assessment A successful attack can: - Corrupt cached market prices and related ...[truncated 386 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the endpoint with an HTTPS version supported and documented by the data provider. 2. Keep TLS certificate verification enabled and do not suppress verification warnings. 3. If the provider does not support HTTPS, select a market-data provider that offers authenticated encrypted transport. 4. Validate response structure, symbol identity, numeric ranges, and timestamps before caching data. 5. Cross-check security-sensitive or anomalous prices against a second independent data source. 6. Mark data with its source and retrieval time so downstream logic can reject stale or inconsistent records. 7. Do not treat data retrieved through plaintext HTTP as trustworthy input for automated decisions. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (66)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The supplied code is narrowly focused on data acquisition: connecting to Tushare if configured, retrieving single/batch real-time prices from Sina/Akshare, and loading historical OHLCV/amount data from Tushare/Akshare. This is consistent with a supporting market-data layer, but not with the declared end-user system description. The declared purpose promises a complete quantitative monitoring and decision system with analytics, strategy engines, recommendation outputs, automation, and UI components. None of those higher-level behaviors appear in this code chunk. There is no evidence of sentiment scoring, stock ranking, selection logic, signal generation, stop-loss/take-profit computation, scheduled tasks, backtest workflows, or web-serving code. Therefore the description materially overstates what this code actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description promises a full-featured A-share quant platform with analytics, data collection, recommendations, monitoring, and UI/automation components. The actual code chunk is a narrow utility script whose sole purpose is determining whether the current time is within certain trading sessions and returning a status via stdout/exit code. This is not merely a supporting detail of the declared system when evaluated in isolation: the primary behavior of the supplied code is much smaller in scope and does not demonstrate the major claimed capabilities. There is no suspicious undeclared behavior beyond time checking, but there is a strong description-to-behavior mismatch because the supplied code does not substantiate the declared functionality.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The code is related to one declared sub-feature—7-dimension market sentiment scoring for A-shares—and does process broad market stock data consistent with that portion of the description. However, the declared purpose describes a much broader end-user capability set centered on a full quantitative monitoring and stock recommendation system, while this code chunk only performs sentiment aggregation and returns a score plus statistics. It does not implement stock screening strategies, recommendations, monitoring, rankings, trading signal calculations, risk controls, UI, cron scheduling, or backtesting. Additionally, one advertised sentiment dimension (trend relative to MA20) is not actually computed and is instead fixed at a neutral default. Therefore, the description materially overstates what this supplied code chunk actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The description presents a comprehensive quantitative trading/stock selection platform, but this code chunk only provides data access utilities: trading-time checks, real-time quote retrieval, batch quote retrieval, and historical data retrieval via an underlying HybridDataSource. These are supporting data-layer functions, not the described end-user system capabilities. There is no evidence here of sentiment scoring, multi-strategy selection, automated recommendations, stop-loss logic, rankings, web UI, cron jobs, or backtesting. While the code is plausibly a component of such a system, the supplied chunk does not accurately represent the broad declared functionality, so this is a material description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared description presents a comprehensive A-share quantitative analysis and stock recommendation platform. However, this code chunk only implements a narrow supporting function: conditionally running a market-data update during trading hours. While data collection/update is consistent with part of the described system, the actual behavior of this chunk is far more limited than the declared purpose and does not demonstrate most of the headline capabilities. Therefore, the description does not accurately represent what this supplied code chunk actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The declared description presents a full-featured quantitative monitoring and stock-picking platform. The supplied code chunk, however, is limited to data acquisition, simple caching, historical/fund-flow retrieval, and bulk market snapshot ingestion. While these behaviors are supportive of such a system, this chunk does not implement the core advertised capabilities such as scoring, strategy-based stock selection, signal generation, risk management, recommendations, web UI, or backtesting. There is no evidence of unrelated malicious behavior or inconsistent resource access; the mismatch is that the actual code is a narrower data-fetching component rather than the described end-user quantitative analysis system.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The description presents a full-featured quantitative stock monitoring and recommendation platform, but the supplied code chunk is narrowly scoped to data persistence and retrieval in SQLite. Its primary purpose is cache/database management, not quantitative analysis, recommendation, monitoring orchestration, or backtesting. While a cache layer could be a supporting component of such a system, this chunk by itself does not substantiate most of the declared high-level capabilities. Therefore the description materially overstates what this code actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The declared description presents a full-featured A-share quantitative monitoring and stock-selection system with data acquisition, analytics, automation, UI, and recommendation capabilities. The supplied code chunk does not implement those system behaviors; it merely stores strategy/risk/indicator configuration constants and provides simple lookup helper functions. Some declared ideas are partially reflected conceptually—such as short-term vs long-term strategies, dynamic ATR stop-loss/take-profit, buy/sell signal scoring weights, and recommendation mappings—but the primary behavior in this chunk is configuration management, not an operational monitoring/selection platform. There is also a concrete quantitative discrepancy: the description claims 5 short-term plus 7 medium/long-term strategies, while the code defines 5 short-term and only 5 long-term strategies. Therefore the description materially overstates what this code chunk actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The code is related to the declared stock-monitoring platform and does include a web interface, historical data access, backtesting, watchlist management, and some market sentiment/selection endpoints. However, this chunk also implements substantial undeclared capabilities centered on authentication, authorization, and user administration, including login/logout, roles, password changes, user CRUD, and persistence of user data. Those are material capabilities not mentioned in the declared description. Additionally, one endpoint (/api/market/sentiment) is exposed without login protection, which differs from the generally described monitored web system behavior. So while the code is broadly in-domain, the description does not accurately represent the full behavior of this code chunk.

Ae1

High
Category
analysis-evasion
Content
编辑 `web_app.py`,修改 `WATCHED_STOCKS` 列表:
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
编辑 `web_app.py`,修改 `WATCHED_STOCKS` 列表:
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
编辑 `web_app.py`,修改 `WATCHED_STOCKS` 列表:
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Missing User Warnings

High
Confidence
99% confidence
Finding
Publishing a default password in public-facing API documentation is a real security issue because users often leave defaults unchanged, especially for local or internal services. In this skill's context, the service exposes trading-related data and automation features, so reuse of the documented credential could allow unauthorized access wherever the app is reachable beyond a strictly isolated localhost setup.

Missing User Warnings

High
Confidence
99% confidence
Finding
The authentication section instructs operators to edit source code and hardcode the password directly in `web_app.py`. Hardcoded secrets are easily leaked through version control, backups, logs, screenshots, and shared packages, and they discourage rotation and secure deployment practices.

Missing User Warnings

High
Confidence
99% confidence
Finding
The document publishes a default administrative username and password in cleartext without any warning or requirement to change them. If this skill is installed as documented and the web service is reachable beyond localhost through port forwarding, reverse proxies, or misconfiguration, attackers could gain unauthorized admin access immediately using known credentials.

Hidden Instructions

High
Category
Prompt Injection
Content
{% block content %}
<div class="container-fluid py-4">
    <!-- 1. 市场情绪 (置顶) -->
    <div class="panel mb-4">
        <div class="panel-header">
            <div class="panel-title">
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill advertises executable Python scripts, local SQLite storage, and external data-fetching packages, but does not declare any tool scope such as allowed-tools or permissions. That omission weakens reviewability and least-privilege enforcement because consumers cannot easily tell that the skill will read/write local files and make network requests.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The documentation instructs users to start a local web server, schedule recurring cron jobs, and use a SQLite cache/database, but does not clearly warn that the skill will create or modify local files and may run continuously in the background. This reduces informed consent and can lead users to deploy persistent automation and data collection without understanding storage, resource use, or operational exposure.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The document says authentication is required, yet all curl, jQuery, and Python examples call protected endpoints without any auth material. This inconsistency strongly suggests either authentication is not actually enforced or integrators will implement clients that assume unauthenticated access, increasing the chance of accidental exposure of market-monitoring data and any adjacent privileged functionality.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The entire skill documentation is written in Chinese and does not indicate that users may choose another language or locale. Under the policy rule, forcing a specific language without opt-in can be a natural-language policy violation unless the locale restriction is explicitly documented and justified.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
Natural-language policy review applies to all file types, including markdown. This file forces a specific language/locale experience for all users by presenting all instructions in Chinese and does not provide an opt-in, alternative language, or a documented justification that the skill is intended only for a Chinese-speaking or region-specific audience.

Internal Network Request

Medium
Category
Server-Side Request Forgery
Content
```python
import requests

response = requests.get('http://localhost:5000/api/market/sentiment')
data = response.json()

print(f"市场情绪: {data['level']} {data['emoji']}")
Confidence
70% confidence
Finding
Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.

Internal Network Request

Medium
Category
Server-Side Request Forgery
Content
```python
import requests

response = requests.get('http://localhost:5000/api/market/sentiment')
data = response.json()

print(f"市场情绪: {data['level']} {data['emoji']}")
Confidence
70% confidence
Finding
Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.

Internal Network Request

Medium
Category
Server-Side Request Forgery
Content
```python
import requests

response = requests.get('http://localhost:5000/api/market/sentiment')
data = response.json()

print(f"市场情绪: {data['level']} {data['emoji']}")
Confidence
70% confidence
Finding
Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.

Internal Network Request

Medium
Category
Server-Side Request Forgery
Content
```python
import requests

response = requests.get('http://localhost:5000/api/market/sentiment')
data = response.json()

print(f"市场情绪: {data['level']} {data['emoji']}")
Confidence
70% confidence
Finding
Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.

Static analysis

No suspicious patterns detected.