Back to skill

Security audit

1688-ranking

Security checks for vulnerabilities and agentic risk

Overview

The skill generally matches its 1688 ranking/search purpose, but it needs review because it stores reusable OAuth tokens in a shared plaintext cache and can print a full access token if the auth helper is run directly.

Install only if you are comfortable giving this skill a 1688 AppKey, AppSecret, and refresh token. Treat the cache file as a secret, restrict its permissions, avoid running scripts/auth.py directly in logged environments, and revoke or rotate the 1688 tokens if console output or the shared cache 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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/auth.py:43
Finding

Shared OAuth Tokens Stored in Plaintext Without Explicit Restrictive Permissions

Content
View full analysis

Vulnerability Details

File Location: scripts/auth.py, lines 19 and 43–58
Vulnerability Type: Plaintext credential storage with insufficient access-control enforcement
Risk Level: Medium

Vulnerable Code

python
# Global token cache path shared by all 1688 Skills
TOKEN_CACHE_PATH = Path.home() / ".openclaw" / "workspace" / "skills" / ".1688_token_cache.json"
python
def save_token_to_cache(token_data, app_key):
    """Save token to cache"""
    ensure_cache_dir()

    # Calculate expiration time
    expires_in = int(token_data.get('expires_in', 3600))
    expires_at = time.time() + expires_in

    cache_data = {
        'access_token': token_data['access_token'],
        'refresh_token': token_data.get('refresh_token'),
        'expires_at': expires_at,
        'app_key': app_key
    }

    with open(TOKEN_CACHE_PATH, 'w') as f:
        json.dump(cache_data, f)

Technical Analysis

The authentication module stores both the access token and refresh token in an unencrypted JSON file. It does not explicitly assign restrictive permissions to the cache directory or file, verify ownership before reading, or reject unsafe file types such as symbolic links.

Consequently, credential confidentiality depends on the process umask and preexisting permissions of the surrounding workspace. The documented cross-Skill cache design also gives other 1688 Skills access to credentials that this Skill could otherwise keep private, increasing the trust boundary beyond the minimum privilege required for ranking and category queries.

Attack Path

  1. The user runs a ranking or category query with ALI1688_REFRESH_TOKEN configured.
  2. get_access_token() sends the refresh request to the official 1688 endpoint and receives OAuth tokens.
  3. save_token_to_cache() writes the access token and potentially the refresh token to .1688_token_cache.json.
  4. A malicious local process, another Skill, or another local user with access to the workspace ...[truncated 886 chars]
Remediation
View remediation

Remediation Suggestions

  • Prefer an operating-system credential store or another dedicated secret-management facility instead of a plaintext workspace file.
  • If a file cache is unavoidable, create its directory with mode 0700 and the cache file with mode 0600, without relying on the ambient umask.
  • Write tokens atomically through a securely created temporary file and then replace the destination.
  • Before reading or replacing the cache, verify that it is a regular file, is not a symbolic link, is owned by the expected user, and has no group or other permissions.
  • Avoid sharing a single token cache among unrelated Skills. Use per-Skill or explicitly scoped credential storage unless cross-Skill sharing is indispensable and approved.
  • Do not retain the refresh token in the cache unless caching it is necessary. Minimize the token material and lifetime stored on disk.
  • Provide token revocation and cache deletion procedures for suspected disclosure.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/auth.py:119
Finding

Access Token Disclosed Through Standard Output

Content
View full analysis

Vulnerability Details

File Location: scripts/auth.py, lines 119–134
Vulnerability Type: Sensitive credential exposure through logging or console output
Risk Level: Medium

Vulnerable Code

python
if __name__ == "__main__":
    # Test case
    app_key = os.getenv('ALI1688_APP_KEY')
    app_secret = os.getenv('ALI1688_APP_SECRET')
    refresh_token = os.getenv('ALI1688_REFRESH_TOKEN')
    access_token = os.getenv('ALI1688_ACCESS_TOKEN')

    if not app_key or not app_secret:
        print("Error: ALI1688_APP_KEY and ALI1688_APP_SECRET are required")
        exit(1)

    try:
        token = get_access_token(app_key, app_secret, refresh_token, access_token)
        print(f"Access token: {token}")
    except Exception as e:
        print(f"Error: {e}")
        exit(1)

Technical Analysis

