Back to skill

Security audit

Agent Health Monitor

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a disclosed agent health monitor, but it under-discloses that it runs shell commands and executes a hard-coded other skill's lifecycle script.

Review this skill carefully before installing. It does not appear to exfiltrate data or install persistence, but it can inspect local OpenClaw agent/session state, read system resource files, and execute shell commands, including a hard-coded lifecycle script from another skill. Install only if you expect that specific wrapper check and trust the local environment and installed skills.

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

Error
Location
index.js:100
Finding
Shell Command Injection Through the HOME Environment Variable## Vulnerability Details **File Location**: `index.js`, lines 100–101 **Vulnerability Type**: OS command injection through unquoted shell interpolation **Risk Level**: High ### Vulnerable Code ```javascript const wrapperPath = path.join(process.env.HOME, '.openclaw', 'workspace', 'skills', 'feishu-evolver-wrapper'); const output = execSync(`cd ${wrapperPath} && node lifecycle.js status 2>/dev/null || echo "unknown"`, { ``` ### Technical Analysis The value of `process.env.HOME` is used to construct `wrapperPath`, which is then interpolated directly into a command passed to `execSync()`. By default, `execSync()` executes the string through a system shell. Because the path is neither safely quoted nor passed as a separate argument, shell metacharacters contained in `HOME` are interpreted as command syntax. An attacker who can influence the process environment could set `HOME` to a value such as `/tmp/x; attacker_command; #`. When `getWrapperStatus()` executes, the resulting shell command would run `attacker_command` under the identity of the Node.js process. The vulnerable function is reached through `checkHealth()`. It is therefore also indirectly reachable through `getFailedAgents()` and every iteration of `startMonitoring()`. ### Attack Path 1. The attacker gains control over, or can influence, the environment variables supplied when the Agent process or skill runner starts. 2. The attacker sets `HOME` to a value containing shell control characters and an injected command, for example `/tmp/x; attacker_command; #`. 3. A caller invokes `getWrapperStatus()`, `checkHealth()`, `getFailedAgents()`, or `startMonitoring()`. 4. The skill constructs `wrapperPath` from the malicious `HOME` value. 5. `execSync()` passes the interpolated command string to the system shell. 6. The shell interprets the injected metacharacters and executes the attacker-supplied command. Exploitation requires the attacker to influence the runtime ...[truncated 689 chars]
Remediation
## Remediation Suggestions Avoid invoking a shell for this operation. Execute Node.js directly and provide the working directory through the process API: ```javascript const { execFileSync } = require('child_process'); const home = process.env.HOME; if (!home || !path.isAbsolute(home)) { return { status: 'unknown', pid: null }; } const wrapperPath = path.resolve( home, '.openclaw', 'workspace', 'skills', 'feishu-evolver-wrapper' ); const output = execFileSync( process.execPath, ['lifecycle.js', 'status'], { cwd: wrapperPath, encoding: 'utf-8', timeout: 5000, stdio: ['ignore', 'pipe', 'ignore'] } ); ``` Additional hardening measures: 1. Resolve and validate the directory against an explicitly trusted OpenClaw root rather than relying blindly on `HOME`. 2. Confirm that the resolved wrapper path remains inside the expected workspace before execution. 3. Handle command failure in JavaScript instead of using shell operators such as `||` and shell redirection. 4. Use `execFileSync()` or `spawnSync()` with argument arrays for the other fixed commands in the file as a defense-in-depth measure. 5. Run the skill under a least-privileged account with only the filesystem permissions required for health monitoring. 6. Add a regression test using `HOME` values containing spaces and shell metacharacters, verifying that no additional command can execute.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (4)

Lp3

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding
The skill includes executable JavaScript examples that imply runtime/code capabilities, but it does not declare any explicit tool scope or permissions boundary. In practice, missing scope metadata can cause the platform or reviewers to underestimate what the skill may access, increasing the risk of unintended environment or runtime access if the implementation reads environment variables or uses other implicit capabilities.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The trigger scenarios are broad enough to activate on common operational phrases like 'check agents' or generic health/status requests, which can cause the skill to run outside its narrowly intended context. Over-broad activation increases the chance of unintended monitoring actions, data exposure about sessions/agents, or interference with other skills handling unrelated status requests.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The health monitor is not generic: it is hard-coded to inspect a specific unrelated skill path, `feishu-evolver-wrapper`, under the user's home directory. This creates unauthorized cross-skill coupling and gives this skill visibility into and operational dependence on another component outside its stated scope, which is dangerous in a plugin/agent ecosystem because it can be used to probe, interfere with, or make decisions based on another skill's private state.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The skill executes shell commands and directly runs another skill's lifecycle script via `execSync`, which expands its capabilities beyond passive health observation into active command execution. Even though the current command string is mostly fixed, invoking a shell and traversing into another skill directory increases attack surface, trusts external binaries and filesystem layout, and could enable unintended code execution or abuse if the target script or environment is compromised.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
index.js:17