Back to skill

Security audit

1688上货助手

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to support its stated product-listing workflow, but it handles account tokens and remote MCP calls in ways that are broader and less protected than users should accept without review.

Review before installing. Use this only if you trust the 商机助理 service and publisher with your account token and product-listing authority. Keep the skill directory private, avoid using --server-url, delete temporary parameter files after use, and rotate the sToken if the directory or logs may have been exposed.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/call_mcp.py:129
Finding

Authorization Token Can Be Sent to an Arbitrary Server

Content
View full analysis

Vulnerability Details

File Location: scripts/call_mcp.py:129-135, scripts/call_mcp.py:239-252, and scripts/call_mcp.py:302-308
Vulnerability Type: Unrestricted credential destination
Risk Level: High

Complete Code Snippet

python
def send_request(url, payload, stoken, session_id=None):
    data = json.dumps(payload).encode("utf-8")
    headers = {
        "Content-Type": "application/json",
        "Accept": "application/json, text/event-stream",
    }
    if stoken:
        headers["sToken"] = stoken
    if session_id:
        headers["Mcp-Session-Id"] = session_id

    req = urllib.request.Request(url, data=data, headers=headers, method="POST")
python
def resolve_server_url(arg_url):
    if arg_url:
        url = arg_url
        if not url.endswith("/"):
            url += "/"
        return url
    url = load_server_url()
    if not url:
        print(json.dumps({"error": "mcpServerUrl is not configured"}),
              file=sys.stderr, flush=True)
        sys.exit(1)
    if not url.endswith("/"):
        url += "/"
    return url
python
list_parser.add_argument("--server-url", dest="server_url", default=None,
                         help="MCP server address")

call_parser.add_argument("--server-url", dest="server_url", default=None,
                         help="MCP server address")

Technical Analysis

The client loads the stored sToken and adds it to every MCP HTTP request. The --server-url command-line option takes precedence over the configured service URL, but the supplied destination is not restricted to the declared MCP service and is not required to use HTTPS.