When the authentication module is executed directly, it prints the complete bearer token to standard output. Standard output may be retained in terminal scrollback, Agent transcripts, CI/CD logs, process-supervisor logs, debugging records, or centralized logging systems.

A bearer token is sufficient for authentication within its granted API scope; possession is generally enough to impersonate the authorized caller. Printing the token is unnecessary for confirming that authentication succeeded.

Attack Path

  1. A user, Agent, administrator, or automated diagnostic process runs python3 scripts/auth.py.
  2. The module retrieves an access token from the environment, shared cache, or official refresh-token flow.
  3. The complete token is printed to standard output.
  4. The output is captured in a transcript, build log, monitoring platform, terminal recording, or other retained record.
  5. A party with access to that record copies the token.
  6. The party submits authenticated requests to the 1688 API until the token expires or is revoked.

Impact Assessment

An attacker who obtains the token can impersonate the authorized API client and exercise th ...[truncated 371 chars]

Remediation
View remediation

Remediation Suggestions

  • Remove the statement that prints the access token.
  • Return only a non-sensitive confirmation such as Authentication succeeded.
  • If diagnostic correlation is necessary, display a short one-way fingerprint rather than any token substring.
  • Ensure exception messages and HTTP diagnostics cannot include request bodies, authorization values, or token responses.
  • Treat previously captured output as potentially compromised: remove it from retained logs where feasible and revoke or rotate exposed tokens.
  • Add tests or secret-scanning rules that fail when access tokens, refresh tokens, app secrets, or authorization headers are written to output.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (30)

Tainted flow: 'token_url' from os.getenv (line 76, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/auth.py (reported line 85)May include surrounding context.

python
}
        
        try:
            response = requests.post(token_url, data=data, timeout=10)
            response.raise_for_status()
            token_data = response.json()

