Back to skill

Security audit

TikTok官方-店铺数据分析

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly supports TikTok Shop video analytics, but it also exposes broader proxy and authorization access that users should review before installing.

Install only if you trust the publisher and runtime environment. Review or restrict the gateway environment variables, avoid exposing production API keys to untrusted shells, and prefer using the named get_video_performances script over the generic proxy unless the broader authorization and analytics access is intentional.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/_shop_analytics_common.py:15
Finding
Configurable Gateway Allows Sensitive Credentials to Be Sent to an Untrusted Destination<![CDATA[ ## Vulnerability Details **File Location**: `scripts/_shop_analytics_common.py`, lines 15-19 and 60-84 **Vulnerability Type**: `T09: Insecure Skill Coding Practices` **Risk Level**: High ### Vulnerable Code ```python API_BASE_URL = ( os.environ.get("LINKFOX_TOOL_GATEWAY") or os.environ.get("TIKTOK_SHOP_API_BASE_URL") or "https://tool-gateway.linkfox.com" ).rstrip("/") DEVELOPER_PROXY_ENDPOINT = f"{API_BASE_URL}/tiktokShop/developerProxy" ``` ```python def get_api_key() -> str: key = os.environ.get("LINKFOX_AGENT_API_KEY") or os.environ.get("LINKFOXAGENT_API_KEY") if not key: print("API Key 未配置", file=sys.stderr) sys.exit(1) return key def call_api(endpoint: str, params: dict) -> dict: api_key = get_api_key() data = json.dumps(params).encode("utf-8") req = Request( endpoint, data=data, headers={ "Authorization": api_key, "Content-Type": "application/json", "User-Agent": "LinkFox-Skill/1.0", "SESSION_ID": os.environ.get("SESSION_ID", ""), "MODE_ID": os.environ.get("MODE_ID", ""), "APP_NAME": os.environ.get("APP_NAME", ""), }, method="POST", ) try: with urlopen(req, timeout=150) as response: return json.loads(response.read().decode("utf-8")) ``` ### Technical Analysis The network request is necessary for the Skill's declared functionality, but its destination is not restricted to the documented LinkFox gateway. The `LINKFOX_TOOL_GATEWAY` and `TIKTOK_SHOP_API_BASE_URL` environment variables can replace the entire gateway origin with an arbitrary URL. The code does not enforce HTTPS, validate the destination hostname, restrict ports, reject URL user information, or otherwise verify that the destination belongs to LinkFox. Every request to the configured endpoint includes: - The LinkFox agent API key in the `Authorization` header. - The merchant's `openId` in ...[truncated 1701 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin the production gateway to an immutable HTTPS origin where operationally possible. 2. If configurability is required for testing, parse the URL and enforce an explicit allowlist of trusted hostnames. 3. Reject non-HTTPS schemes, URL user information, fragments, unexpected ports, IP-literal destinations, and malformed URLs. 4. Separate test and production configuration so production credentials cannot be sent to test endpoints. 5. Confirm redirect behavior and disable or strictly validate redirects so a trusted endpoint cannot redirect credentials to another origin. 6. Remove `SESSION_ID`, `MODE_ID`, and `APP_NAME` unless the gateway strictly requires them. If required, document their purpose and minimize their contents. 7. Use a narrowly scoped, short-lived API credential restricted to the required developer-proxy operation. 8. Add automated tests proving that untrusted hosts and plain HTTP destinations are rejected before any request is issued. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/_analytics_api_runner.py:244
Finding
Generic ERP Proxy Exposes Broader API Access Than the Declared Analytics Operations<![CDATA[ ## Vulnerability Details **File Location**: `scripts/_analytics_api_runner.py`, lines 244-296; `scripts/_shop_analytics_common.py`, lines 105-145 **Vulnerability Type**: `T05: Unauthorized Access and Privilege Escalation` **Risk Level**: Medium ### Vulnerable Code ```python def run_analytics_proxy(params: dict, caller: str = "analytics_proxy.py") -> dict: """Generic proxy: path + method + openId (+ optional shop_cipher).""" if not params.get("skipDepCheck"): ensure_auth_skill_available(caller) path = params.get("path") method = params.get("method") if not path or not method: print("Missing required fields: path, method", file=sys.stderr) sys.exit(1) open_id = require_open_id(params) shop_cipher = None needs_cipher = str(path).lstrip("/").startswith("analytics/") if needs_cipher: shop_cipher = resolve_shop_cipher(params, open_id) query_string = params.get("queryString") if shop_cipher: pairs = dict(parse_qsl(str(query_string or "").lstrip("?"), keep_blank_values=True)) pairs["shop_cipher"] = shop_cipher query_string = urlencode(pairs) body = params.get("body") if body is not None and not isinstance(body, str): body = json.dumps(body, ensure_ascii=False, separators=(",", ":")) if "requestBody" in params and body is None: rb = params["requestBody"] body = rb if isinstance(rb, str) else json.dumps(rb, ensure_ascii=False, separators=(",", ":")) proxy = developer_proxy_call( open_id, str(path), str(method).upper(), region=params.get("region"), query_string=query_string, body=body, content_type=str(params.get("contentType") or "application/json"), ) out = { "developerProxy": proxy, "resolvedPath": str(path).lstrip("/"), "appType": "erp", } if shop_cipher: out["shop_cipher"] = shop_cipher if query_string: ...[truncated 4076 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the generic `analytics_proxy.py` interface if it is not essential to the declared Skill functionality. 2. Enforce an exact allowlist of method-and-path pairs, preferably using the existing `ANALYTICS_ENDPOINTS` registry. 3. For the present feature set, permit only: - `GET authorization/202309/shops` - `GET analytics/202403/shop_videos/performance` 4. Reject request bodies for GET operations and reject methods not explicitly declared by the endpoint specification. 5. Validate query parameters against each endpoint's documented field list rather than accepting an unrestricted raw query string. 6. Apply the same exact allowlist on the server-side developer proxy. Client-side validation must not be treated as an authorization boundary. 7. Require caller authorization binding between the invoking identity, `openId`, and selected shop. 8. Add regression tests confirming that undocumented paths, alternate methods, arbitrary bodies, and future namespace endpoints are denied by default. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (20)

Tainted flow: 'req' from os.environ.get (line 70, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
method="POST",
    )
    try:
        with urlopen(req, timeout=150) as response:
            return json.loads(response.read().decode("utf-8"))
    except HTTPError as e:
        body = e.read().decode("utf-8") if e.fp else ""
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The documented available scripts include retrieval of authorized shops, which is operationally different from fetching video performance analytics and overlaps with authorization/shop-selection workflows the description says are excluded. This is dangerous because it leaks or expands access to account/shop metadata and undermines trust in the skill's declared boundaries.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The documented available scripts include retrieval of authorized shops, which is operationally different from fetching video performance analytics and overlaps with authorization/shop-selection workflows the description says are excluded. This is dangerous because it leaks or expands access to account/shop metadata and undermines trust in the skill's declared boundaries.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The documented available scripts include retrieval of authorized shops, which is operationally different from fetching video performance analytics and overlaps with authorization/shop-selection workflows the description says are excluded. This is dangerous because it leaks or expands access to account/shop metadata and undermines trust in the skill's declared boundaries.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The documented available scripts include retrieval of authorized shops, which is operationally different from fetching video performance analytics and overlaps with authorization/shop-selection workflows the description says are excluded. This is dangerous because it leaks or expands access to account/shop metadata and undermines trust in the skill's declared boundaries.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The documented available scripts include retrieval of authorized shops, which is operationally different from fetching video performance analytics and overlaps with authorization/shop-selection workflows the description says are excluded. This is dangerous because it leaks or expands access to account/shop metadata and undermines trust in the skill's declared boundaries.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The generic `run_analytics_proxy` accepts caller-supplied `path` and `method` and forwards them to `/tiktokShop/developerProxy` with only a minimal prefix check for `analytics/` before auto-resolving `shop_cipher`. That means a skill advertised as only supporting Get Video Performances can be used to reach arbitrary ERP proxy endpoints and HTTP methods, creating scope expansion and potential unauthorized access to broader TikTok Shop APIs beyond the manifest-declared capability.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
This wrapper advertises and forwards a generic proxy request shape containing user-controlled path and method, and its own usage text explicitly allows both analytics/ and authorization/ prefixes. In an analytics-only skill that explicitly says it does not include authorization, exposing authorization routes expands the reachable backend surface and can enable unintended access to auth-related endpoints through the ERP developerProxy, creating a capability mismatch between the manifest and the actual code.

Intent-Code Divergence

High
Confidence
96% confidence
Finding
The inline help text tells callers that authorization/ is an allowed path prefix, directly contradicting the skill description that says the skill has no authorization scope. That contradiction is dangerous because it normalizes and encourages use of auth-related backend routes from an analytics wrapper, increasing the chance of misuse, privilege creep, or accidental exposure of sensitive authorization operations.

Lp3

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding
The skill advertises executable scripts and proxy-based API access but does not declare any explicit tool scope or permissions boundaries. In an agent environment, undeclared access to shell, network, and environment increases the chance of over-privileged execution and makes it harder to constrain what the skill can do if invoked unexpectedly or with attacker-controlled inputs.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The referenced API documentation is for listing authorized shops, while the skill is declared as a TikTok Shop video analytics capability. This mismatch can cause the agent to invoke or expose authorization-scoped shop metadata instead of the intended analytics endpoint, leading to overbroad data access, privacy leakage, or incorrect operational behavior. In this context, the skill depends on shop selection via openId, so mixing authorization and analytics references increases the chance of confusing privilege boundaries and retrieving sensitive shop identifiers such as cipher values unnecessarily.

Natural-Language Policy Violations

Medium
Confidence
87% confidence
Finding
This markdown file presents the operational instructions and safety notes only in Chinese, including the key usage guidance in the 'Agent 注意事项' section. Under the policy, forcing a specific language without user opt-in is a natural-language locale violation unless the constraint is explicitly justified.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
To resolve shop_cipher, the code calls the authorization/202309/shops endpoint to enumerate authorized shops. The manifest explicitly says the skill does not include authorization, so embedding an authorization-domain API call extends capability beyond the stated analytics-only purpose, even if used as a convenience dependency.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The code whitelist allows both analytics and authorization paths even though the skill metadata says the skill does not include authorization. In a skill-routing context, this creates a capability mismatch that could let this analytics skill invoke auth-related upstream endpoints through the shared developer proxy, expanding privileges beyond the declared purpose and potentially bypassing policy or review boundaries.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
print(f"DEPENDENCY_MISSING: {json.dumps(payload, ensure_ascii=False)}", file=sys.stderr)
        sys.exit(DEPENDENCY_EXIT_CODE)
    try:
        result = subprocess.run(
            [sys.executable, str(checker)],
            capture_output=True,
            text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The helper sends request data to a remote endpoint and includes SESSION_ID, MODE_ID, and APP_NAME from the environment in HTTP headers. While the code performs the network call, it provides no confirmation prompt, user-facing disclosure, or warning comment/docstring indicating that user or system metadata will be transmitted.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The script invokes `run_analytics_api("get_authorized_shops", ...)` even though the skill metadata and declared purpose are limited to video performance analytics. This creates a scope mismatch that can expose shop-authorization inventory data to callers who expected only analytics access, increasing the risk of unintended data access and privilege expansion within the skill surface.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
The substantive instructional content in this reference is written in Chinese, and the file does not indicate that language is optional or provide an alternative locale. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy concern.

Natural-Language Policy Violations

Low
Confidence
94% confidence
Finding
The script emits a user-facing reason string in Chinese only: "linkfox-tiktok-shop-analytics 依赖 linkfox-tiktok-shop-auth,未找到其 SKILL.md。" This forces a specific language for at least part of the output without offering a language choice or documenting a justified locale constraint.

Intent-Code Divergence

Low
Confidence
90% confidence
Finding
The docstring says 'TikTok Shop ERP analytics — get_authorized_shops', framing the file as an analytics operation. But the actual API call on L22 performs 'get_authorized_shops', which is about authorization/shop discovery rather than analytics data, creating a documentation-to-code intent mismatch.

Static analysis

No suspicious patterns detected.