Consequently, a caller that can influence script arguments can redirect initialization and tool requests to an attacker-controlled origin. The authorization token is then attached to the redirected request. Supporting arbitrary MCP destinations is not ...[truncated 1622 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove --server-url from production invocations and use a fixed trusted endpoint.
  2. If configurability is essential, enforce an exact allowlist of trusted scheme, hostname, port, and path values.
  3. Reject all non-HTTPS destinations before loading or attaching the token.
  4. Normalize and validate URLs with urllib.parse.urlsplit; do not rely on string-prefix validation.
  5. Disable automatic cross-origin redirects or strip sToken and Mcp-Session-Id whenever the redirect origin differs.
  6. Load the token only after endpoint validation succeeds.
  7. Add tests proving that HTTP URLs, deceptive hostnames, alternate ports, user-information components, and cross-origin redirects are rejected.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/call_mcp.py:64
Finding

Authorization Token and MCP Session Identifier Are Persisted in Plaintext

Content
View full analysis

Vulnerability Details

File Location: scripts/call_mcp.py:64-83 and scripts/call_mcp.py:159-171; related token-storage workflow in SKILL.md:28-64
Vulnerability Type: Insecure local storage of authentication material
Risk Level: Medium

Complete Code Snippet

python
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
SKILL_DIR = os.path.dirname(SCRIPT_DIR)
CONFIG_PATH = os.path.join(SKILL_DIR, "skill-config.json")
SESSION_FILE = os.path.join(SCRIPT_DIR, ".mcp_session_id")


def load_config():
    with open(CONFIG_PATH, "r", encoding="utf-8") as f:
        return json.load(f)


def load_stoken():
    return load_config().get("sToken", "")


def load_server_url():
    return load_config().get("mcpServerUrl", "")
python
def _save_session_id(session_id):
    if session_id:
        with open(SESSION_FILE, "w", encoding="utf-8") as f:
            f.write(session_id)


def _load_session_id():
    if os.path.exists(SESSION_FILE):
        with open(SESSION_FILE, "r", encoding="utf-8") as f:
            sid = f.read().strip()
            if sid:
                return sid
    return None

The corresponding configuration file uses the following plaintext structure:

json
{
  "sToken": "",
  "mcpServerUrl": "https://api.fjdaze.cn/skillmanager/"
}

Technical Analysis

The documented authorization workflow stores a future sToken directly in skill-config.json. The client also stores the MCP session identifier in scripts/.mcp_session_id. Both values are ordinary plaintext files inside the Skill directory.

The code does not request restrictive file permissions, use an operating-system credential store, separate secrets from distributable project files, or reliably clear session state after operations complete. Default permissions depend on the process environment and may allow access by other local users or services.

Although the audited ...[truncated 1316 chars]

Remediation
View remediation

Remediation Suggestions

  1. Store the authorization token in the operating system's credential manager or another dedicated secret store.
  2. Keep secrets outside the project and Skill installation directories.
  3. If file-backed storage is unavoidable, create files with owner-only permissions, such as mode 0600 on POSIX systems, and apply an equivalent restrictive access-control list on Windows.
  4. Store session files in a permission-restricted per-user runtime directory rather than under scripts/.
  5. Delete session identifiers when sessions expire, authentication changes, or the workflow terminates.
  6. Add skill-config.json, .mcp_session_id, and equivalent secret-bearing files to packaging and version-control exclusion rules.
  7. Use atomic writes and reject files with unexpected ownership, permissions, or symbolic-link status.
  8. Document token revocation and rotation procedures for users who may have exposed the Skill directory.

T09 · Insecure Skill Coding Practices

Note
Location
SKILL.md:95
Finding

Predictable Temporary Parameter Files Can Retain or Expose User Data

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:95-106, with repeated use at SKILL.md:194-202, 265-273, 421-429, 533-541, and 572-580
Vulnerability Type: Unsafe temporary-file handling
Risk Level: Low

Complete Vulnerable Workflow Snippet

The Skill instructs the agent to create a predictable parameter file and pass it to the helper:

bash
python scripts/call_mcp.py call get_copy_rule_config --params-file params.json

It further standardizes a predictable working-directory filename:

bash
python scripts/call_mcp.py call url_identify --params-file _mcp_params.json

The helper then opens the caller-provided path directly:

python
if args.params_file:
    with open(args.params_file, "r", encoding="utf-8") as f:
        params = json.load(f)
elif args.params:
    params_str = args.params
    if params_str.startswith("@") and len(params_str) > 1:
        with open(params_str[1:], "r", encoding="utf-8") as f:
            params = json.load(f)
    else:
        params = json.loads(params_str)

Technical Analysis

The workflow repeatedly recommends _mcp_params.json or similarly predictable filenames in the current working directory. These files can contain product URLs, product identifiers, shipping-address identifiers, freight-template selections, pricing settings, and product-copy parameters.

No instruction requires secure exclusive creation, owner-only permissions, symbolic-link protection, or deletion after use. The helper accepts and reads the path directly. A predictable shared filename introduces a race window between the agent writing the file and the helper reading it, and the contents may remain on disk after the request.

Exploitation requires local access to the relevant working directory or another process operating under permissions that allow observing or modifying the file.

Attack Path

  1. The Skill prepares an MCP operation using t ...[truncated 1170 chars]
Remediation
View remediation

Remediation Suggestions

  1. Prefer passing JSON through standard input so sensitive parameters are never written to a working-directory file.
  2. If a file is required, use the platform's secure temporary-file API with a cryptographically unpredictable name and exclusive creation.
  3. Apply owner-only permissions when the file is created.
  4. Store temporary files in a permission-restricted per-user temporary directory.
  5. Delete parameter files in a guaranteed cleanup block immediately after the helper finishes.
  6. Reject symbolic links and validate file ownership and type before reading a parameter file.
  7. Avoid fixed names such as _mcp_params.json, especially in shared or project directories.
  8. Exclude temporary parameter patterns from version control, packaging, backup, and synchronization where practical.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The documented purpose is a narrowly scoped 商机助理上货 workflow, but the described behavior includes a generic remote MCP client pattern: listing tools, initializing sessions, persisting session IDs, and calling arbitrary tool names with arbitrary JSON. A skill that can invoke arbitrary remote tools is effectively a general-purpose privileged bridge, which can be repurposed for unintended actions, data access, or further system interaction far beyond the declared business function.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill requires sensitive capabilities including reading and writing local files, accessing environment data, and making network/MCP calls, but it does not declare any explicit tool scope or allowed-tools restrictions. That leaves the runtime with an over-broad effective capability set and makes it easier for the skill or any future prompt changes to access resources beyond the intended one-click listing workflow.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill metadata and all prescribed user-facing outputs are written as mandatory Chinese instructions, with no indication that the user may choose another language. This can violate a language/locale policy when the broader assistant is expected to respect user language preferences or offer opt-in for locale constraints.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

L606 instructs the agent to call get_skill_login_info and read result.copyRecordUrl after a successful copy task. However, the documented return schema for get_skill_login_info at L160-L168 contains only userId and userName, so the instruction contradicts the documented behavior of that tool. This is an active intent/documentation inconsistency that could cause the agent to rely on a nonexistent field.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code sends JSON-RPC payloads to a remote server and includes the sToken header when present, but there is no user-facing disclosure in the execution path that request contents and credentials are being transmitted over HTTP. For code files, remote data transmission should have some visible warning, prompt, or documented notice unless clearly disclosed elsewhere in the skill description.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · skill-config.json (reported line 3)May include surrounding context.

json
{
  "sToken": "",
  "mcpServerUrl": "https://api.fjdaze.cn/skillmanager/"
}

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The sToken save-flow trigger at L43-L47 says the flow starts when the user provides a token after auth prompt or uses keywords 保存授权 or 修改授权. But the later trigger-condition section at L141-L145 defines the authorization scene as 修改授权 or 修改账号, omitting 保存授权 and adding 修改账号. These instructions contradict each other and can lead to inconsistent invocation behavior.

Content

No source excerpt is available for this finding.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/call_mcp.py (reported line 56)May include surrounding context.

python
self._file.write(s)
                self._file.flush()
            def __getattr__(self, name):
                return getattr(self._file, name)
        sys.stdout = _Utf8Writer(sys.stdout)
        sys.stderr = _Utf8Writer(sys.stderr)

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The script persists the MCP session ID to a local file named .mcp_session_id, but the user is not warned that execution creates and updates local state on disk. For code files, file writes that affect local state should have at least some visible disclosure, comment, prompt, or external documentation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The command-line interface presents help and descriptions partly in Chinese, while the top-level program description is in English, without offering any language selection or documenting a locale requirement. This can violate language-choice policy when a specific language is effectively forced on users without opt-in.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.