Back to skill

Security audit

qianfan clawhub

Security checks for vulnerabilities and agentic risk

Overview

This skill has a plausible search-and-install purpose, but its installer can unsafely write downloaded files and can expose the Baidu API key to a caller-chosen endpoint.

Treat this as a review-required installer. Do not use it with a production BAIDU_API_KEY or against untrusted/custom endpoints until endpoint allowlisting and safe ZIP extraction are added. If testing is necessary, use a low-privilege disposable key, the official Baidu endpoint only, an isolated workdir, and avoid --force unless you have checked what will be replaced.

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/qianfanclawhub.py:132
Finding
Baidu API Key Disclosure Through a User-Controlled API Endpoint## Vulnerability Details **File Location**: `scripts/qianfanclawhub.py`, lines 14–15, 46–47, 75–78, 132, and 153 **Vulnerability Type**: Credential disclosure through an unrestricted network destination **Risk Level**: High ### Vulnerable Code ```python def __init__(self, endpoint=None, api_key=None, workdir=None): self.endpoint = endpoint or 'https://appbuilder.baidu.com' self.api_key = api_key ``` ```python headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {self.api_key}' } response = requests.post( f"{self.endpoint}/v2/skills/search", json=params, headers=headers ) ``` ```python url = f"{self.endpoint}/v2/skills/download" params = {"slugName": slug_name} headers = {'Authorization': f'Bearer {self.api_key}'} response = requests.get( url, params=params, headers=headers, timeout=60 ) ``` ```python parser.add_argument( '--endpoint', type=str, default=None, help='指定 API 服务器地址' ) ``` ```python client = QianfanClawhubClient( endpoint=args.endpoint, api_key=api_key, workdir=args.workdir ) ``` ### Technical Analysis The command-line `--endpoint` option permits the caller to replace the trusted default Baidu endpoint with an arbitrary URL. The selected endpoint is used directly for both search and download requests, and the value of the `BAIDU_API_KEY` environment variable is attached as an HTTP Bearer credential. The implementation does not validate: - The URL scheme. - Whether TLS is required. - Whether the destination hostname belongs to Baidu. - Whether the destination is a local, private, or attacker-controlled server. - Whether the supplied endpoint is authorized to receive the Baidu credential. Consequently, an endpoint such as `https://attacker.example` receives the API key when either supported operation is invoked. A plaintext `http://` endpoint ...[truncated 1893 chars]
Remediation
## Remediation Suggestions 1. Remove `--endpoint` from production builds if alternative endpoints are not required for the declared functionality. 2. If endpoint customization is required, parse the URL and enforce: - An `https` scheme. - An exact allowlist of approved Baidu hostnames. - An expected port. - No embedded user information. 3. Do not rely on substring or suffix checks that can be bypassed with hostnames such as `baidu.com.attacker.example`. 4. Refuse to attach `BAIDU_API_KEY` to localhost, private-network, link-local, or unapproved destinations. 5. Use separate, low-privilege test credentials for development endpoints rather than forwarding the production API key. 6. Apply least privilege to the Baidu credential and rotate any key that may have been exposed. 7. Add connection and read timeouts to every request, including the search request. 8. Add automated tests proving that credentials are never sent when the endpoint is not an explicitly approved HTTPS origin.

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/qianfanclawhub.py:81
Finding
Arbitrary File Write Through ZIP Path Traversal During Skill Installation## Vulnerability Details **File Location**: `scripts/qianfanclawhub.py`, lines 81–120 **Vulnerability Type**: ZIP path traversal and unrestricted file overwrite **Risk Level**: High ### Vulnerable Code ```python # 解压 zip 包 with zipfile.ZipFile(io.BytesIO(response.content)) as zf: # 获取 zip 内的根目录名 namelist = zf.namelist() if not namelist: print("zip 包为空") return # 找到顶层的技能目录 skill_prefix = None for name in namelist: if name.endswith('/') and name != namelist[0]: # 找到第一个顶层目录 skill_prefix = name break # 解压到目标目录 if skill_prefix: # 如果有顶层目录,只解压该目录下的内容 for name in namelist: if name.startswith(skill_prefix): target_name = name[len(skill_prefix):] if target_name: target_path = os.path.join(skill_dir, target_name) if name.endswith('/'): os.makedirs(target_path, exist_ok=True) else: os.makedirs(os.path.dirname(target_path), exist_ok=True) with zf.open(name) as src, open(target_path, 'wb') as dst: dst.write(src.read()) else: # 没有顶层目录,直接解压所有文件 for name in namelist: if name: target_path = os.path.join(skill_dir, name) if name.endswith('/'): os.makedirs(target_path, exist_ok=True) else: os.makedirs(os.path.dirname(target_path), exist_ok=True) with zf.open(name) as src, open(target_path, 'wb') as dst: dst.write(src.read()) ``` ### Technical Analysis Archive member names are treated as trusted filesystem paths. In both extraction branches, a ZIP entry name is passed to `os.path.join` and opened for writi ...[truncated 3565 chars]
Remediation
## Remediation Suggestions 1. Extract into a newly created temporary directory rather than writing directly into the final installation location. 2. Reject archive member names that: - Are absolute paths. - Contain `..` path components. - Resolve outside the extraction root. - Use unexpected drive prefixes or platform-specific path forms. 3. Canonicalize the extraction root and each destination, then verify containment before creating any file: ```python extraction_root = os.path.realpath(skill_dir) destination = os.path.realpath( os.path.join(extraction_root, target_name) ) if os.path.commonpath([extraction_root, destination]) != extraction_root: raise ValueError("Archive member escapes extraction directory") ``` 4. Inspect ZIP metadata and reject symbolic links, device entries, and other unsupported special file types. 5. Enforce limits on archive download size, total uncompressed size, individual member size, file count, and compression ratio. 6. Validate a signed manifest or trusted cryptographic checksum before installation. 7. Validate the complete extracted tree before atomically moving it into `skill_dir`. 8. Do not follow pre-existing symlinks in destination path components. Use filesystem APIs and installation-directory permissions that prevent symlink races where supported. 9. Define safe overwrite behavior for `--force`; avoid modifying an existing installation until the replacement has passed every validation step. 10. Add regression tests using parent traversal, absolute paths, nested traversal after a valid prefix, symlink entries, oversized archives, and conflicting file paths.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared behavior materially differs from the actual capabilities: beyond search, the skill installs files locally, extracts downloaded ZIPs, and contacts a localhost service to choose install paths. This mismatch is dangerous because users may consent to a harmless search tool while actually invoking code that writes to disk and interacts with local services, increasing the risk of unintended file modification, ZIP-slip style extraction issues, or abuse of trusted localhost endpoints.

