Back to skill

Security audit

美团外卖

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real Meituan coupon helper, but it handles live account tokens in ways that could expose them through logs, command arguments, URLs, and local files.

Install only if you are comfortable giving this skill access to your Meituan login flow and storing account tokens locally. Avoid using it on shared machines or environments where command output, process arguments, or agent logs may be retained, and clear both login and device data when finished.

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

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:179
Finding
Authentication Token Exposure Through Process Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:179`, `SKILL.md:246-249`, `scripts/issue.py:150`, `scripts/query.py:144` **Vulnerability Type**: Authentication token disclosure through process arguments **Risk Level**: Medium ### Vulnerable Code ```bash ISSUE_RESULT=$($PYTHON "$ISSUE_SCRIPT" --token "$USER_TOKEN" --phone-masked "$PHONE_MASKED") ``` ```bash QUERY_RESULT=$($PYTHON "$QUERY_SCRIPT" --token "$USER_TOKEN" --dates "20260323") QUERY_RESULT=$($PYTHON "$QUERY_SCRIPT" --token "$USER_TOKEN" --dates "20260320,20260323") ``` ```python # scripts/issue.py parser.add_argument("--token", required=True, help="User user_token") parser.add_argument("--phone-masked", required=True, help="Masked phone number used to generate redeem_code") ``` ```python # scripts/query.py parser.add_argument("--token", required=True, help="User user_token") parser.add_argument( "--dates", required=True, help="Query date, such as 20260323, or range, such as 20260320,20260323" ) ``` ### Technical Analysis The Skill transfers a reusable Meituan session token between processes using a command-line argument. Command-line arguments are not an appropriate secret transport mechanism because they may be visible through: - Process inspection utilities available to other local processes under applicable operating-system permissions. - Agent execution traces and tool-call records. - Shell debugging or tracing facilities. - Endpoint monitoring, audit, or process telemetry. - Error reports that record the executed command. Quoting the variable prevents shell word splitting but does not conceal the value from process metadata or logging. The token is already stored in a permission-restricted authentication file, so exposing it again through the command line exceeds the minimum data exposure necessary for coupon issuance and history queries. ### Attack Path 1. The user authenticates successfully, and the Skill obtains a valid `user_token`. 2. The Agent invokes ` ...[truncated 758 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the `--token` argument from `issue.py` and `query.py`. - Have the scripts load the token directly from the existing authentication file after verifying its ownership and restrictive permissions. - Alternatively, pass the token over standard input or through a dedicated inherited file descriptor. - Ensure Agent tool output, command telemetry, and error messages redact authentication tokens. - Avoid environment variables for long-lived secrets where process-environment inspection is possible. - Rotate or invalidate tokens that may already have been exposed through historical execution logs. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/auth.py:252
Finding
Session and Device Tokens Returned in Standard Output<![CDATA[ ## Vulnerability Details **File Location**: `scripts/auth.py:189-197`, `scripts/auth.py:252-260`, `scripts/auth.py:486-491` **Vulnerability Type**: Sensitive authentication material exposed in command output **Risk Level**: Medium ### Vulnerable Code ```python if user_token: print(json.dumps({ "success": True, "valid": True, "user_token": user_token, "device_token": device_token, "phone_masked": phone_masked, "check_mode": "local" }, ensure_ascii=False)) ``` ```python if code == 0: print(json.dumps({ "success": True, "valid": True, "user_token": user_token, "device_token": existing_device_token, "phone_masked": phone_masked, "check_mode": "remote" }, ensure_ascii=False)) ``` ```python result = { "success": True, "user_token": user_token, "device_token": device_token, "phone_masked": phone_masked, "message": "Authentication succeeded; user_token was written" } print(json.dumps(result, ensure_ascii=False)) ``` ### Technical Analysis The authentication commands print both the reusable session token and persistent device identifier to standard output. In an Agent environment, standard output commonly crosses several trust boundaries and may be retained in: - Tool execution results. - Conversation transcripts. - Debug logs and observability platforms. - Terminal scrollback. - Continuous integration or automation logs. Returning the secrets is not required to communicate authentication success. Downstream coupon scripts can obtain account state from protected local storage without exposing raw token values to the Agent orchestration layer. The device token is deliberately persistent across logout operations, increasing the period during which captured output remains sensitive. Although the device token may not independently authenticate the account, disclosing it weakens device-binding protections and provides useful ac ...[truncated 930 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Return only non-sensitive fields such as `success`, `valid`, `phone_masked`, and an error code. - Keep both `user_token` and `device_token` inside the authentication module's protected storage boundary. - Let issuance and query functions retrieve tokens internally rather than requiring the Agent to parse them. - Add centralized secret-redaction controls for logs and exception reports. - Do not print secret values in success messages, debug output, or structured telemetry. - Review existing Agent and execution logs and remove or restrict records containing previously emitted tokens. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/auth.py:239
Finding
Session Token Included in Token-Verification Query String<![CDATA[ ## Vulnerability Details **File Location**: `scripts/auth.py:239-247` **Vulnerability Type**: Authentication token disclosure through URL query parameters **Risk Level**: Medium ### Vulnerable Code ```python url = BASE_URL + TOKEN_VERIFY_PATH try: resp = httpx.post( url, params={"token": user_token}, headers={"Content-Type": "application/json"}, timeout=10, verify=True ) ``` ### Technical Analysis The verification request uses HTTPS and enables certificate verification, which protects the token in transit against ordinary passive network observers. However, `params={"token": user_token}` places the token in the request URL rather than the request body or authorization header. URLs are more likely than request bodies or authorization headers to be captured by: - Web server access logs. - Reverse proxies and load balancers. - Application performance monitoring systems. - Network error reports and tracing infrastructure. - Security gateways and URL analytics. A POST request does not prevent its query string from being logged. Consequently, infrastructure operators or attackers with log access may obtain a reusable session credential. ### Attack Path 1. `token-verify` constructs a request such as `/eds/claw/login/token/verify?token=<secret>`. 2. A reverse proxy, server, monitoring agent, or tracing system records the complete request URL. 3. An attacker gains read access to the corresponding logs or telemetry. 4. The attacker extracts the token from the query string. 5. The token is replayed against Meituan APIs before expiration or revocation. ### Impact Assessment Exploitation can compromise the Meituan session represented by the leaked token. The accessible operations are limited by server-side token permissions, but may include coupon issuance or coupon-history operations. The vulnerability does not directly grant access to the local host or elevate operating-system privileges. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Move the token from the query string to an authorization header, preferably using the server's supported bearer-token scheme. - If an authorization header is unavailable, place the token in the JSON POST body. - Configure servers, proxies, and observability systems to redact authorization material. - Ensure application errors never reproduce complete request URLs containing sensitive parameters. - Review existing access and tracing logs for historical token exposure and invalidate affected tokens where necessary. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/issue.py:87
Finding
Raw Session Tokens Stored as Plaintext Coupon-History Keys<![CDATA[ ## Vulnerability Details **File Location**: `scripts/issue.py:87-108`, `scripts/query.py:88-97`, `SKILL.md:292-308` **Vulnerability Type**: Redundant plaintext storage of reusable authentication tokens **Risk Level**: Medium ### Vulnerable Code ```python def save_redeem_code( sub_channel_code: str, user_token: str, date_str: str, redeem_code: str ): """ Store a redemption code in the history file. """ history = load_history() channel_data = history.setdefault(sub_channel_code, {}) token_data = channel_data.setdefault(user_token, {}) date_data = token_data.setdefault(date_str, {}) codes = date_data.setdefault(TASK_TYPE, []) if redeem_code not in codes: codes.append(redeem_code) save_history(history) ``` ```python def get_redeem_codes_by_dates( sub_channel_code: str, user_token: str, dates: list[str] ) -> list[str]: history = load_history() token_data = history.get(sub_channel_code, {}).get(user_token, {}) codes = [] for date in dates: date_codes = token_data.get(date, {}).get(TASK_TYPE, []) codes.extend(date_codes) ``` The documented history format also explicitly uses the raw token as a key: ```json { "<subChannelCode>": { "<user_token>": { "<YYYYMMDD>": { "coupon": ["redeem_code_1"] } } } } ``` ### Technical Analysis The coupon-history file uses a live account token as a JSON object key. This duplicates authentication material outside the dedicated authentication file and combines it with activity metadata and redemption codes. The code attempts to apply mode `0600`, which is a positive control on operating systems that enforce POSIX permissions. It does not eliminate the underlying exposure because: - The file may be copied into backups or diagnostic bundles. - The storage path can be redirected through `XIAOMEI_COUPON_HISTORY_FILE`. - Windows may not enforce the requested mode because chmod failures are ...[truncated 1309 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Never store the raw `user_token` in the coupon-history file. - Generate a random local account identifier after authentication and use it to associate history records. - Alternatively, derive a pseudonymous identifier using HMAC with a locally protected random key; do not use an unkeyed hash if token-guessing or cross-file correlation is a concern. - Migrate existing history entries to the replacement identifier and securely remove raw token keys. - Delete or migrate matching history data when the user requests complete data removal. - Validate redirected history paths and reject locations with unsafe ownership or permissions. - Use platform-native access controls on Windows rather than relying solely on POSIX-style `chmod`. - Preserve restrictive file permissions, atomic file replacement, and ownership checks as defense-in-depth measures. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (6)

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill instructs the agent to use shell execution, environment variables, local file storage, and network access, but it declares no explicit tool scope or permission boundaries. This increases the risk of over-privileged execution: an agent or platform may grant broader access than necessary, enabling unintended file access, token handling, or external requests beyond the minimal needs of coupon issuance and login.

Vague Triggers

Medium
Confidence
96% confidence
Finding
The trigger list is very broad and includes generic phrases like '领优惠券', '美团优惠', and '外卖红包', which can match casual conversation or ambiguous user intent. That can cause unintended activation of a skill that performs authentication, sends SMS, accesses local token files, and issues network requests, leading to surprise side effects and privacy-sensitive actions without sufficiently clear user intent.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The file prescribes fixed Chinese user-facing prompts for login and subsequent interaction, and the overall instructions are written as mandatory response templates in Chinese. There is no indication that the user may choose another language or that the locale restriction is optional or justified as a region-specific language policy.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This Python file contains the primary module docstring and CLI descriptions entirely in Chinese, including usage examples and operational messages. Under the policy rule for natural-language violations, forcing a specific language without opt-in or a clearly justified regional constraint is reportable.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The script sends a sensitive user token together with locally stored redeem-code history to a remote Meituan endpoint, but the executable flow provides no explicit user-facing notice, consent step, or data-minimization control. In a coupon-query skill this network transmission is functionally expected, but the local history file and token are still sensitive identifiers, so silent transmission increases privacy and misuse risk if the skill is invoked unexpectedly or in a broader agent context.

Natural-Language Policy Violations

Low
Confidence
94% confidence
Finding
This file contains natural-language strings only in Chinese, including the module description and usage/help text. Under the policy, forcing a specific language without user opt-in is a locale/language policy violation unless the constraint is explicitly documented and justified.

Static analysis

No suspicious patterns detected.