Back to skill

Security audit

123pan upload and share

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to be a real 123pan upload helper, but it uses cloud credentials, optional rclone/WebDAV flows, and subprocess/network behavior that are broader than its safest upload path.

Install only if you intend selected files to leave your machine and be stored on 123pan. Use a dedicated low-privilege 123pan token, set an isolated RCLONE_CONFIG, avoid running the WebDAV/rclone paths with unrelated secrets in the environment, pin dependencies in a virtual environment, and review generated links before sharing them.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/upload.py:85
Finding

Unvalidated API-Provided Upload Endpoint Receives Credentials and File Data

Content
View full analysis
bool: """Upload a single slice using v2 API (multipart/form-data POST).""" import time url = f"{upload_server}/upload/v2/file/slice" slice_md5 = hashlib.md5(data).hexdigest() headers = get_upload_headers() for attempt in range(max_retries): try: files = { "slice": (f"slice_{slice_no}", data, "application/octet-stream") } form_data = { "preuploadID": preupload_id, "sliceNo": slice_no, "sliceMD5": slice_md5 } resp = requests.post( url, headers=headers, data=form_data, files=files, timeout=300 ) ``` ```python upload_domain = get_upload_domain() url = f"{upload_domain}/upload/v2/file/single/create" headers = get_upload_headers() data = { "parentFileID": folder_id, "filename": filename, "etag": etag, "size": file_size, "duplicate": 1 } with open(file_path, "rb") as f: files = {"file": (filename, f)} resp = requests.post(url, headers=headers, data=data, files=files, timeout=300) ``` ### Technical Analysis The upload host returned by `https: ...[truncated 1937 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/upload_rclone.py:16
Finding

Rclone Subprocess Inherits Unrelated Secrets and May Access Shared Cloud Credentials

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
scripts/webdav_upload.py:15
Finding

Unpinned and Incompletely Declared Python Dependencies Permit Supply-Chain Substitution

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (33)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The top-level description emphasizes small-file single-step upload, but the skill also documents alternate WebDAV/rclone flows that require additional credentials and may access ~/.config/rclone/rclone.conf. That mismatch can cause users or orchestrators to authorize the skill under incomplete assumptions, increasing the chance of unintended credential exposure or broader filesystem/config access.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The top-level description emphasizes small-file single-step upload, but the skill also documents alternate WebDAV/rclone flows that require additional credentials and may access ~/.config/rclone/rclone.conf. That mismatch can cause users or orchestrators to authorize the skill under incomplete assumptions, increasing the chance of unintended credential exposure or broader filesystem/config access.

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 · manifest.json (reported line 11)May include surrounding context.

json
{
        "name": "PAN123_ACCESS_TOKEN",
        "required": true,
        "description": "123pan API access token from https://www.123pan.com/dashboard/dev"
      },
      {
        "name": "PAN123_DIRECT_FOLDER_ID",

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 · scripts/upload.py (reported line 35)May include surrounding context.

python
{
        "name": "PAN123_ACCESS_TOKEN",
        "required": true,
        "description": "123pan API access token from https://www.123pan.com/dashboard/dev"
      },
      {
        "name": "PAN123_DIRECT_FOLDER_ID",

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · manifest.json (reported line 48)May include surrounding context.

json
],
    "suggested_isolation": {
      "rclone_config": "Create dedicated rclone config: rclone config --config ~/123pan-rclone.conf",
      "env_file": "Store credentials in .env file (add to .gitignore)"
    }
  },
  "inputs": {

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/upload_rclone.py (reported line 26)May include surrounding context.

python
def get_rclone_env():
    """获取 rclone 环境变量,支持配置隔离"""
    env = os.environ.copy()
    if RCLONE_CONFIG:
        env["RCLONE_CONFIG"] = RCLONE_CONFIG
        print(f"Using isolated rclone config: {RCLONE_CONFIG}")

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/upload_webdav_link.py (reported line 31)May include surrounding context.

python
def get_rclone_env():
    """获取 rclone 环境变量,支持配置隔离"""
    env = os.environ.copy()
    if RCLONE_CONFIG:
        env["RCLONE_CONFIG"] = RCLONE_CONFIG
        print(f"Using isolated rclone config: {RCLONE_CONFIG}")

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The manifest says this skill uploads files to 123pan and generates shareable links, including short share links or direct download links. But this script stops after uploading and explicitly states that users must use the 123pan web interface to get share links, showing the implemented behavior is narrower than the described capability.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The README advertises a broader upload capability than the manifest context: it explicitly says the skill supports files over 1GB via chunked upload. The manifest, however, limits scope to small files under 1GB using single-step upload, so the documented behavior exceeds the stated skill purpose.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% 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 · README.md (reported line 21)May include surrounding context.

openclaw skill install ./123pan-upload.skill

方法二:手动复制

mkdir -p ~/.openclaw/skills/123pan-upload cp -r 123pan-upload/* ~/.openclaw/skills/123pan-upload/

text

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README instructs users to upload local files to a third-party cloud service without an explicit privacy or data-handling warning. In an agent/skill context, this can cause users to transmit sensitive local data off-host without fully understanding that the content leaves their environment and becomes subject to a third party's storage, logging, and sharing model.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

These lines describe a chunked upload process for files at or above 1GB, including create, get upload URL, upload parts, and complete operations. That documented capability is inconsistent with the manifest description, which says the skill works with small files under 1GB via single-step upload.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
85% confidence
Finding

The skill documents use of environment variables, network access, and shell commands, but it does not declare any explicit tool scope or permissions boundary. That creates an execution-trust gap: an agent may invoke the skill with broader capabilities than users expect, including access to local environment secrets and arbitrary shell/network operations.

Content

No source excerpt is available for this finding.

Tainted flow: 'filename' from requests.post (line 445, network input) → requests.post (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

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

python
file_size = file_path.stat().st_size
    etag = get_md5(str(file_path))

    resp = requests.post(
        f"{API_BASE}/upload/v2/file/create",
        headers=get_headers(),
        json={

Tainted flow: 'form_data' from requests.get (line 154, network input) → requests.post (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/upload.py (reported line 160)May include surrounding context.

python
"sliceMD5": slice_md5
            }
            
            resp = requests.post(
                url,
                headers=headers,
                data=form_data,

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The manifest description frames the skill as working with small files under 1GB via single-step upload. However, the code explicitly implements chunked uploads for files >=1GB and allows uploads up to a 10GB API limit, which is materially broader behavior than described.

Content

No source excerpt is available for this finding.

Tainted flow: 'data' from requests.post (line 46, network input) → requests.post (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/upload.py (reported line 339)May include surrounding context.

python
with open(file_path, "rb") as f:
        files = {"file": (filename, f)}
        resp = requests.post(url, headers=headers, data=data, files=files, timeout=300)

    resp.raise_for_status()
    result = resp.json()

Tainted flow: 'file_id' from requests.post (line 444, network input) → requests.get (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/upload.py (reported line 356)May include surrounding context.

python
def get_direct_link(file_id: int) -> str:
    """Get direct link for a file."""
    resp = requests.get(
        f"{API_BASE}/api/v1/direct-link/url",
        headers=get_headers(),
        params={"fileID": file_id},

Tainted flow: 'filename' from requests.post (line 445, network input) → requests.post (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/upload.py (reported line 373)May include surrounding context.

python
def create_share_link(file_id: int, filename: str) -> str:
    """Create share link for a file."""
    resp = requests.post(
        f"{API_BASE}/api/v1/share/create",
        headers=get_headers(),
        json={

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
84% confidence
Finding

The script allows the executable path to be controlled by the RCLONE_BIN environment variable, and otherwise resolves rclone from PATH using which. In an agent or multi-tenant execution environment, a malicious or tainted environment could cause execution of an attacker-controlled binary, leading to arbitrary code execution under the agent's privileges.

Content

Scanner excerpt · scripts/upload_rclone.py (reported line 16)May include surrounding context.

python
from pathlib import Path

# 检测 rclone 路径:环境变量 > 系统 PATH > 默认本地路径
RCLONE_BIN = os.environ.get("RCLONE_BIN") or subprocess.run(["which", "rclone"], capture_output=True, text=True).stdout.strip() or os.path.expanduser("~/.openclaw/rclone-v1.73.2-linux-amd64/rclone")

# 支持隔离的 rclone 配置(避免读取 ~/.config/rclone/rclone.conf)
RCLONE_CONFIG = os.environ.get("RCLONE_CONFIG")

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/upload_rclone.py (reported line 70)May include surrounding context.

python
]
    
    try:
        process = subprocess.Popen(
            cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/upload_webdav_link.py (reported line 80)May include surrounding context.

python
]
    
    try:
        process = subprocess.Popen(
            cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,

Tainted flow: 'cmd' from os.environ.get (line 122, credential/environment) → subprocess.Popen (code execution)

Medium
Category
Data Flow
Confidence
88% confidence
Finding

The command executed by Popen inherits its first element from RCLONE_BIN, which is sourced from environment or PATH resolution. If an attacker can influence the environment, they can replace rclone with an arbitrary executable and gain code execution when uploads are performed.

Content

Scanner excerpt · scripts/upload_rclone.py (reported line 70)May include surrounding context.

python
]
    
    try:
        process = subprocess.Popen(
            cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/upload_rclone.py (reported line 123)May include surrounding context.

python
# Get remote file info using rclone ls
        cmd = [RCLONE_BIN, 'lsjson', remote_file]
        result = subprocess.run(cmd, capture_output=True, text=True, env=get_rclone_env())
        
        if result.returncode == 0:
            import json

Tainted flow: 'cmd' from os.environ.get (line 122, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Confidence
88% confidence
Finding

This verification command also executes the binary selected through environment/PATH-controlled resolution, so the same binary-hijacking risk applies. Because the code runs after upload as part of normal workflow, a poisoned environment could reliably trigger attacker-controlled code.

Content

Scanner excerpt · scripts/upload_rclone.py (reported line 123)May include surrounding context.

python
# Get remote file info using rclone ls
        cmd = [RCLONE_BIN, 'lsjson', remote_file]
        result = subprocess.run(cmd, capture_output=True, text=True, env=get_rclone_env())
        
        if result.returncode == 0:
            import json

Static analysis

No suspicious patterns detected.