Tainted flow: 'url' from os.getenv (line 55, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/category.py (reported line 58)May include surrounding context.

python
url = f"{BASE_URL}/{url_path}"
    
    try:
        response = requests.post(url, data=params, timeout=15)
        response.raise_for_status()
        return response.json()
    except requests.RequestException as e:

Tainted flow: 'url' from os.getenv (line 101, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/ranking.py (reported line 67)May include surrounding context.

python
url = f"{BASE_URL}/{url_path}"
    
    try:
        response = requests.post(url, data=params, timeout=15)
        response.raise_for_status()
        return response.json()
    except requests.RequestException as e:

Tainted flow: 'url' from os.getenv (line 101, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/ranking.py (reported line 104)May include surrounding context.

python
url = f"{BASE_URL}/{url_path}"
    
    try:
        response = requests.post(url, data=params, timeout=15)
        response.raise_for_status()
        return response.json()
    except requests.RequestException as e:

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

There is a clear description-behavior mismatch. The declared purpose is a榜单/热搜 skill for fetching 1688 ranking lists and category hot search terms. However, the supplied code calls a category translation/info endpoint (category.translation.getById) and exposes parameters for cate_id and language, indicating category metadata retrieval. No logic exists for ranking APIs, hot search APIs, or list-type selection (综合榜/热卖榜/好价榜). Authentication details are consistent with 1688 Open Platform usage, but the primary function of the code is materially different from the declared purpose.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 221)May include surrounding context.

md
- **语言支持**: 默认使用 `country=en`,但返回字段包含中英双语
  - 中文字段示例: `title`  
  - 英文字段示例: `translateTitle`
- **Access Token**: 当前解决方案产生的access_token是**长久有效**的
- **筛选条件**: 支持多种商品筛选条件(发货时效、认证工厂、一件代发等)
- **排序功能**: 支持按价格/复购率/月销量排序,但仅对当前页有效

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 247)May include surrounding context.

md
- **语言支持**: 默认使用 `country=en`,但返回字段包含中英双语
  - 中文字段示例: `title`  
  - 英文字段示例: `translateTitle`
- **Access Token**: 当前解决方案产生的access_token是**长久有效**的
- **筛选条件**: 支持多种商品筛选条件(发货时效、认证工厂、一件代发等)
- **排序功能**: 支持按价格/复购率/月销量排序,但仅对当前页有效

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The main test path reads credentials from environment variables and prints the resulting access token to stdout. Tokens written to console output may be captured in shell history, CI logs, terminal scrollback, or centralized logging systems, enabling token theft and unauthorized API use.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
97% confidence
Finding

The code explicitly outputs the access token, which is a bearer credential. Anyone with access to the terminal session, captured logs, or automation output can reuse the token to impersonate the application until expiry, and possibly chain with the cached refresh token issue for longer-term access.

Content

Scanner excerpt · scripts/auth.py (reported line 134)May include surrounding context.

python
try:
        token = get_access_token(app_key, app_secret, refresh_token, access_token)
        print(f"Access token: {token}")
    except Exception as e:
        print(f"Error: {e}")
        exit(1)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding

The skill documentation declares no explicit tool scope even though it clearly requires environment variables, network access, and shared file-based token caching. This weakens least-privilege controls and makes it harder for a host platform to constrain what the skill may access or modify, increasing the blast radius if the implementation is flawed or compromised.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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.md (reported line 81)May include surrounding context.

  1. 页面会跳转到你的回调地址,URL 中带有 code 参数
  2. 用 code 换取 Token(有效期短,需在10分钟内使用):
bash
curl -X POST "https://gw.open.1688.com/openapi/param2/1/system.oauth2/getToken/YOUR_APPKEY" \
-d "grant_type=authorization_code" \
-d "need_refresh_token=true" \
-d "client_id=YOUR_APPKEY" \

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The documentation states that automatic category queries use language=en, and elsewhere repeatedly describes English as the default behavior. This is a natural-language locale policy issue because the skill imposes a specific language choice rather than offering the user a language or locale option at invocation time.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The parameter table specifies --lang with default en, which is a natural-language statement imposing a default locale. Because the documentation does not present this as a user choice or provide justification for an English-only default, it conflicts with the policy guidance on forced language/locale behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The documentation describes the --country parameter as defaulting to en, again imposing a locale choice in natural language. Without explicit opt-in or a documented business justification, this constitutes a locale policy violation under the stated rules.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SKILL.md (reported line 212)May include surrounding context.

请求地址

text
POST https://gw.open.1688.com/openapi/param2/1/com.alibaba.fenxiao.crossborder/product.topList.query/${APPKEY}

请求参数

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · references/api.md (reported line 7)May include surrounding context.

请求地址

text
POST https://gw.open.1688.com/openapi/param2/1/com.alibaba.fenxiao.crossborder/product.topList.query/${APPKEY}

请求参数

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/ranking.py (reported line 57)May include surrounding context.

python
### 请求地址
```
POST https://gw.open.1688.com/openapi/param2/1/com.alibaba.fenxiao.crossborder/product.topList.query/${APPKEY}
```

### 请求参数

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This markdown file documents required access_token and sign parameters, and later explains app-secret-based signing, but it does not warn users that these values are sensitive credentials that must be protected. For markdown files, omission of warnings about behaviors affecting privacy or system integrity qualifies as a missing user warning.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The code stores access and refresh tokens in a globally shared cache file under the user's home directory, which increases the chance that other skills or local users/processes can read reusable credentials. Because the refresh token is long-lived and the cache is explicitly shared across all 1688 skills, compromise of this file can enable persistent unauthorized API access.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The refresh flow sends refresh_token, client_id, and client_secret in an HTTP POST request to the 1688 API. While this is functionally expected for token refresh, the file provides no user-facing disclosure, prompt, or warning that local credentials will be sent over the network.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The call to get_categories(0, 'en') hard-codes English as the locale, while the surrounding user-facing messages are in Chinese. This imposes a specific language setting without user opt-in or any documented rationale, which matches the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The file header and function documentation explicitly describe category querying, which contradicts the declared skill purpose. In agent-integrated systems, misleading documentation increases the risk of improper tool selection, hidden capability creep, and accidental misuse because operators may rely on metadata and comments to understand what a tool does.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The implementation does not match the skill's stated purpose of retrieving 1688 ranking lists and hot-search terms; instead it performs category translation queries. This mismatch can cause the agent to invoke unintended functionality, undermining trust boundaries, confusing downstream automation, and potentially exposing broader API capabilities than users expected.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The skill claims independent authentication while also documenting a single shared token cache file across all 1688 skills. Shared credential state between skills can enable unintended cross-skill access, token reuse, or overwriting, especially if multiple skills or users share the same runtime or filesystem.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

Earlier sections explain that access tokens are valid for about 10 hours and that refresh tokens are used for automatic renewal, but later sections claim the access token is '长久有效' and '无需频繁刷新'. Those statements actively conflict and could cause incorrect operator assumptions about token handling.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.