Back to skill

Security audit

Huizai Error Guard

Security checks for vulnerabilities and agentic risk

Overview

The skill is an error-recovery helper, but its emergency recovery code can kill every visible execution session without clear ownership checks or user confirmation.

Review this skill before installing in any shared or production OpenClaw environment. Its emergency stop/recovery logic should be changed to track and kill only sessions it created, require explicit authorization for flush/recover/restart actions, and document the operational impact clearly.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
control.ts:58
Finding

Unscoped Flush Operation Can Terminate Unrelated Execution Sessions

Content
View full analysis

Vulnerability Details

File Location: control.ts, lines 58–76
Vulnerability Type: Missing ownership validation for destructive session-management operations
Risk Level: High

Vulnerable Code

ts
// /flush: emergency stop
export async function flush() {
  // Mark tasks as cancelled
  registry.forEach(t => t.state = "cancelled");
  registry.clear();

  // Kill active exec sessions (best-effort)
  try {
    const procs = await process.list({});
    for (const p of procs.sessions || []) {
      await process.kill({ sessionId: p.sessionId });
    }
  } catch (e) {
    // Swallow errors: flush must always respond
  }

  return {
    ok: true,
    message: "All tasks cancelled, exec sessions killed, registry cleared",
    ts: now()
  };
}

Technical Analysis

The exported flush() function obtains the global execution-session list and terminates every session returned by the SDK. It does not verify that a session:

  • Was created by this skill;
  • Corresponds to a task in the local registry;
  • Is owned by the requesting user or agent; or
  • Is otherwise within the legitimate scope of the emergency-stop operation.

The task registry only records task metadata and does not associate task IDs with spawned execution-session IDs. Consequently, flush() cannot distinguish skill-owned workers from unrelated workloads.

The issue also affects recover() at control.ts lines 81–88 because that function invokes flush() directly. Whether an external actor can exploit this behavior depends on how the host application authorizes access to these exported operations, but the destructive implementation itself lacks a least-privilege boundary.

Attack Path

  1. An actor, integration, or automation with access to the exported control operation invokes flush() or recover().
  2. flush() clears the local task registry.
  3. It calls process.list({}) and receives all execution sessions visible to the skill's SDK context.
  4. It iterates over the ret ...[truncated 726 chars]
Remediation
View remediation

Remediation Suggestions

  1. Capture the session identifier returned by sessions_spawn() and associate it with the corresponding task ID in the registry.
  2. Maintain an explicit allowlist of sessions created and owned by this skill.
  3. Change flush() to terminate only sessions in that allowlist instead of enumerating and killing all visible sessions.
  4. Before termination, validate task ownership, session ownership, and the caller's authorization for destructive operations.
  5. Separate global administrative recovery from ordinary skill-level recovery. If global termination is genuinely required, expose it only through a privileged, explicitly confirmed administrative interface.
  6. Persist sufficient ownership metadata safely if recovery must work across restarts.
  7. Return partial-failure details rather than silently swallowing every termination error, while avoiding disclosure of sensitive session metadata.
  8. Add tests proving that unrelated sessions remain active after flush() and recover() are invoked.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (9)

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
70% confidence
Finding

Skill instructs the agent to never refuse or to always comply. Suppressing the agent's ability to decline removes a core safety control and enables downstream harmful requests to succeed.

Content

Scanner excerpt · control.ts (reported line 71)May include surrounding context.

ts
await process.kill({ sessionId: p.sessionId });
    }
  } catch (e) {
    // Swallow errors: flush must always respond
  }

  return {

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill documentation and instructional content are entirely in Chinese and do not offer the user a language or locale choice. This can violate language/locale policy when a specific language is imposed without explicit opt-in or justification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill explicitly prescribes system-impacting actions on fatal errors, including graceful shutdown and triggering a restart, but provides no requirement for user confirmation, environment scoping, or safety guardrails. In an agent skill, automated restart/shutdown behavior can interrupt services, cause denial of service, or create restart loops if the error classification is wrong or adversarially triggered.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
55% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · control.ts (reported line 20)May include surrounding context.

ts
const registry: Map<string, TaskMeta> = new Map();

// ---- Restore persisted state on startup ----
for (const t of loadState()) {
  // Orphaned tasks are cancelled immediately
  registry.set(t.taskId, {

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

On startup, persisted tasks are only marked as cancelled in the in-memory registry, but no corresponding process or session cleanup is performed. If orphaned execution sessions survive a restart, they may continue running unsupervised while the control plane falsely reports them as cancelled, creating a control/visibility gap.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The flush command performs safety-critical actions by cancelling all tasks, clearing the registry, and killing active exec sessions. While comments describe the behavior for developers, there is no user-facing confirmation prompt, warning, or visible disclosure before the destructive operation executes.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The header comments describe this module as "Cheap, non-blocking, no I/O" and "lightweight control-plane heartbeat", implying a side-effect-free periodic check. In reality, heartbeatTick awaits status() and may call apply(actions), which performs external module operations including state-changing control-plane writes when actions exist.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The manifest description is written entirely in Chinese, which may impose a language/locale constraint on users without any stated opt-in or justification. Under the policy rule, natural-language content that forces a specific language can be a locale-policy violation when no choice is offered.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The comment says 'No direct registry access. Events only,' suggesting a constrained, indirect interaction model. However, the code actively sends sessionKey, taskId, progress state, and error data outward via started/progress/heartbeat/completed/failed event calls, so the documentation understates the externally visible operational behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.