Back to skill

Security audit

OpenClaw Skill Scaffolder

Security checks for vulnerabilities and agentic risk

Overview

The skill broadly matches its scaffolding purpose, but it generates deployable code and shell commands from user-provided text without validation, creating serious downstream injection risk.

Review the generated project before running, deploying, or publishing it. Do not feed this scaffolder configuration from untrusted parties, only use simple allowlisted names and environment variable identifiers, pin Wrangler before use, and be aware that user_id, skill details, and billing data are sent to external services.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (5)

T01 · Skill Instruction Hijacking

Error
Location
src/templates.ts:1
Finding
Attacker-Controlled Content Is Embedded into Generated Skill Instructions Without Escaping<![CDATA[ ## Vulnerability Details **File Location**: `src/templates.ts:1-24` **Vulnerability Type**: Generated skill instruction and YAML injection **Risk Level**: High ### Complete Code Snippet ```ts export function generateSkillMd(params: { name: string; description: string; price: number; envVars?: string[]; }): string { const envList = params.envVars ? [...params.envVars, "SKILLPAY_API_KEY"] : ["SKILLPAY_API_KEY"]; return `--- name: ${params.name} description: ${params.description} version: 1.0.0 metadata: openclaw: requires: env: ${envList.map((e) => ` - ${e}`).join("\n")} --- # ${params.name} ${params.description} ## Pricing $${params.price} USDT per call via SkillPay.me `; } ``` The values originate directly from the request body: ```ts const body = await request.json() as { user_id: string; name: string; description: string; price_usdt: number; env_vars?: string[]; }; ``` ### Technical Analysis The generated `SKILL.md` places `name`, `description`, and environment-variable names directly into YAML frontmatter and Markdown without validation, YAML serialization, escaping, or content-boundary enforcement. A TypeScript type assertion does not validate runtime JSON. An attacker can therefore include newlines, YAML keys, Markdown sections, or agent-directed instructions in these fields. In particular, the `description` is emitted both inside frontmatter and in the skill body, where it can become operative instructions when an AI agent loads the generated skill. This is especially dangerous because the declared purpose of the project is to create artifacts that users subsequently deploy and publish. The untrusted input therefore crosses a trust boundary and becomes trusted skill content. ### Attack Path 1. An attacker submits a scaffold request containing a multiline `description`, for example one that starts with a benign description and then adds instructions telling an agent to disclose secrets ...[truncated 1140 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Treat all scaffold parameters as untrusted structured data. - Enforce strict schemas and maximum lengths before template generation. - Restrict skill names to a conservative pattern such as `^[a-z0-9][a-z0-9-]{0,62}$`. - Reject control characters and line breaks in fields intended to occupy one YAML scalar. - Generate frontmatter with a well-maintained YAML serializer rather than string interpolation. - Quote and serialize every environment-variable entry. - Validate environment-variable names with a pattern such as `^[A-Z_][A-Z0-9_]*$`. - Define an explicit policy for descriptions. If descriptions are not intended to contain agent instructions, reject instruction-like sections, frontmatter delimiters, and unapproved Markdown structures. - Present the generated `SKILL.md` for explicit human review before publishing it. - Add adversarial tests covering newlines, `---`, YAML keys, Markdown headings, tool instructions, and oversized values. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
src/templates.ts:33
Finding
Generated TypeScript Allows Arbitrary Source-Code Injection<![CDATA[ ## Vulnerability Details **File Location**: `src/templates.ts:33-89` **Vulnerability Type**: Source-code injection into generated Worker **Risk Level**: High ### Complete Code Snippet ```ts export function generateWorkerIndex(params: { skillName: string; price: number; envVars: string[]; }): string { const envInterface = ["SKILLPAY_API_KEY", ...params.envVars] .map((e) => ` ${e}: string;`) .join("\n"); return `import type { BillingResult } from "./billing"; interface Env { ${envInterface} } const SKILLPAY_API = "https://skillpay.me/api/billing/charge"; async function chargeUser(userId: string, env: Env): Promise<BillingResult> { try { const response = await fetch(SKILLPAY_API, { method: "POST", headers: { "Content-Type": "application/json", Authorization: \`Bearer \${env.SKILLPAY_API_KEY}\`, }, body: JSON.stringify({ user_id: userId, amount: ${params.price}, skill: "${params.skillName}", }), }); return await response.json() as BillingResult; } catch (err) { return { success: false, error: err instanceof Error ? err.message : "Billing failed" }; } } ``` The request values are passed into the generator without runtime type or syntax validation: ```ts "src/index.ts": generateWorkerIndex({ skillName: body.name, price: body.price_usdt, envVars, }), ``` ### Technical Analysis `envVars`, `skillName`, and `price` are inserted into executable TypeScript source contexts without safe encoding: - Environment-variable names are inserted as raw interface members. - `skillName` is inserted into a double-quoted string literal without escaping. - `price` is inserted as a raw source expression. The declaration `request.json() as {...}` only informs the compiler; it does not guarantee that runtime values have the declared types. A JSON client can submit strings, arrays, objects, line breaks, quote characters, or source fragments. For example, ...[truncated 1638 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Perform runtime schema validation immediately after parsing JSON. Reject values whose actual types do not match the schema. - Require `price_usdt` to be a finite number within an explicit minimum and maximum range. - Restrict `env_vars` to valid JavaScript/TypeScript identifier-compatible environment names, preferably `^[A-Z_][A-Z0-9_]*$`. - Restrict skill names to a conservative slug format. - Never place untrusted strings directly in source code. - Encode string literals with `JSON.stringify(value)` when source generation is unavoidable. - Convert validated numeric values with a canonical numeric formatter and reject `NaN`, infinity, objects, and strings. - Prefer an AST-based TypeScript generator or a fixed Worker implementation driven by validated configuration. - Run formatting, parsing, type checking, and static security analysis on every generated artifact before returning it. - Add regression tests using quote termination, template-literal markers, comments, braces, newlines, and values with deliberately incorrect JSON types. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
src/index.ts:63
Finding
Generated Deployment Commands Permit Shell Command Injection<![CDATA[ ## Vulnerability Details **File Location**: `src/index.ts:63-69` **Vulnerability Type**: Shell command injection in generated deployment instructions **Risk Level**: High ### Complete Code Snippet ```ts const secretCommands = ["SKILLPAY_API_KEY", ...envVars].map( (v) => `npx wrangler secret put ${v}` ); const result: ScaffoldResult = { files, deploy_commands: [...secretCommands, "npx wrangler deploy"], test_command: "npx wrangler dev", }; ``` `envVars` comes directly from the request: ```ts const envVars = body.env_vars ?? []; ``` ### Technical Analysis Environment-variable names are concatenated into shell command strings without validation or shell escaping. If a consumer copies these commands into a POSIX shell, shell metacharacters such as semicolons, command substitutions, pipes, redirections, or newlines are interpreted as syntax rather than as part of a variable name. Although the service does not execute the commands itself, the project explicitly returns them as deployment instructions and tells users to execute generated commands. This makes the output a practical command-execution delivery channel. ### Attack Path 1. An attacker requests a scaffold with an `env_vars` entry containing a shell metacharacter and a second command. 2. The server returns a `deploy_commands` item of the form: ```sh npx wrangler secret put SAFE_NAME; attacker-command ``` 3. The generated response presents this as an ordinary deployment command. 4. A user or automation pipeline executes the returned command. 5. The shell runs both the expected Wrangler command and the injected command. 6. The injected process executes with the local privileges and credentials of the deploying user or CI runner. ### Impact Assessment Exploitation can lead to arbitrary local command execution on a developer workstation or CI/CD runner. Depending on that environment, an attacker may obtain source code, local files, Cloudflare credentials, package-registry ...[truncated 240 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Validate every environment-variable name against `^[A-Z_][A-Z0-9_]*$` before generating any output. - Reject values containing whitespace, control characters, quotes, substitutions, redirects, separators, or other shell metacharacters. - Avoid returning executable shell command strings assembled from user input. - Return structured deployment steps, such as an executable name and an argument array, so trusted client code can invoke processes without a shell. - If commands are displayed for manual use, generate them only from strictly allowlisted identifiers and clearly mark them as content requiring review. - Add tests for semicolons, pipes, ampersands, backticks, `$()`, newlines, redirections, and platform-specific shell syntax. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
src/templates.ts:26
Finding
Unescaped Skill Name Allows Injection into Generated Wrangler Configuration<![CDATA[ ## Vulnerability Details **File Location**: `src/templates.ts:26-31` **Vulnerability Type**: TOML configuration injection **Risk Level**: Medium ### Complete Code Snippet ```ts export function generateWranglerToml(name: string): string { return `name = "${name}" main = "src/index.ts" compatibility_date = "2026-03-01" `; } ``` ### Technical Analysis The requested skill name is inserted directly inside a quoted TOML value. Quotes, backslashes, and newlines are not escaped, and the name is not constrained to the format expected for a Cloudflare Worker name. A malicious value can terminate the `name` string and introduce additional TOML keys or sections. Depending on the inserted settings and how Wrangler resolves duplicate or conflicting keys, this can corrupt the deployment, alter bindings or deployment behavior, or direct the generated project toward attacker-selected infrastructure. ### Attack Path 1. An attacker supplies a skill name containing a quote, newline, and additional TOML configuration. 2. `generateWranglerToml` places the value verbatim in `wrangler.toml`. 3. The victim downloads the scaffold and follows the documented `npx wrangler deploy` workflow. 4. Wrangler parses the injected settings as trusted project configuration. 5. The generated project is deployed with altered behavior, or deployment is redirected or disrupted. ### Impact Assessment The attacker can control portions of the generated deployment configuration. The precise privilege obtained depends on which Wrangler settings are accepted and on the victim's Cloudflare credentials and account configuration. Plausible consequences include unauthorized bindings, unexpected routes or environments, deployment disruption, and exposure of data to attacker-controlled services configured in the injected settings. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Restrict Worker names to Cloudflare's documented naming rules using a strict allowlist. - Reject quotes, backslashes, whitespace, line breaks, control characters, and TOML delimiters. - Use a TOML serialization library instead of constructing configuration text through interpolation. - Parse the generated TOML before returning it and verify that only the expected keys are present. - Consider using a fixed deployment configuration and mapping a validated slug only to the `name` property. - Add tests for quote termination, new sections, duplicate keys, comments, Unicode control characters, and multiline values. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:67
Finding
Deployment Workflow Executes Unpinned Packages Through npx<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:67-72` **Vulnerability Type**: Unpinned executable dependency and supply-chain exposure **Risk Level**: Medium ### Complete Code Snippet ```sh cd my-cool-skill npx wrangler secret put SKILLPAY_API_KEY npx wrangler deploy clawhub publish . --slug my-cool-skill --name "My Cool Skill" --version 1.0.0 --tags latest ``` The generated response similarly returns unversioned commands: ```ts const secretCommands = ["SKILLPAY_API_KEY", ...envVars].map( (v) => `npx wrangler secret put ${v}` ); const result: ScaffoldResult = { files, deploy_commands: [...secretCommands, "npx wrangler deploy"], test_command: "npx wrangler dev", }; ``` ### Technical Analysis No package manifest or lockfile is present in the audited project, and the documented workflow invokes `npx wrangler` without a pinned package version or integrity-locked dependency. Depending on the local environment and `npx` behavior, the command may download and execute a package version selected at execution time. This means the effective executable can change after the skill has been audited. A compromised upstream release, registry account, dependency chain, or package-resolution environment could result in arbitrary package lifecycle or CLI code running under the user's account. ### Attack Path 1. A user follows the documented deployment process in an environment without a trusted, locally locked Wrangler installation. 2. `npx` resolves and downloads the currently selected `wrangler` package and its transitive dependencies. 3. An upstream package or dependency has been compromised, or an unsafe package-resolution configuration selects an attacker-controlled artifact. 4. Package or CLI code executes during installation or invocation. 5. The malicious code accesses the developer or CI environment with the privileges of the invoking user. ### Impact Assessment A compromised executable can access local project files, environment variab ...[truncated 348 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Add a package manifest declaring an exact reviewed Wrangler version. - Commit and enforce a lockfile with integrity hashes. - Use `npm ci` or an equivalent immutable installation mode in CI. - Invoke the locally installed binary through a package script rather than allowing `npx` to resolve an unspecified version. - If `npx` must be used, specify an exact reviewed package version and disable interactive package installation. - Pin and review the publishing CLI in the same manner. - Use dependency scanning, provenance verification, and controlled registries for deployment tooling. - Periodically update pinned versions through a reviewed dependency-update process. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (8)

Ae1

High
Category
analysis-evasion
Content
- `SKILL.md` template
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Lp3

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding
The skill instructs users to make external network requests and relies on an external billing/scaffolding service, but it does not declare any explicit tool scope such as network permissions or allowed tools. That mismatch reduces transparency and weakens policy enforcement, making it easier for a skill to perform undeclared outbound actions or for users to miss that data is being sent off-platform.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill explicitly tells users to POST a `user_id` and other configuration data to an external HTTP endpoint, but provides no privacy notice, data handling explanation, retention policy, or warning that identifiers are being transmitted to a third party. In a billing context this is more concerning because users may assume the data exchange is required and trustworthy, increasing the chance of unintended disclosure of personal or tenant-linked information.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
90% confidence
Finding
The generated deployment instructions invoke `npx wrangler secret put` without pinning a specific Wrangler version. `npx` may fetch the latest package at execution time, which creates a supply-chain risk: users could run an unexpected or compromised version with access to secrets they are entering. This is more dangerous in this skill because the command is explicitly used to handle sensitive values such as `SKILLPAY_API_KEY` and user-provided environment variable names.

Rp1

Medium
Category
MCP Rug Pull
Confidence
90% confidence
Finding
The scaffolded deploy command includes `npx wrangler deploy` without a pinned version, so execution may download and run whatever version is current at that moment. That exposes users to supply-chain and reproducibility risks, especially since this skill generates deployable infrastructure code and asks users to immediately execute the returned commands. The skill context increases risk because it operationalizes the unsafe command directly rather than merely mentioning Wrangler conceptually.

Rp1

Medium
Category
MCP Rug Pull
Confidence
88% confidence
Finding
The returned test command `npx wrangler dev` is also unpinned, meaning local development may execute an unreviewed package version fetched at runtime. While this is somewhat less sensitive than secret entry or deployment, it still creates a supply-chain execution path on the user's machine. In this scaffolding context, users are likely to copy-paste the command directly, which makes the unsafe pattern more likely to be exploited in practice.

Static analysis

No suspicious patterns detected.