Back to skill

Security audit

Node Transfer

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real node-to-node file transfer tool, but its remote deployment, integrity check, and plaintext transfer design have safety issues that need review before use.

Install only in trusted, controlled node environments. Avoid using it for sensitive files over untrusted networks, restrict sender exposure with firewall or interface controls, validate source and destination paths, and treat deploy.js and ensure-installed.js as privileged operations until the PowerShell quoting and executable manifest issues are fixed.

Vulnerability Patterns
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • 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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
deploy.js:71
Finding
PowerShell Command Injection Through Unsafely Interpolated Deployment Parameters<![CDATA[ ## Vulnerability Details **File Location**: `deploy.js:71-83`, with attacker-controlled input selected at `deploy.js:133-134` **Vulnerability Type**: PowerShell command injection **Risk Level**: High ### Vulnerable Code ```javascript function generateDeployCommand(nodeId, targetDir) { const scriptsDir = targetDir; // Build PowerShell script let psScript = ` # node-transfer deployment script # Target: ${nodeId} # Directory: ${scriptsDir} $ErrorActionPreference = "Stop" # Create directory New-Item -ItemType Directory -Force -Path "${scriptsDir.replace(/\//g, '\\')}" | Out-Null `.trim(); ``` The values originate from command-line arguments or an environment variable: ```javascript const nodeId = args[0]; const targetDir = args[1] || process.env.TRANSFER_TARGET_DIR || 'C:/openclaw/skills/node-transfer/scripts'; ``` The same unescaped path is subsequently embedded in another executable PowerShell statement at `deploy.js:94-102`: ```javascript const targetPath = path.join(scriptsDir, file).replace(/\//g, '\\'); psScript += `\n\n`; psScript += `# Deploy ${file}\n`; psScript += `$b64 = "${encoded}"\n`; psScript += `[System.IO.File]::WriteAllBytes("${targetPath}", [System.Convert]::FromBase64String($b64))`; ``` ### Technical Analysis `nodeId`, the command-line `targetDir`, and `TRANSFER_TARGET_DIR` are inserted directly into generated PowerShell source without validation or PowerShell-safe quoting. A value containing a double quote, newline, statement separator, subexpression, or other PowerShell syntax can terminate the intended string or comment context and introduce additional commands. Replacing forward slashes with backslashes does not prevent command injection. The generated script is specifically intended to be sent to a remote node through `nodes.invoke`. Consequently, exploitation crosses from input manipulation on the orchestrating system to arbitrary command execution on the selected target node. The Base64 encoding it ...[truncated 1521 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Avoid constructing executable PowerShell through direct string interpolation. 2. Pass node identifiers and paths as separately encoded arguments rather than embedding them into source code. 3. Validate node identifiers using a strict allowlist appropriate to the OpenClaw node-ID format. 4. Resolve and constrain the deployment directory to approved installation roots. 5. Reject control characters, newlines, quotes, PowerShell metacharacters, and unsupported path forms. 6. If PowerShell source generation is unavoidable, implement and test a dedicated PowerShell literal encoder. Single-quoted PowerShell literals must escape each embedded single quote by doubling it. 7. Prefer a structured remote file-upload API over generated shell commands. 8. Require explicit confirmation of the target node and normalized destination before remote execution. 9. Add automated tests using paths containing quotes, semicolons, newlines, dollar signs, backticks, and PowerShell subexpressions. ]]>

T07 · Tool Hijacking and Spoofing

Error
Location
ensure-installed.js:86
Finding
Integrity Checker Executes an Untrusted Version Manifest<![CDATA[ ## Vulnerability Details **File Location**: `ensure-installed.js:86-97` and `ensure-installed.js:106-126` **Vulnerability Type**: Execution of untrusted JavaScript during integrity verification **Risk Level**: High ### Vulnerable Code ```javascript function loadVersionInfo(targetDir) { const versionPath = path.join(targetDir, 'version.js'); if (!fs.existsSync(versionPath)) { return null; } try { // Clear require cache to get fresh version delete require.cache[require.resolve(versionPath)]; return require(versionPath); } catch { return null; } } ``` The executable manifest is loaded before the installation is trusted: ```javascript function checkInstalled(targetDir) { const results = { installed: true, missing: [], mismatched: [], version: null, requiredVersion: VERSION }; // Check version file first const versionInfo = loadVersionInfo(targetDir); if (!versionInfo) { results.installed = false; results.missing.push('version.js'); } else { results.version = versionInfo.version; if (versionInfo.version !== VERSION) { results.installed = false; results.mismatched.push(`version: ${versionInfo.version} → ${VERSION}`); } // Check files based on version.js manifest if (versionInfo.files) { for (const [file, expectedHash] of Object.entries(versionInfo.files)) { const filePath = path.join(targetDir, file); if (!fs.existsSync(filePath)) { results.installed = false; results.missing.push(file); } else { const actualHash = hashFile(filePath); if (actualHash !== expectedHash) { results.installed = false; results.mismatched.push(`${file}: hash mismatch`); ...[truncated 2629 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace `version.js` with a non-executable data format such as `version.json`. 2. Read the manifest as text and parse it with `JSON.parse`; never use `require()` or dynamic import for integrity metadata. 3. Embed the trusted manifest or expected hashes in the checker itself, or authenticate an external manifest against a trusted embedded public key or digest. 4. Populate the manifest with actual full-length SHA-256 hashes rather than `null` or shortened placeholders. 5. Validate the manifest schema and reject unknown properties, absolute paths, path traversal components, and non-string hash values. 6. Restrict manifest file names to a hardcoded allowlist. 7. Verify the manifest before relying on any values from it. 8. Treat unreadable, malformed, or unsigned manifests as failed integrity checks without executing their contents. 9. Add tests proving that JavaScript expressions in manifest content are treated as invalid data and never executed. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
send.js:275
Finding
Unauthenticated Plaintext File Transfer Allows Token Disclosure and Content Substitution<![CDATA[ ## Vulnerability Details **File Location**: `send.js:275-291`; related receiver behavior at `receive.js:166-169` and `receive.js:278-286` **Vulnerability Type**: Plaintext transmission of bearer credentials and file data without cryptographic integrity **Risk Level**: Medium ### Vulnerable Code The sender explicitly advertises a plaintext HTTP endpoint: ```javascript server.listen(args.port, '0.0.0.0', () => { const address = server.address(); const port = address.port; // Get network interfaces const interfaces = os.networkInterfaces(); let ip = '127.0.0.1'; // Find first non-internal IPv4 address for (const name of Object.keys(interfaces)) { for (const iface of interfaces[name]) { if (iface.family === 'IPv4' && !iface.internal) { ip = iface.address; break; } } if (ip !== '127.0.0.1') break; } const url = `http://${ip}:${port}/transfer`; ``` The receiver places the bearer token in the query string and permits plaintext HTTP: ```javascript // Build full URL with token const fullUrl = `${args.url}?token=${encodeURIComponent(args.token)}`; // Choose http or https module const client = parsedUrl.protocol === 'https:' ? https : http; ``` Transfer integrity is checked only by comparing the received byte count to the peer-provided content length: ```javascript writeStream.on('finish', () => { const duration = (Date.now() - startTime) / 1000; const speed = receivedBytes / duration / 1024 / 1024; // MB/s // Verify received bytes match expected if (totalBytes > 0 && receivedBytes !== totalBytes) { logError('SIZE_MISMATCH', `Received ${receivedBytes} bytes, expected ${totalBytes}`); cleanupAndExit(1); return; } const output = { success: true, bytesReceived: receivedBytes, totalBytes: totalBytes || receivedBytes, duration: Math.round(duration ...[truncated 2359 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require HTTPS rather than advertising or accepting plaintext HTTP. 2. Authenticate node certificates and validate host identities; do not disable TLS certificate validation. 3. Prefer the existing authenticated OpenClaw transport where available. 4. Send bearer credentials in an `Authorization` header rather than a query parameter. 5. Bind every token to the expected source node, destination node, file metadata, expiration time, and single transfer operation. 6. Compute a full SHA-256 digest of the source file and deliver it through an authenticated channel. 7. Verify the digest before reporting success and delete the destination file on any mismatch. 8. For stronger protocol-level protection, authenticate the metadata and stream with an HMAC or authenticated encryption. 9. Avoid logging tokens and redact authorization data from diagnostics and error messages. 10. Consider binding the sender to an approved network interface and enforce firewall rules limiting access to expected destination nodes. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (19)

Ae1

High
Category
analysis-evasion
Content
1. **Sender** (`send.js`):
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
1. **Sender** (`send.js`):
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
1. **Sender** (`send.js`):
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
2. **Receiver** (`receive.js`):
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
2. **Receiver** (`receive.js`):
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The API examples and problem statement discuss transferring files but do not clearly warn that the destination path will be written and may overwrite existing data. In practice, file-transfer primitives that omit overwrite/creation semantics can lead to unintended data loss or destructive writes when used by agents or automation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
**Implementation:**
1. Include `send.js`, `receive.js`, `ensure-installed.js` in core resources
2. Add `nodes.transfer()` method to SDK
3. Auto-deploy scripts on first transfer attempt
4. Cache installation status in node metadata

```javascript
Confidence
90% confidence
Finding
Auto-deployment on first use is an autonomous action that causes code to be installed on remote nodes without a clear interactive authorization step. In security-sensitive infrastructure, this behavior can bypass normal approval workflows and make accidental or unauthorized lateral changes easier.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The proposal explicitly recommends auto-deploying helper scripts to remote nodes on first transfer attempt, which changes remote systems without an explicit consent or warning boundary. In an agent environment, silent deployment expands the blast radius of a single transfer request and can violate operator expectations, change-management controls, or node-hardening policies.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
**Pros:**
- Core knows about transfers
- Scripts auto-deployed
- Clean API for users

---
Confidence
85% confidence
Finding
Describing scripts as 'auto-deployed' normalizes autonomous remote modification as part of the feature design. In the context of an agent skill, that increases risk because the feature can initiate software placement on additional systems beyond the user's immediate intent of moving a file.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
1. Add `nodes.transfer()` to SDK (wrapper around skill)
2. Include scripts in core distribution
3. Auto-deployment on first use
4. Deprecate manual installation

### Phase 3: Native Protocol
Confidence
90% confidence
Finding
The migration plan includes auto-deployment on first use, which preserves a pattern of autonomous remote changes as the system evolves. This is dangerous because it embeds remote installation into routine file-transfer operations, making privilege misuse or accidental deployment more likely at scale.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
3. **Performance**: 100x+ improvement over current methods
4. **Safety**: Token-based security, automatic cleanup

**Recommendation:** Integrate as `nodes.transfer()` with auto-deployment of helper scripts, planning for native protocol implementation in future releases.

---
Confidence
88% confidence
Finding
The recommendation endorses auto-deployment of helper scripts as the preferred integration path, reinforcing unattended remote code placement as a standard workflow. In an agent-driven environment, that can facilitate broader unintended system modification and weakens the principle of least surprise for operators.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The report explicitly instructs operators to run PowerShell with `-ExecutionPolicy Bypass`, including sending the script body for remote execution via `nodes.invoke`. Even though this is documentation rather than executable code, it normalizes disabling a Windows safety control and provides no warning, signature verification, or trust validation for the deployed script, which increases the chance that tampered or incorrect content will be executed remotely.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
This markdown file documents deploying scripts to a node and transferring files between nodes, including writing to a destination path. While these actions are the skill's purpose, the README does not include any explicit warning about network data transmission, destination-file overwrite risk, or operational impact on target nodes.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The documentation explicitly shows `receive.js` writing attacker- or operator-specified data to an arbitrary `outputPath`, but it does not clearly warn that this path can target sensitive filesystem locations or overwrite existing files depending on implementation and privileges. In an agent/node environment, users may copy-paste examples into automation, so missing safety guidance increases the chance of unintended file placement, destructive overwrites, or persistence via dropped files in privileged locations.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The script calls require(versionPath) on a file located inside a user-supplied target directory, which executes arbitrary JavaScript from that directory during what is documented as a simple installation check. This creates a code-execution primitive if an attacker can control or influence the target directory contents, and the understated documentation increases the chance that operators will run it in unsafe contexts.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The example invokes a receiver that writes transferred data directly to a caller-supplied destination path with no validation, overwrite confirmation, or safety guardrails shown in this workflow. In an agent context, this can lead to unintended file overwrite or modification of sensitive paths if the destination path is wrong, attacker-influenced, or resolves to an important file.

Description-Behavior Mismatch

Medium
Confidence
88% confidence
Finding
The package metadata presents the skill as only providing file transfer functionality, but the published file list includes installation and deployment-related scripts such as ensure-installed.js and deploy.js. This scope mismatch can mislead reviewers and users about the package's real capabilities, increasing supply-chain risk because higher-impact behaviors may be overlooked or implicitly trusted during installation or use.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The script binds an HTTP file server to 0.0.0.0 and prints a usable URL and bearer-style token, which makes the file reachable from any network that can access the host. While the random token provides access control, there is no explicit warning, interface restriction, TLS, or narrowing of allowed clients, so sensitive local files could be exposed unintentionally or intercepted on untrusted networks.

Natural-Language Policy Violations

Low
Confidence
77% confidence
Finding
The natural-language content and examples center on Windows-specific conventions, including explicit acknowledgment that deployment currently uses PowerShell. Because the document does not clearly frame this as an intentionally Windows-only or region-specific tool, it risks an unjustified platform/locale constraint.

Static analysis

No suspicious patterns detected.