Back to skill

Security audit

OpenClaw Consensus

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to run the advertised OpenClaw consensus workflow, but it needs review because it persists plaintext briefs and model outputs while making an unsupported gitignore safety claim.

Review before installing. Use this only for briefs you are willing to send to the selected configured model providers and store locally in plaintext. Add or verify a /runs/ gitignore rule, avoid confidential prompts unless you control retention, and do not use --run-root paths supplied by untrusted parties.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
src/cli.mjs:359
Finding

Explicit Run Root Validation Can Be Bypassed with Symbolic Links and TOCTOU Replacement

Content
View full analysis
0) { throw new Error(`--run-root must be empty or non-existent (refusing to write into a non-empty directory): ${resolved}`); } return resolved; } fs.mkdirSync(resolved, { recursive: true }); return resolved; } // Default path: collision-safe under runs/. const stamp = new Date().toISOString().replace(/[:]/g, '-').replace(/\.\d{3}Z$/, 'Z'); const slug = slugify(label || brief.slice(0, 60) || 'run'); fs.mkdirSync(DEFAULT_RUNS_DIR, { recursive: true }); const base = path.join(DEFAULT_RUNS_DIR, `${stamp}-${slug}`); ``` The associated validation only examines the lexical path: ```javascript function validateExplicitRunRoot(runRoot) { if (typeof runRoot !== 'string' || runRoot === '') { throw new Error('--run-root must be a non-empty path.'); } if (runRoot.includes('\0')) { throw new Error('--run-root contains a null byte.'); } const resolved = path.resolve(runRoot); if (resolved === '/' || resolved === '') { throw new Error('--run-root cannot be the filesystem root.'); } for (const prefix of FORBIDDEN_RUN_ROOT_PREFIXES) { if (resolved === prefix || resolved.startsWith(`${prefix}/`)) { throw new Error(`--run-root is inside a protected system path (${prefix}): ${resolved}`); } } return resolved; } ``` ### Technical Analysis `path.res ...[truncated 2728 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
README.md:80
Finding

Sensitive Run Artifacts Are Persisted in the Repository Without the Documented Git Exclusion

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • 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 (6)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description says the skill runs a 2-round cross-model deliberation via a local runtime. The provided code does not perform deliberation or invoke any consensus runtime. Instead, it is an installation script that copies the repository into a workspace skills directory, removes and recreates the target directory, and writes an install marker file. This is a materially different primary purpose and includes undeclared filesystem modification and deployment behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description says the skill performs a fixed two-round cross-model deliberation via the local OpenClaw Consensus runtime. The supplied code does something materially different: it is a Bash test runner that iterates over specific test files and invokes them with Node, reporting pass/fail status. The comments explicitly state the tests are offline, deterministic, and do not invoke openclaw or any provider. This is a clear description-to-behavior mismatch in primary purpose and implemented capabilities.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared purpose describes executing a 2-round cross-model deliberation via a local consensus runtime. The supplied code does not run any deliberation logic, invoke models, or operate as a runtime. Instead, it locates a workspace skill directory, verifies the presence of a marker file, and recursively deletes the target directory. This is a materially different primary purpose and includes an undeclared destructive filesystem capability.

Content

No source excerpt is available for this finding.

YARA rule 'agent_skill_prompt_injection_hidden_instructions': Prompt injection or hidden instructions embedded in AI agent skill text [agent_skills]

High
Category
YARA Match
Confidence
80% confidence
Finding

YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Content

Scanner excerpt · validation/tests/cli-helpers.test.mjs (reported line 4)May include surrounding context.

js
#!/usr/bin/env node
// Lightweight self-checks for src/cli.mjs helpers.
//
// These do not exercise the openclaw CLI or any model calls — they only
// assert behavior of pure helper functions added/hardened in the recent
// security pass. Run with: node validation/tests/cli-helpers.test.mjs

import assert from 'node:assert/strict';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const here = path.dirname(fileURLToPath(import.meta.url));
const cliPath = path.resolve(here, '..', '..', 'src', 'cli.mjs');

const cli = await import(cliPath);

const cases = [];
function test(name, fn) {
  cases.push({ name, fn });
}

// ---- parseFlags ----
test('parseFlags: basic key/value', () => {
  const ou

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The spec explicitly says the same user brief is sent to multiple LLM providers and that artifacts are stored durably, but it does not require any disclosure, consent, retention controls, or data-handling limits. This creates a real privacy and compliance risk because users may unknowingly submit sensitive, regulated, or proprietary information that is replicated across third parties and retained locally.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
src/cli.mjs:551

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
validation/tests/cli-cli.test.mjs:29