Back to skill

Security audit

OpenClaw Model Router Skill

Security checks for vulnerabilities and agentic risk

Overview

The skill largely does what it claims, but its cron scheduler can turn a crafted schedule rule ID into shell commands if the generated cron output is installed.

Review before installing. Only use trusted schedule files and rule IDs, and do not install the generated cron preview until rule IDs are restricted to a safe character set or shell-quoted. Also confirm the OpenClaw CLI and any configured auth environment variables are appropriate for the account running scheduler commands.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
src/scheduler.js:48
Finding

Shell and Cron Injection Through Unsanitized Schedule Rule IDs

Content
View full analysis

Vulnerability Details

File Location: src/scheduler.js:48-50, 212-214
Vulnerability Type: Command injection in generated cron entries
Risk Level: Medium

The scheduler validates a rule ID only as a non-empty string:

js
if (!rule.id || typeof rule.id !== 'string') {
  throw new Error('rule.id must be a non-empty string');
}

It later inserts that value directly into shell commands without validation or quoting:

js
lines.push(`# ${rule.id} -> ${rule.model}`);
lines.push(`${startM} ${startH} * * ${rule.days.map(d => DAYS.indexOf(d)).join(',')} node src/cli.js schedule apply --id ${rule.id}`);
lines.push(`${endM} ${endH} * * ${rule.days.map(d => DAYS.indexOf(d)).join(',')} node src/cli.js schedule end --id ${rule.id}`);

Technical Analysis

The schedule add command accepts and persists any non-empty rule ID. When schedule cron is subsequently invoked, buildCronPreview() interpolates the ID directly into generated crontab command lines.

Because the value is neither restricted to a safe identifier grammar nor encoded as a shell argument, an attacker-controlled ID may contain shell metacharacters, command substitutions, whitespace, or newline characters. This can alter the syntax of the generated crontab and append arbitrary commands.

The generated cron output is documented as requiring manual installation, so generating the preview alone does not execute the payload. Exploitation occurs if a user or automated deployment process trusts and installs the generated output.

Attack Path

  1. An attacker gains the ability to invoke schedule add, influence its arguments, or modify a schedule file consumed by the application.
  2. The attacker supplies a malicious rule ID containing shell syntax or a newline followed by an additional cron entry.
  3. The application accepts the ID because validation checks only that it is a non-empty string.
  4. The attacker-controlled value is persist ...[truncated 1047 chars]
Remediation
View remediation

Remediation Suggestions

  1. Enforce a strict allowlist for rule IDs at every input and configuration boundary. For example:

    js
    const SAFE_RULE_ID = /^[A-Za-z0-9_-]+$/;
    
    if (
      typeof rule.id !== 'string' ||
      !SAFE_RULE_ID.test(rule.id)
    ) {
      throw new Error(
        'rule.id may contain only letters, digits, underscores, and hyphens'
      );
    }
    
  2. Explicitly reject control characters, carriage returns, newlines, whitespace, quotes, backticks, dollar signs, semicolons, pipes, redirection operators, and other shell metacharacters.

  3. Do not construct cron shell commands by raw string interpolation. Apply a well-reviewed POSIX shell-argument quoting function to every dynamic argument, even after allowlist validation.

  4. Validate existing schedule files when loading them so that malicious IDs introduced by direct file modification cannot bypass CLI validation.

  5. Generate cron entries from structured, trusted data and clearly separate comments from executable lines. Avoid inserting untrusted content into comments because newline characters can escape the comment context.

  6. Add regression tests covering IDs containing semicolons, pipes, command substitutions, backticks, quotes, spaces, tabs, carriage returns, and newline-injected cron entries.

  7. Document that cron previews must not be installed without validation, and ensure automated deployment processes reject generated output containing unexpected additional lines or commands.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (10)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 43)May include surrounding context.

md
node src/cli.js validate

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 46)May include surrounding context.

md
node src/cli.js validate

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 49)May include surrounding context.

md
node src/cli.js validate

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 50)May include surrounding context.

md
node src/cli.js validate

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 51)May include surrounding context.

md
node src/cli.js validate

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 52)May include surrounding context.

md
node src/cli.js validate

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

The ensureAuth function reads required authentication environment variables from process.env and uses them to gate execution, but the file does not include any user-facing disclosure or explanatory comment about credential access. Access to sensitive environment variables is explicitly in scope for missing-warning review of code files.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The skill executes an external binary via execFileAsync and passes through the full process environment, but this file contains no confirmation prompt, logging, print statement, or explanatory comment/docstring disclosing that behavior. Because subprocess execution is a safety-relevant operation under the rule, this lacks visible user warning within the code.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The configuration fixes operation to the Europe/Rome timezone, which is a locale-specific setting. Because the file provides no indication that this locale is user-selected or justified as region-specific, it may violate the policy against forcing a locale without opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The scheduler formats date parts using a fixed 'en-US' locale in natural-language-related configuration. This enforces a specific locale choice without offering user selection or documenting why that locale is required, which matches the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.