Back to skill

Security audit

API Merchant Fee

Security checks for vulnerabilities and agentic risk

Overview

This merchant-fee lookup skill matches its stated purpose, but it stores and reuses sensitive API credentials in unsafe ways and ships a possible hardcoded API key and HTTP endpoint.

Review this skill carefully before installing. It may be usable for merchant-fee lookups, but only in an environment where you are comfortable with API credentials being passed on the command line, saved in a local plaintext file, and reused automatically. Treat the bundled apiKey as exposed, avoid real production credentials unless the storage and transport are fixed, and prefer a version that uses HTTPS, validates the official API host, and stores secrets in a managed secret store with explicit opt-in.

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

Error
Location
scripts/query_fee.py:34
Finding

API credentials are persisted in a plaintext file with no restrictive permissions

Content
View full analysis

Vulnerability Details

File Location: scripts/query_fee.py, lines 34-37
Vulnerability Type: Plaintext credential storage
Risk Level: High

Vulnerable Code

python
def save_auth(base_url: str, agent_no: str, api_key: str):
    """保存认证信息"""
    with open(AUTH_FILE, "w", encoding="utf-8") as f:
        json.dump({"baseUrl": base_url, "agentNo": agent_no, "apiKey": api_key}, f)

The function is invoked after every query, regardless of whether the request or authentication succeeded:

python
# 保存认证信息(不管成功失败都保存)
save_auth(base_url, agent_no, api_key)

Technical Analysis

The reusable AES API key, agent identifier, and API destination are written directly to scripts/.auth.json without encryption or an explicit restrictive file mode. The permissions therefore depend on the process umask and runtime environment. Other local users, processes, backup systems, repository scanners, or diagnostic tools may be able to read the resulting file.

Persisting credentials is part of the declared convenience functionality, but plaintext storage is not the minimum privilege necessary. Saving the values after failed requests also allows invalid or attacker-influenced credentials and destinations to replace previously valid state.

Attack Path

  1. A user executes a merchant-fee query with an API key.
  2. The script calls save_auth even if the network request or authentication fails.
  3. The key, agent number, and destination are written in plaintext to scripts/.auth.json.
  4. A local process or user with read access retrieves the file.
  5. The exposed key is reused to decrypt compatible traffic, forge encrypted requests, or access the API within the key's authorization scope.

Impact Assessment

Successful exploitation exposes a reusable API credential and its associated agent identity. The attacker obtains the same API authorization scope granted to that key; the exact merchant and API o ...[truncated 183 chars]

Remediation
View remediation

Remediation Suggestions

  • Store the API key in an operating-system credential manager or dedicated secrets service.
  • If file storage is unavoidable, create the file atomically with mode 0600, verify its owner and permissions before reading, and place it outside the distributed Skill directory.
  • Do not store the API key unless the user explicitly opts in.
  • Save or replace authentication state only after a successfully authenticated response.
  • Separate endpoint configuration from credentials and validate both before persistence.
  • Implement credential rotation and secure deletion procedures.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/query_fee.py:76
Finding

User-controlled API destination permits sensitive requests over unauthenticated HTTP

Content
View full analysis

Vulnerability Details

File Location: scripts/query_fee.py, lines 76-93
Vulnerability Type: Unvalidated network destination and insecure transport
Risk Level: High

Vulnerable Code

python
    url = f"{base_url.rstrip('/')}/agent/getMerchantFeeInfo"
    timeout = 30

    # 构造明文请求体
    plaintext = json.dumps(
        {"agentNo": agent_no, "userId": user_id, "tusn": tusn}, separators=(",", ":")
    )

    # AES 加密
    encrypted_data = aes_encrypt(plaintext, api_key)

    # form-data 请求
    form_data = urllib.parse.urlencode(
        {"appKey": agent_no, "data": encrypted_data}
    ).encode("utf-8")

    headers = {"Content-Type": "application/x-www-form-urlencoded"}

The package configuration also identifies a plaintext HTTP endpoint:

