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. ]]>
