Back to skill

Security audit

Local Claw Skill Nest Client

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent private skill-repository client, but its install/update path can write outside the intended skills folder or execute unsafe archive handling when the configured repository is malicious or compromised.

Install only if you control and trust the configured Claw Skill Nest server. Avoid remote plaintext HTTP endpoints, replace the default API key, and treat install/update as persistent filesystem modification. The client should validate skill names, filenames, archive entries, and extracted paths before broad use.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/manage_local_claw_skill_nest.ts:95
Finding
PowerShell Command Injection Through an Unvalidated Skill Name<![CDATA[ ## Vulnerability Details **File Location**: `scripts/manage_local_claw_skill_nest.ts`, lines 95-103 **Vulnerability Type**: PowerShell command injection **Risk Level**: High ### Vulnerable Code ```ts async function extractZip(archivePath: string, targetDir: string): Promise<boolean> { try { if (process.platform === 'win32') { await run('powershell', [ '-NoProfile', '-Command', `Expand-Archive -Path \"${archivePath}\" -DestinationPath \"${targetDir}\" -Force`, ]); return true; } ``` The affected destination is constructed from the externally influenced Skill name: ```ts const skillDir = join(SKILLS_DIR, skillName); ``` ### Technical Analysis On Windows, `targetDir` is interpolated directly into a string passed to PowerShell's `-Command` argument. The backslashes before the double quotes are JavaScript string escapes; they do not provide PowerShell-safe escaping in the resulting command. The `targetDir` value includes `skillName`. The name is supplied through a command-line argument and must also match a name returned by the configured repository. A malicious or compromised repository can publish a specially crafted name containing a quotation mark and PowerShell syntax. If that name is selected for installation, the injected syntax becomes part of the PowerShell program. Using `spawn()` does not prevent this vulnerability because PowerShell is intentionally invoked with `-Command`, causing the supplied string to be interpreted as executable PowerShell source. ### Attack Path 1. An attacker controls or compromises the configured private Skill repository. 2. The repository returns a Skill whose `name` contains PowerShell metacharacters and injected commands. 3. The user installs that Skill using its exact repository-provided name. 4. `installSkill()` incorporates the name into `skillDir`. 5. `extractZip()` interpolates that directory into a PowerShell `-Command` string. 6. PowerShell parses and ...[truncated 423 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not construct executable PowerShell source using interpolated values. - Prefer a maintained archive library that accepts paths as ordinary API parameters and supports validation of archive entries. - If PowerShell must be used, invoke a fixed script and pass paths as properly bound parameters rather than embedding them in `-Command`. - Restrict Skill names to a conservative identifier format, such as `^[A-Za-z0-9._-]+$`. - Resolve and validate the destination path before extraction, ensuring it remains under the configured Skills directory. - Add Windows-specific tests containing quotes, semicolons, dollar signs, backticks, and line breaks in repository metadata. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/manage_local_claw_skill_nest.ts:120
Finding
Path Traversal Through Skill Names and Repository-Provided Filenames<![CDATA[ ## Vulnerability Details **File Location**: `scripts/manage_local_claw_skill_nest.ts`, lines 120-145 **Vulnerability Type**: Unrestricted filesystem path construction **Risk Level**: High ### Vulnerable Code ```ts const skillDir = join(SKILLS_DIR, skillName); await mkdir(skillDir, { recursive: true }); const tmpRoot = await mkdtemp(join(tmpdir(), 'claw-skill-nest-')); const ext = extname(skill.originalName ?? '').toLowerCase() || '.bin'; const tmpFile = join(tmpRoot, `download${ext}`); try { const fileBuf = await downloadSkillFile(skill.id); await writeFile(tmpFile, fileBuf); if (ext === '.zip') { const ok = await extractZip(tmpFile, skillDir); if (!ok) { const fallback = join(skillDir, skill.originalName || `${skillName}.zip`); await copyFile(tmpFile, fallback); } } else { const fallback = join(skillDir, skill.originalName || `${skillName}${ext}`); await copyFile(tmpFile, fallback); } ``` ### Technical Analysis Both `skillName` and `skill.originalName` are used as path components without validating that they are safe basenames. A Skill name containing parent-directory components such as `../` can cause `skillDir` to resolve outside `~/.openclaw/workspace/skills`. In addition, a repository-controlled `originalName` containing traversal components can cause the fallback copy operation to write outside the selected Skill directory. Checking the filename extension does not make the path safe. The implementation does not canonicalize the completed destination or verify that it remains inside the intended installation root. ### Attack Path 1. An attacker controls or compromises the configured Skill repository. 2. The attacker publishes repository metadata containing traversal components in `name` or `originalName`. 3. A user requests installation of the affected Skill. 4. The client joins the untrusted value with `SKILLS_DIR` or `skillDir`. 5. Files or directories are created outside `~/.openclaw/workspac ...[truncated 534 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Enforce a strict allowlist for Skill identifiers, such as `^[A-Za-z0-9._-]+$`, and explicitly reject `.` and `..`. - Convert `originalName` to a basename and reject values that differ from their basename. - Use `resolve()` to canonicalize the installation root and every destination. - Verify containment using a separator-aware check before creating or copying files. The resolved destination must be equal to or located beneath the resolved installation root. - Reject absolute paths, drive-qualified paths, UNC paths, parent-directory components, NUL characters, and platform-specific path separators. - Store downloaded files under server-independent local names rather than trusting `originalName`. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/manage_local_claw_skill_nest.ts:95
Finding
Untrusted ZIP Archives Are Extracted Without Entry or Resource Validation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/manage_local_claw_skill_nest.ts`, lines 95-112 **Vulnerability Type**: Unsafe archive extraction **Risk Level**: High ### Vulnerable Code ```ts async function extractZip(archivePath: string, targetDir: string): Promise<boolean> { try { if (process.platform === 'win32') { await run('powershell', [ '-NoProfile', '-Command', `Expand-Archive -Path \"${archivePath}\" -DestinationPath \"${targetDir}\" -Force`, ]); return true; } if (existsSync('/usr/bin/unzip') || existsSync('/bin/unzip')) { await run('unzip', ['-o', archivePath, '-d', targetDir]); return true; } } catch { return false; } return false; } ``` ### Technical Analysis Archives downloaded from the configured repository are passed directly to platform-specific extraction tools. The client does not inspect archive entries before extraction and does not enforce restrictions on: - Absolute or parent-relative entry paths. - Symbolic links and other special entries. - The number of archive entries. - Per-file or total expanded size. - Compression ratios. - Overwrites of existing files in the destination. Although individual extraction tools may implement some traversal protections, the implementation relies on platform-dependent behavior rather than enforcing its own security boundary. The `-o` and `-Force` options also permit replacement of existing destination files. ### Attack Path 1. An attacker controls or compromises the configured repository. 2. The attacker supplies a malicious ZIP archive containing dangerous paths, links, a very large expanded payload, or a high compression ratio. 3. The user installs or updates the Skill. 4. The archive is downloaded and passed directly to `unzip` or `Expand-Archive`. 5. Depending on extractor behavior, malicious entries may overwrite files or escape intended paths. Independently, a decompression bomb can consume exc ...[truncated 483 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Inspect every archive entry before extraction. - Reject absolute paths, drive-qualified paths, UNC paths, parent-directory traversal, NUL characters, and entries whose resolved destinations leave the staging directory. - Reject symbolic links, hard links, device files, and other special entries unless they are explicitly required and safely handled. - Enforce limits on entry count, individual uncompressed size, total uncompressed size, and compression ratio. - Extract into a newly created staging directory rather than directly into an existing Skill directory. - Validate staged content and then atomically replace the final Skill directory. - Avoid overwrite flags against an existing installation. - Use one maintained, cross-platform archive library to obtain consistent validation behavior. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/manage_local_claw_skill_nest.ts:15
Finding
API Credential Uses a Hardcoded Default and May Be Transmitted Over Plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `scripts/manage_local_claw_skill_nest.ts`, lines 15-16 **Vulnerability Type**: Hardcoded shared credential and insecure transport configuration **Risk Level**: Medium ### Vulnerable Code ```ts const SKILLHUB_URL = process.env.SKILLHUB_URL ?? 'http://localhost:17890'; const SKILLHUB_API_KEY = process.env.SKILLHUB_API_KEY ?? 'claw-skill-nest-secret-key'; ``` The credential is transmitted in request headers: ```ts const res = await fetch(`${SKILLHUB_URL}${path}`, { headers: { 'X-API-Key': SKILLHUB_API_KEY }, }); ``` ```ts const res = await fetch(`${SKILLHUB_URL}/api/skills/${skillId}/download`, { headers: { 'X-API-Key': SKILLHUB_API_KEY }, }); ``` ```ts const res = await fetch(`${SKILLHUB_URL}/api/skills/upload`, { method: 'POST', headers: { 'X-API-Key': SKILLHUB_API_KEY }, body: form, }); ``` ### Technical Analysis The client silently falls back to a public, predictable API key. If the corresponding server also accepts this documented default, the key provides no meaningful authentication. The default URL uses HTTP. Loopback HTTP does not traverse an external network under normal conditions, but `SKILLHUB_URL` accepts arbitrary destinations without requiring TLS or validating that a plaintext destination is loopback-only. When configured with a remote HTTP service, the API key and uploaded Skill archive are sent without transport encryption. This network activity is necessary for the declared repository-client functionality, but the credential fallback and unrestricted plaintext transport exceed the minimum security controls needed for that functionality. ### Attack Path **Predictable credential path:** 1. A repository deployment retains the default API key. 2. An attacker learns the key from this publicly available client source. 3. The attacker authenticates to the repository using the same shared value. 4. The attacker accesses any repository operations authorized to that key. **Plain ...[truncated 799 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the hardcoded API-key fallback and fail closed when `SKILLHUB_API_KEY` is missing. - Reject the known default value if compatibility requires temporarily retaining it. - Generate unique, high-entropy credentials for each deployment or user. - Parse `SKILLHUB_URL` with the standard URL API and require HTTPS for every non-loopback destination. - Permit HTTP only for explicitly recognized loopback hosts such as `127.0.0.1`, `[::1]`, and a carefully validated `localhost`. - Consider enforcing an administrator-configured host allowlist. - Use separate credentials with least-privilege scopes for listing, downloading, and uploading where supported. - Provide certificate-validation and private-CA configuration guidance for private deployments. - Avoid including server response bodies in errors where they may expose sensitive server details. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:53
Finding
Documentation Executes an Unpinned Runtime Package Through npx<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 53-57 **Vulnerability Type**: Unpinned executable dependency **Risk Level**: Medium ### Vulnerable Code ```text - General script: `scripts/manage_local_claw_skill_nest.ts` - Execution method: - `npx tsx scripts/manage_local_claw_skill_nest.ts list` - `npx tsx scripts/manage_local_claw_skill_nest.ts install <name>` - `npx tsx scripts/manage_local_claw_skill_nest.ts update <name>` - `npx tsx scripts/manage_local_claw_skill_nest.ts upload <local-file-path> [skill-name] [description]` ``` The displayed command names above are English translations of the documented operations; the security-relevant invocation is the unversioned `npx tsx` command. ### Technical Analysis The documented execution method invokes `tsx` through `npx` without a pinned version, committed lockfile, or integrity constraint. If `tsx` is unavailable locally, `npx` may retrieve executable package content from the configured package registry. Consequently, the code executed before this audited script starts can change independently of the Skill package. The effective runtime therefore depends on mutable registry state and the user's registry configuration. ### Attack Path 1. A user follows the documented `npx tsx` command. 2. No trusted, locally pinned `tsx` installation is available. 3. `npx` resolves and downloads a package version from the configured registry. 4. A compromised registry account, registry response, local registry configuration, or malicious package release supplies altered package content. 5. The downloaded package executes with the invoking user's privileges before or while launching the audited script. ### Impact Assessment A compromised runtime package can execute arbitrary code with the user's privileges. It could access local files and environment variables, including `SKILLHUB_API_KEY`, alter uploaded archives, replace downloaded content, or modify the user workspace. Exploitation depe ...[truncated 75 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Declare an audited `tsx` version in project dependencies. - Commit the package manifest and lockfile with integrity metadata. - Invoke the project-local executable rather than allowing `npx` to resolve an unspecified package dynamically. - Use reproducible installation commands that honor the lockfile, such as a frozen or clean dependency installation. - Pin the exact dependency version rather than a floating range where practical. - Configure an approved package registry and apply dependency integrity and provenance verification. - For distribution, consider compiling the TypeScript script into JavaScript so users do not need to download a runtime package when invoking the Skill. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (10)

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill documents access to environment variables and a local/private network service, but it does not declare any explicit tool scope or permissions boundaries. That makes the skill's operational capabilities less transparent to users and runtime policy, increasing the chance of unintended secret access or network actions against the local Skill Nest service.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The skill requires `SKILLHUB_URL` and `SKILLHUB_API_KEY` and communicates with a local/private service, but it does not clearly warn users that data and credentials will be transmitted to that service. Even though the target is described as local/private, authenticated network communication can still expose sensitive content or secrets if the service endpoint is misconfigured or untrusted.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
Using `npx tsx` without pinning a specific version allows execution of whatever package version is resolved at runtime. In a compromised registry, poisoned cache, or dependency-confusion scenario, this can result in arbitrary code execution on the local machine when the documented command is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
Using `npx tsx` without pinning a specific version allows execution of whatever package version is resolved at runtime. In a compromised registry, poisoned cache, or dependency-confusion scenario, this can result in arbitrary code execution on the local machine when the documented command is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
Using `npx tsx` without pinning a specific version allows execution of whatever package version is resolved at runtime. In a compromised registry, poisoned cache, or dependency-confusion scenario, this can result in arbitrary code execution on the local machine when the documented command is run.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
Using `npx tsx` without pinning a specific version allows execution of whatever package version is resolved at runtime. In a compromised registry, poisoned cache, or dependency-confusion scenario, this can result in arbitrary code execution on the local machine when the documented command is run.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The skill states that installation writes into `~/.openclaw/workspace/skills/<name>` but does not present a clear user-facing warning that install and update operations modify the local filesystem. For a skill that downloads or updates content from a local/private repository, lack of an explicit modification warning can mislead users about persistence and overwrite risk.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
The script hardcodes Chinese for error messages, console output, usage text, and even the accepted command names such as 安装, 更新, 列出, and 上传. This imposes a specific language/locale on all users with no opt-in or alternative, which matches the language-policy violation criteria.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
The script downloads archives from the configured Nest server and then invokes host-native extraction tools (PowerShell or unzip) on that untrusted content. This expands the trust boundary from simple file transfer to local processing of attacker-controlled archives, increasing risk of archive-based attacks such as path traversal, overwrite of files under the skills directory, or abuse of external tooling behavior on malformed archives.

Intent-Code Divergence

Low
Confidence
93% confidence
Finding
The manifest/documentation says the skill is used when installing or updating skills from the local/private claw-skill-nest. In code, '更新' is implemented by directly calling installSkill, which fetches the named skill from /api/skills and downloads it, rather than performing a distinct update flow or checking an already-installed local skill state.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.env_credential_access

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/manage_local_claw_skill_nest.ts:21

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/manage_local_claw_skill_nest.ts:15