json
{
  "apiKey": "o/W3zri8T1ev2oSh1G5bfA==",
  "baseUrl": "http://47.111.144.23:8094",
  "timeout": 30
}

Technical Analysis

base_url is accepted from command-line input and used without validating its scheme, hostname, port, or trust relationship. It is subsequently persisted for future two-argument queries. The bundled configuration uses an IP-based plaintext HTTP URL.

The request exposes agentNo as the appKey form field and sends encrypted merchant and terminal identifiers to the selected destination. AES-ECB encryption does not provide endpoint authentication or ciphertext integrity and is not a substitute for TLS. On HTTP connections, a network attacker can observe and replay requests, block traffic, or alter responses. A user-controlled destination can also cause future requests to be sent to an unintended server.

The network request itself is required for the Skill's declared lookup functionality. Arbitrary destination selection and use of HTTP exceed the minimum privileges necessary.

Attack Path

  1. An untrusted workflow or instruction supplies a non-official base_url together with otherwise valid query a ...[truncated 943 chars]
Remediation
View remediation

Remediation Suggestions

  • Remove user-controlled API destinations and hardcode or centrally provision the official service hostname.
  • Require HTTPS and reject plaintext HTTP, IP literals, unexpected ports, embedded credentials, and unsupported URL schemes.
  • Allowlist the exact hostname and verify the destination again after every redirect, or disable redirects.
  • Retain standard certificate and hostname validation; consider certificate pinning if operationally appropriate.
  • Do not persist a destination until it has passed validation and a request has authenticated successfully.
  • Replace AES-ECB with a protocol providing authenticated encryption, such as AES-GCM, if application-layer encryption is required.
  • Add server-side nonce, timestamp, and replay protection.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/config.json:1
Finding

Reusable AES API key is hardcoded in distributed configuration

Content
View full analysis

Vulnerability Details

File Location: scripts/config.json, lines 1-5
Vulnerability Type: Hardcoded secret
Risk Level: High

Vulnerable Code

json
{
  "apiKey": "o/W3zri8T1ev2oSh1G5bfA==",
  "baseUrl": "http://47.111.144.23:8094",
  "timeout": 30
}

Technical Analysis

The configuration contains a Base64-encoded value explicitly labeled apiKey. Base64 is an encoding, not encryption, so every recipient of the Skill package can recover the key bytes directly.

The reviewed script does not currently read config.json, and the audit cannot establish whether this key is active. Nevertheless, distributing a potentially reusable cryptographic secret creates credential exposure through source archives, artifact registries, backups, and version-control history.

Attack Path

  1. An attacker obtains a copy of the Skill package or its source history.
  2. The attacker reads scripts/config.json and extracts the Base64 API key.
  3. If the key remains active, the attacker uses it to generate encrypted requests, decrypt captured compatible traffic, or access the associated API.
  4. The attacker receives whatever merchant data the server authorizes for the key and agent identity.

Impact Assessment

If active and associated with a valid agent account, the key may permit unauthorized API requests and compromise merchant fee information within that account's server-side authorization scope. It may also permit decryption of traffic encrypted with the same key. If the value is obsolete or a test credential, direct operational impact is reduced, but its inclusion still establishes an unsafe secret-management practice.

Remediation
View remediation

Remediation Suggestions

  • Immediately determine whether the exposed key is active; revoke and rotate it if it is or may have been active.
  • Remove the key from the package and purge it from version-control and artifact history where feasible.
  • Provision secrets at runtime through an operating-system credential store or secrets-management service.
  • Use separate, narrowly scoped credentials for development, testing, and production.
  • Add secret scanning to source-control and release pipelines.
  • Ensure server-side authorization limits each key to the minimum required agents, merchants, and read-only operations.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/query_fee.py:174
Finding

API key is accepted through process command-line arguments

Content
View full analysis

Vulnerability Details

File Location: scripts/query_fee.py, lines 174-181
Vulnerability Type: Credential exposure through process arguments
Risk Level: Medium

Vulnerable Code

