Back to skill

Security audit

度小满支付技能

Security checks for vulnerabilities and agentic risk

Overview

This payment wallet skill also installs remote skill packages and writes local credentials, with install behavior that is too broad and under-scoped for automatic approval.

Review before installing. This skill is not just a payment QR helper: it can register a local client, store a signing key, download remote ZIP packages, and install files into the shared skills workspace. Only use it if you trust the dxmpay/clawpay service and package-signing pipeline, and prefer a version that validates skill IDs, installs only into an isolated expected directory, prevents overwriting existing skills without explicit consent, and stores credentials with owner-only permissions.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/clawpay-cli.js:378
Finding
User-Controlled Skill ID Enables Archive Path Traversal<![CDATA[ ## Vulnerability Details **File Location**: `scripts/clawpay-cli.js:378-380` **Vulnerability Type**: Path traversal leading to arbitrary file overwrite and deletion **Risk Level**: High ### Vulnerable Code ```javascript const zipName = `${skillId}.zip`; const zipPath = path.join(process.cwd(), zipName); fs.writeFileSync(zipPath, res.body); ``` ### Technical Analysis The `skillId` value originates from the `--skill-id` command-line argument and is used directly when constructing the downloaded archive path. No allowlist validation or basename normalization is applied before passing the resulting path to `fs.writeFileSync`. Because `path.join()` normalizes traversal components, a value such as `../../target` produces a path outside the current working directory. The `.zip` suffix limits the final filename, but it does not prevent directory traversal. The same path is later passed to `fs.unlinkSync`, so successful exploitation can both overwrite and subsequently delete the selected file. ### Attack Path 1. An attacker persuades the user or agent to invoke `downloadSkill` with a crafted Skill ID containing traversal components, such as `../../some/path/target`. 2. The client includes this value in the server request. 3. If the server returns a binary response, the response body is written to the path derived from the malicious Skill ID. 4. The resolved path escapes the intended working directory. 5. The file is overwritten with the downloaded response body. 6. During cleanup, the same path may be deleted with `fs.unlinkSync`. Exploitation requires the remote service to return a binary download response for the supplied identifier, or an attacker to control or compromise that service response. ### Impact Assessment The process can overwrite or delete files accessible to the current user, provided the targeted filename can end in `.zip`. This can corrupt user data, interfere with other applications, or modify application artifacts. The vulnerabi ...[truncated 80 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Validate `skillId` with a strict allowlist before using it in any filesystem operation, for example: ```javascript if (!/^[A-Za-z0-9_-]+$/.test(skillId)) { throw new Error('Invalid Skill ID'); } ``` - Create a private temporary directory with `fs.mkdtempSync()` and use a fixed archive filename rather than deriving the filename from user input. - Resolve the final path and verify that it remains beneath the intended download directory. - Open newly created files with restrictive permissions and exclusive creation flags. - Perform cleanup in a `finally` block using only paths generated internally by the application. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/clawpay-cli.js:393
Finding
Signed Archives Can Overwrite Unrelated Skills in the Shared Skill Directory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/clawpay-cli.js:14, 393-405` **Vulnerability Type**: Insufficient installation isolation and cross-Skill overwrite **Risk Level**: High ### Vulnerable Code ```javascript const SKILLS_DIR = path.join(__dirname, '../..'); ``` ```javascript const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'skill-')); try { extractZip(zipPath, tmpDir); } catch (e) { output({ success: false, message: `解压失败: ${e.message}`, zipPath }); process.exit(1); } process.stderr.write(`✅ 已解压到: ${tmpDir}\n`); // 3. 拷贝到 ~/.openclaw/workspace/skills/ fs.mkdirSync(SKILLS_DIR, { recursive: true }); try { fs.cpSync(tmpDir, SKILLS_DIR, { recursive: true }); } catch (e) { output({ success: false, message: `安装失败: ${e.message}`, tmpDir }); process.exit(1); } ``` ### Technical Analysis The ZIP extractor correctly rejects absolute paths and `..` traversal components. The downloaded content is also subject to hash and signature verification before extraction. However, these controls only establish that the archive was authorized by the configured signing key; they do not constrain which Skill directories the archive may contain. The entire extraction directory is recursively copied into `SKILLS_DIR`, which is the shared parent directory for Skills. The installer does not require the archive to contain exactly one top-level directory matching the requested `skillId`, and it does not reject collisions with existing Skill directories. Consequently, any party capable of producing a validly signed archive can include paths belonging to unrelated Skills and overwrite their files during installation. This is a trust-boundary weakness in the installation design. ### Attack Path 1. The signing service, its private signing key, or its archive-generation pipeline is compromised or acts maliciously. 2. A validly signed archive is generated for an apparently legitimate Skill download. 3. The archive contains top-level paths that co ...[truncated 1004 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Install each package only into an isolated destination such as `${SKILLS_DIR}/${validatedSkillId}`. - Require every archive entry to reside beneath exactly one expected top-level directory matching the requested Skill ID. - Reject archives containing multiple top-level roots, symbolic links, hard links, device files, or unexpected file types. - Reject installation if the destination already exists unless the user explicitly authorizes an update. - Stage the complete validated package outside the shared Skill root and use an atomic rename for final installation. - Define maximum archive size, entry count, expanded size, and compression ratio to mitigate resource-exhaustion archives. - Consider a signed manifest that binds the archive hash to the expected Skill ID, version, file inventory, and destination. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/clawpay-cli.js:280
Finding
Authentication Private Key Is Stored Without Explicit Owner-Only Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/clawpay-cli.js:280-288` **Vulnerability Type**: Insecure storage of authentication key material **Risk Level**: Medium ### Vulnerable Code ```javascript const configToSave = { uid: keys.uid, publicKeyB64: keys.publicKeyB64, publicKeyPem: keys.publicKeyPem, privateKeyPem: keys.privateKeyPem, registered: true, registeredAt: new Date().toISOString(), }; fs.mkdirSync(path.dirname(CONFIG_PATH), { recursive: true }); fs.writeFileSync(CONFIG_PATH, JSON.stringify(configToSave, null, 2)); ``` ### Technical Analysis The generated EC private key is serialized into `clawpay.json`. The file is created with `fs.writeFileSync` without an explicit mode, so its effective permissions depend on the host process's umask and existing file permissions. On a system with a permissive umask, or where the configuration file already has permissive permissions, the private key may be readable by other local users. The code also does not verify file ownership, permissions, or whether the target is a symbolic link before reading or writing the configuration. The private key signs API requests and therefore functions as an authentication credential. ### Attack Path 1. The user runs `userConfig` in an environment with a permissive umask, or an existing configuration file has overly broad permissions. 2. The private key is written to `scripts/clawpay.json`. 3. Another local account with filesystem access reads the configuration. 4. The attacker extracts `uid`, `publicKeyB64`, and `privateKeyPem`. 5. The attacker constructs and signs requests using the stolen identity. This path requires local filesystem access to the configuration file. ### Impact Assessment A local attacker may impersonate the registered client when communicating with the payment or Skill service. Depending on server-side authorization, this could expose purchase information or permit downloads associated with the victim ide ...[truncated 156 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Create the configuration file with owner-only permissions: ```javascript fs.writeFileSync( CONFIG_PATH, JSON.stringify(configToSave, null, 2), { mode: 0o600, flag: 'wx' } ); ``` - If updating an existing file, verify ownership and use `fs.chmodSync(CONFIG_PATH, 0o600)`. - Reject symbolic links and unexpected file types by checking the path with `lstat`. - Ensure the containing directory is owned by the current user and is not writable by other users. - Where available, store the private key in an operating-system credential store rather than a plaintext JSON file. - Avoid returning sensitive configuration content in logs or error messages. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/clawpay-cli.js:184
Finding
Legacy TLS Server Compatibility Weakens Transport Security<![CDATA[ ## Vulnerability Details **File Location**: `scripts/clawpay-cli.js:184-191`; `scripts/qrcode.js:54-64` **Vulnerability Type**: Explicit enablement of legacy TLS server behavior **Risk Level**: Low ### Vulnerable Code ```javascript const reqOptions = { hostname: urlObj.hostname, port: urlObj.port || (urlObj.protocol === 'https:' ? 443 : 80), path: urlObj.pathname + urlObj.search, method: options.method || 'GET', headers: options.headers || {}, }; if (urlObj.protocol === 'https:') { try { reqOptions.secureOptions = crypto.constants.SSL_OP_LEGACY_SERVER_CONNECT; } catch (_) {} } ``` ```javascript const options = { hostname: 'www.dxmpay.com', port: 443, path: '/facilepaycenter/tinyurl/createurl', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(postData), }, secureOptions: require('crypto').constants.SSL_OP_LEGACY_SERVER_CONNECT, }; ``` ### Technical Analysis Both HTTP implementations set `SSL_OP_LEGACY_SERVER_CONNECT`. This OpenSSL compatibility option allows connections to servers that rely on legacy renegotiation behavior. Enabling it overrides a stricter part of the platform's default TLS posture. The code does not document a specific compatibility requirement, limit the option to a narrowly controlled fallback, or warn the user when legacy behavior is required. Certificate verification is not explicitly disabled, so this does not constitute a direct TLS authentication bypass. It nevertheless expands the set of weaker server configurations the clients will accept. ### Attack Path 1. The client initiates an HTTPS request to the configured payment or Skill endpoint. 2. The endpoint, a compromised endpoint, or infrastructure in the connection path presents a server configuration requiring legacy renegotiation compatibility. 3. The explicit OpenSSL option permits a connection that a stricter default client could reject. 4. The client sends regis ...[truncated 652 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove `SSL_OP_LEGACY_SERVER_CONNECT` from both HTTPS request implementations. - Require endpoints to support modern TLS configurations and fail closed when secure negotiation is unavailable. - If temporary compatibility is operationally unavoidable, isolate it behind an explicit opt-in setting, restrict it to a documented host, and emit a security warning. - Define a modern minimum TLS version through supported Node.js TLS options. - Monitor certificate and TLS configuration changes for both remote services. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (20)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill’s declared purpose is limited to payment QR handling, but the documented install flow expands its capabilities to key generation, client registration, remote package download, signature verification, unzip, and local skill installation. That is a major trust-boundary expansion: a payment helper effectively becomes a software installer, which increases supply-chain and unauthorized code installation risk if invoked unexpectedly or by broad trigger phrases.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill’s declared purpose is limited to payment QR handling, but the documented install flow expands its capabilities to key generation, client registration, remote package download, signature verification, unzip, and local skill installation. That is a major trust-boundary expansion: a payment helper effectively becomes a software installer, which increases supply-chain and unauthorized code installation risk if invoked unexpectedly or by broad trigger phrases.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill’s declared purpose is limited to payment QR handling, but the documented install flow expands its capabilities to key generation, client registration, remote package download, signature verification, unzip, and local skill installation. That is a major trust-boundary expansion: a payment helper effectively becomes a software installer, which increases supply-chain and unauthorized code installation risk if invoked unexpectedly or by broad trigger phrases.

Ae1

High
Category
analysis-evasion
Content
**脚本路径(Skill 下载安装)**: `scripts/clawpay-cli.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
**脚本路径(Skill 下载安装)**: `scripts/clawpay-cli.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
**脚本路径(Skill 下载安装)**: `scripts/clawpay-cli.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
**脚本路径(Skill 下载安装)**: `scripts/clawpay-cli.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The file implements client registration, key generation, package download, ZIP extraction, and installation into a shared skills workspace, which materially exceeds the described payment-link/QR-generation purpose. This creates a software installation/update channel inside a payment-related skill, increasing supply-chain and unauthorized code deployment risk even though the download is signature-checked.

Context-Inappropriate Capability

High
Confidence
95% confidence
Finding
The code downloads a remote ZIP and copies its extracted contents into the shared skills directory, which is a powerful code deployment capability. Although it includes hash/signature checks and path traversal defenses, compromise or misuse of the signing service, server, or authorized package pipeline would directly enable untrusted code to be installed into the local workspace.

Vague Triggers

Medium
Confidence
89% confidence
Finding
Generic install triggers like “install skill” are too broad for a capability that downloads and installs remote skill packages. In context, this is especially risky because the skill is documented to perform configuration creation, remote download, verification, unzip, and local installation, so a casual phrase could trigger sensitive supply-chain actions.

Vague Triggers

Medium
Confidence
91% confidence
Finding
Broad trigger phrases such as payment-related requests can overlap with normal conversation and unintentionally invoke a flow that generates payment artifacts or initiates related actions. In this skill’s context, accidental activation is more dangerous because the skill also ties into purchase and install-adjacent workflows, increasing the chance of confusing or coercive payment prompts.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The documentation states that the skill does not execute external commands, yet it explicitly instructs execution of Node scripts via shell. This contradiction can mislead reviewers and users about the skill’s execution model, causing them to underestimate command-execution, local file access, and script-trust risks.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
Claiming the skill only handles audited structured JSON while the documented workflow includes multiple shell command executions is a dangerous transparency failure. In a skill ecosystem, this can lead downstream agents or operators to pass data into a component they believe is passive when it actually performs active command execution and installation-related actions.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The CLI generates an EC private key and stores it in clawpay.json on disk without any visible warning, passphrase protection, or permission hardening. If another local user, process, backup system, or malware can read that file, it can impersonate the client for signed requests and potentially download or query protected resources.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
The skill download path writes a ZIP to the current directory, extracts it, and proceeds toward installation without an explicit pre-install warning or confirmation step. In context, this means a payment-wallet-related skill can cause local filesystem modifications and stage code for installation with limited user awareness.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The file’s natural-language comments and all user-facing messages are written in Chinese, including usage text and success/error outputs. There is no indication that the skill is intentionally region-specific or that users can opt into a preferred language, which creates a locale-policy issue under the language-choice rule.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The file-level security comment says the short-link feature is disabled by default and requires an explicit flag, but the standalone CLI path initializes enableShortUrl to true and only disables it when --long-url is passed. The usage text also says --short-url is required, even though that flag is never parsed and short-linking is effectively on by default.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
The user-facing trigger and behavior description is written as Chinese-only interaction guidance, while also including one English trigger phrase, but there is no statement that the skill supports multiple languages or follows the user's preferred locale. This can create a locale policy issue if the skill defaults to Chinese responses without user opt-in.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
This CLI contains natural-language comments and user-visible output such as error and status messages in Chinese only, with no indication of language selection or opt-in. That can violate a language/locale policy when a skill imposes a specific language on all users without offering a choice.

Intent-Code Divergence

Low
Confidence
91% confidence
Finding
The JSDoc declares that success returns data shaped as { qr: string, fp: string }, but the implementation actually returns { qr, fp, url }. This is an active mismatch between documented intent and actual behavior.

Static analysis

No suspicious patterns detected.