Self-Modification

High
Category
Rogue Agent
Content
# Install to default location (~/.qianfan/workspace/skills/)
python3 scripts/qianfanclawhub.py install "baidu-search"

# Force overwrite existing skill
python3 scripts/qianfanclawhub.py install "ai-ppt-generate" --force

# Install to custom directory
Confidence
91% confidence
Finding
The documented `--force` overwrite capability enables replacement of an existing installed skill, which is a form of self-modification or local code modification. In a skill installer context this is especially sensitive because replacing an existing skill can silently change future behavior, persistence, or trust assumptions, particularly when combined with downloaded content and custom installation paths.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill advertises executable behavior requiring environment access and network access but does not declare any explicit tool scope or permission boundaries. This creates a transparency and governance gap: users and calling systems cannot accurately constrain what the skill may access before execution.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The installation examples normalize writing into default and custom directories, including force-overwrite behavior, without an explicit warning that local files will be created or replaced. Users may trigger destructive filesystem changes without understanding the consequence, especially when custom paths or shared directories are used.

Context-Inappropriate Capability

Medium
Confidence
83% confidence
Finding
The manifest describes a skill for searching and installing Qianfan ecosystem skills, but the code also probes a local HTTP service at localhost:4096 to discover a workspace path and separately requires an API key from the BAIDU_API_KEY environment variable. Reading local service state and environment credentials is not described in the skill purpose and is not an obvious user-facing capability of fuzzy skill search/install itself.

Internal Network Request

Medium
Category
Server-Side Request Forgery
Content
self.skills_dir = os.path.join(workdir, 'skills')
        else:
            try:
                response = requests.get("http://localhost:4096/path", timeout=5)
                json_data = response.json()
                self.skills_dir = os.path.join(json_data['directory'], 'skills')
            except Exception as e:
Confidence
70% confidence
Finding
Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.

External Transmission

Medium
Category
Data Exfiltration
Content
limit = 20
            params = {'query': prefix, 'limit': limit}
            headers = {'Content-Type': 'application/json', 'Authorization': f'Bearer {self.api_key}'}
            response = requests.post(f"{self.endpoint}/v2/skills/search", json=params, headers=headers)
            skills = []
            if response.status_code == 200:
                skills = response.json().get('data', {}).get('skills', [])
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The installer writes files from a remote ZIP archive directly into the local skills directory without validating archive entry paths or warning the user about the extent of filesystem changes. A malicious archive can exploit path traversal sequences such as '../' or absolute paths to overwrite arbitrary files outside the intended install directory, making this more dangerous because the skill's explicit purpose is to fetch and install untrusted remote content.

Natural-Language Policy Violations

Low
Confidence
80% confidence
Finding
The description states the skill 'Prefers English keywords, falls back to Chinese if no results,' and later recommends an English-first workflow. This imposes a language preference in the skill guidance without offering the user a language choice or clearly justifying the constraint as region-specific behavior.

Missing User Warnings

Low
Confidence
88% confidence
Finding
The script reads BAIDU_API_KEY from the environment and sends it as a Bearer token in outbound requests. While this is functionally expected for an API client, the code provides no user-facing disclosure in help text or comments that the command will use local credentials and transmit them to the configured endpoint.

Static analysis

No suspicious patterns detected.