python
def main():
    """
    用法:
      首次/换代理:python3 query_fee.py <baseUrl> <agentNo> <apiKey> <userId> <tusn>
      复用认证:    python3 query_fee.py <userId> <tusn>
    """
    if len(sys.argv) == 6:
        base_url, agent_no, api_key, user_id, tusn = sys.argv[1:]

Technical Analysis

The first-use workflow requires the reusable API key to be supplied as a command-line argument. Depending on the operating system and execution environment, arguments may appear in process listings, shell history, audit records, crash diagnostics, orchestration metadata, or agent tool-execution logs.

Passing secrets through command-line arguments is unnecessary for the declared lookup operation and exposes the credential to more local components than required.

Attack Path

  1. A user follows the documented first-use workflow and places the API key in the command invocation.
  2. The operating system, shell, automation platform, or monitoring system records or exposes the process arguments.
  3. A local user or log reader obtains the API key.
  4. If still valid, the attacker reuses it within its server-side authorization scope.

Impact Assessment

Exploitation exposes the same reusable API credential used by the legitimate agent. The attacker may obtain access to merchant-fee API operations authorized for that key. Required access depends on the environment: an attacker would generally need local process visibility, shell-history access, or access to execution and monitoring logs.

Remediation
View remediation

Remediation Suggestions

  • Do not accept secrets through command-line arguments.
  • Retrieve the key directly from an operating-system credential manager or secrets service.
  • For interactive setup, read the key with a non-echoing prompt such as getpass.
  • For automation, use a protected file descriptor or another platform-specific secret injection mechanism that does not expose the value in process arguments.
  • Prevent command invocations and secret-bearing environment data from being written to logs.
  • Rotate the credential if it has previously appeared in process, shell, or automation logs.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
Findings (9)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill describes capabilities that read and write local files and perform network requests, but it does not declare any tool scope or permission boundaries. That creates an authorization gap: an agent may exercise broader capabilities than users expect, especially when handling credentials and querying external APIs.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill explicitly instructs persistent local storage and reuse of user-supplied authentication secrets. In this context, the stored values are API credentials used to access merchant fee data, so compromise of the local file could enable unauthorized API access and exposure of merchant information across future runs.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill states that agentNo and apikey are automatically saved to a local file for later reuse, but it does not provide an explicit warning, consent flow, retention policy, or storage protection details. Persisting authentication secrets without clear disclosure increases the risk of credential theft, unintended reuse across sessions, and lateral compromise if the local workspace is accessible.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The workflow directs the agent to automatically retrieve previously stored credentials and use them in future requests when only partial parameters are supplied. This increases the chance of unintended credential use, cross-user/session confusion, and silent access to merchant data without renewed user confirmation.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script stores sensitive agent credentials (base URL, agent number, and API key) in a local .auth.json file even though credential persistence is not essential to performing a one-time fee lookup. This increases the attack surface because any local user, backup process, or malware with file access can recover reusable API credentials and use them to query or abuse the upstream service.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The code saves API credentials to a local plaintext file without any explicit warning, consent prompt, or secure storage mechanism. In this skill context, the saved values are operational credentials for merchant-related API access, so silent persistence can expose business-sensitive access tokens to other local processes or users.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The activation description and all user-facing examples/instructions are written only in Chinese, with no indication that users may choose another language or that the skill is intentionally restricted to a Chinese-speaking context. Under the stated policy, forcing a specific language without opt-in is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module docstring says the script 'supports reading locally saved agentNo/apikey' at L7, which implies reuse of existing local auth data. However, the implementation also saves credentials unconditionally via save_auth() and calls it on every run at L200-L201, so the documentation understates and misrepresents the side effect.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

All user-facing documentation and output strings in the script are fixed in Chinese, with no indication that another language can be selected. This can violate language or locale policy when a skill imposes a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.install_untrusted_source

Install source points to URL shortener or raw IP.

Warn
Code
suspicious.install_untrusted_source
Location
scripts/config.json:3