Back to skill

Security audit

虾安全

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed local OpenClaw security scanner, with no evidence of exfiltration or destructive behavior, but its real-time monitor appears broken and its local audit files should be handled as sensitive.

Install only if you are comfortable with a Chinese-language local security scanner reading your OpenClaw workspace identity, memory, and skill script files and writing local logs/snapshots under ~/.cik-audit. Treat those logs as sensitive, and do not rely on daemon monitoring until monitor.cjs is fixed and tested.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/monitor.cjs:123
Finding

Fatal Syntax Error Prevents the Security Monitor from Starting

Content
View full analysis

Vulnerability Details

File Location: scripts/monitor.cjs, lines 123-128
Vulnerability Type: Security-monitor availability failure caused by invalid JavaScript syntax
Risk Level: High

Vulnerable Code

js
} else {
  if (state.consecutiveAlerts > 0) {
    log(`✅ 安全问题已修复 (连续${state.consecutiveAlerts}次告警后)");
  }
  state.consecutiveAlerts = 0;
}

The call to log begins a template literal with a backtick but terminates it with a double quotation mark. Consequently, Node.js cannot parse the file.

Technical Analysis

JavaScript parses an entire CommonJS module before executing any of it. The unterminated template literal therefore produces a syntax error before main(), tick(), or the audit subprocess can run. This affects both documented invocation modes:

bash
node scripts/monitor.cjs
node scripts/monitor.cjs --daemon

The defect disables the monitoring control rather than merely affecting one error-handling branch. No audit is launched, no periodic interval is installed, no state is updated, and no monitor alert is generated.

Attack Path

  1. An operator installs the Skill and starts the documented monitoring command.
  2. Node.js parses scripts/monitor.cjs and encounters the mismatched template-literal delimiter.
  3. The process terminates immediately with a syntax error.
  4. The operator may continue under the mistaken assumption that monitoring is active.
  5. Any subsequent modification to identity files, memory files, or scripts remains undetected by the disabled daemon.

This issue requires no direct attacker-controlled input. An attacker can benefit from the pre-existing monitoring failure by modifying files that the monitor was intended to inspect.

Impact Assessment

The defect does not directly grant filesystem privileges or execute attacker-controlled code. Its impact is loss of the complete real-time monitoring function within the user's OpenClaw wo ...[truncated 214 chars]

Remediation
View remediation

Remediation Suggestions

Correct the mismatched delimiter:

js
} else {
  if (state.consecutiveAlerts > 0) {
    log(`Security issues resolved after ${state.consecutiveAlerts} consecutive alerts`);
  }
  state.consecutiveAlerts = 0;
}

Add the following hardening measures:

  1. Run node --check scripts/monitor.cjs in continuous integration and before publishing.
  2. Add a startup test that launches both one-shot and daemon modes.
  3. Add a health indicator, PID file, or watchdog so operators can verify that the monitor remains active.
  4. Ensure process startup failures are surfaced through the deployment or service-management mechanism rather than relying only on console output.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/monitor.cjs:99
Finding

Daemon Silently Treats High-Severity Audit Findings as a Clean Run

Content
View full analysis

Vulnerability Details

File Location: scripts/audit.cjs, lines 251-265; scripts/monitor.cjs, lines 99-128
Vulnerability Type: Incorrect severity signaling and incomplete audit-result processing
Risk Level: High

Vulnerable Code

The audit includes both HIGH and CRITICAL findings in allIssues, but returns exit code 2 only when at least one finding is CRITICAL:

js
const allIssues = [
  ...(output.checks.identity || []).filter(r => r.level === 'CRITICAL' || r.level === 'HIGH'),
  ...(output.checks.knowledge || []).filter(r => r.level === 'CRITICAL' || r.level === 'HIGH'),
  ...(output.checks.capability?.results || []).filter(r => r.level === 'CRITICAL' || r.level === 'HIGH'),
];

if (allIssues.length > 0) {
  log(`[${new Date().toISOString()}] [WARNING] [CIK] 发现 ${allIssues.length} 个潜在安全问题`);
  for (const i of allIssues) log(`[${new Date().toISOString()}] [${i.level}] [CIK] ${i.file}: ${i.detail}`);
} else {
  log(`[${new Date().toISOString()}] [INFO] [CIK] 安全检查完成, 无严重问题`);
}

if (flags.json) {
  console.log(JSON.stringify(output, null, 2));
} else {
  printReport(output);
}

process.exit(allIssues.some(i => i.level === 'CRITICAL') ? 2 : 0);

The monitor processes findings only when the subprocess returns code 2:

js
if (code === 2 && result) {
  // Critical issues found
  const anomalies = checkAnomalies(result);
  if (anomalies.length > 0) {
    state.consecutiveAlerts++;
    state.lastAlert = now;

    log(`🚨 第${state.consecutiveAlerts}次告警`);
    for (const a of anomalies) {
      log(a);
      // Write to alerts.log for external monitoring
      fs.appendFileSync(
        path.join(AUDIT_DIR, 'alerts.log'),
        `[${now}] ${a}\n`
      );
    }

    // Alert suppression: only report every 3 consecutive alerts
    if (state.consecutiveAlerts === 1 || state.consecutiveAlerts % 3 === 0) {
      console.log('\n🛡️ CIK Security Alert\n
...[truncated 2429 chars]
Remediation
View remediation

Remediation Suggestions

Process every successfully parsed audit result regardless of whether the child exits with code 0 or 2:

js
if (result) {
  const anomalies = checkAnomalies(result);

  if (anomalies.length > 0) {
    state.consecutiveAlerts++;
    state.lastAlert = now;
    for (const anomaly of anomalies) {
      log(anomaly);
    }
  } else {
    state.consecutiveAlerts = 0;
  }
} else {
  throw new Error(`Audit returned no result; exit code: ${code}`);
}

Alternatively, define and document explicit exit codes, such as:

  • 0: no findings
  • 1: high-severity findings
  • 2: critical findings
  • 3: audit execution failure

The monitor must handle both finding codes. Additional hardening should include:

  1. Unit tests for HIGH-only, CRITICAL-only, mixed, and clean results.
  2. Integration tests verifying that each identity, knowledge, and capability rule reaches the monitor log.
  3. Separation of audit execution errors from security-finding exit codes.
  4. A fail-closed policy that records an explicit monitor error when valid results cannot be processed.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/monitor.cjs:26
Finding

Monitor Fails on First Launch When Its Storage Directory Does Not Exist

Content
View full analysis

Vulnerability Details

File Location: scripts/monitor.cjs, lines 12-14, 26-30, and 128-134
Vulnerability Type: Unsafe assumption that a required filesystem directory already exists
Risk Level: Medium

Vulnerable Code

The monitor defines paths under ~/.cik-audit:

js
const AUDIT_DIR = path.join(HOME, '.cik-audit');
const STATE_FILE = path.join(AUDIT_DIR, 'monitor-state.json');
const LOG_FILE = path.join(AUDIT_DIR, 'monitor.log');

Its logging function writes directly to that directory without creating it:

js
function log(msg) {
  const entry = `[${new Date().toISOString()}] ${msg}`;
  fs.appendFileSync(LOG_FILE, entry + '\n');
  if (verbose) console.log(entry);
}

The first action in tick() invokes the unsafe logging function before audit.cjs can create the directory:

js
async function tick() {
  const state = loadState();
  const now = new Date().toISOString();

  log('开始安全检查...');

  try {
    const { code, result } = await runAudit();

Technical Analysis

fs.appendFileSync() can create a missing file, but it cannot create missing parent directories. On a fresh installation where ~/.cik-audit does not exist, the first log() call throws an ENOENT exception.

The call occurs before the try block that wraps runAudit(), so the local error handler does not process it. Although audit.cjs contains an ensureDir(AUDIT_DIR) call, the monitor fails before launching that subprocess. The state-writing and alert-writing paths make the same directory-existence assumption.

Attack Path

  1. The Skill is installed in an environment where ~/.cik-audit has not previously been created.
  2. The operator starts the documented one-shot or daemon monitor command.
  3. tick() calls log() before invoking the audit.
  4. fs.appendFileSync() throws ENOENT because the parent directory is absent.
  5. Monitoring terminates without performing a s ...[truncated 625 chars]
Remediation
View remediation

Remediation Suggestions

Create the directory before any log, state, or alert operation:

js
function ensureAuditDir() {
  fs.mkdirSync(AUDIT_DIR, {
    recursive: true,
    mode: 0o700
  });
}

async function main() {
  ensureAuditDir();

  if (!daemon) {
    await tick();
    return;
  }

  // Continue daemon initialization.
}

Apply the following additional controls:

  1. Call the initialization routine before loadState() and log().
  2. Use restrictive permissions for a directory containing security logs and state.
  3. Handle filesystem failures explicitly and report them to standard error.
  4. Test startup with the directory absent, present, read-only, and replaced by a non-directory file.
  5. Consider atomic state-file updates using a temporary file followed by a same-filesystem rename.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (12)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

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

md
| **外部URL检测** | 指向可疑免费域名(.xyz/.tk/.ml/.ga/.cf等)的请求 |
| **凭证外传检测** | 凭证与可疑URL一起出现时报警 |
| **动态代码执行** | eval/exec处理用户输入的检测 |
| **根目录删除** | rm -rf / 或等效危险命令检测 |
| **快照备份** | 每次检查自动保存快照到 `~/.cik-audit/snapshots/` |
| **告警日志** | 所有异常记录到 `~/.cik-audit/alerts.log` |

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

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

md
| **外部URL检测** | 指向可疑免费域名(.xyz/.tk/.ml/.ga/.cf等)的请求 |
| **凭证外传检测** | 凭证与可疑URL一起出现时报警 |
| **动态代码执行** | eval/exec处理用户输入的检测 |
| **根目录删除** | rm -rf / 或等效危险命令检测 |
| **快照备份** | 每次检查自动保存快照到 `~/.cik-audit/snapshots/` |
| **告警日志** | 所有异常记录到 `~/.cik-audit/alerts.log` |

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

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

md
| **外部URL检测** | 指向可疑免费域名(.xyz/.tk/.ml/.ga/.cf等)的请求 |
| **凭证外传检测** | 凭证与可疑URL一起出现时报警 |
| **动态代码执行** | eval/exec处理用户输入的检测 |
| **根目录删除** | rm -rf / 或等效危险命令检测 |
| **快照备份** | 每次检查自动保存快照到 `~/.cik-audit/snapshots/` |
| **告警日志** | 所有异常记录到 `~/.cik-audit/alerts.log` |

YARA rule 'agent_skill_destructive_autonomous_actions': Autonomous destructive filesystem, shell history, or repository actions in AI agent skills [agent_skills]

High
Category
YARA Match
Confidence
75% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

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

edge 监控** | MEMORY.md 可疑行为指令扫描(伪造习惯类攻击) | | Capability 监控 | skills/ 目录新增脚本的可疑模式检测 | | 外部URL检测 | 指向可疑免费域名(.xyz/.tk/.ml/.ga/.cf等)的请求 | | 凭证外传检测 | 凭证与可疑URL一起出现时报警 | | 动态代码执行 | eval/exec处理用户输入的检测 | | 根目录删除 | rm -rf / 或等效危险命令检测 | | 快照备份 | 每次检查自动保存快照到 ~/.cik-audit/snapshots/ | | 告警日志 | 所有异常记录到 ~/.cik-audit/alerts.log |

快速开始

一次性安全检查(主要用法)

bash
node skills/cik-security/scripts/audit.cjs

输出示例:

text
🛡️  CIK Security Audit v4
时间: 2026-04-23T07:52:01.083Z

[Identity (身份)] (扫描 5 个文件)
  ✅ 无严重问题

[Knowledge (知识)] (扫描 2 个文件)
  ✅ 无严重问题

[Capability (能力)] (扫描 165 个脚本)
  ✅ 无严重问题

📁 �

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

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

md
只报警 `eval(req.|body.|input.|data.|params.|query.|headers.|cookies).` 模式(用户输入进入 eval)

### 根目录删除
只报警 `rm -rf /` 或 `Remove-Item ... -Recurse -Force $/`(排除了正常清理如 `rm -rf $HOME/.cache`)

## 文件结构

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

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

md
只报警 `eval(req.|body.|input.|data.|params.|query.|headers.|cookies).` 模式(用户输入进入 eval)

### 根目录删除
只报警 `rm -rf /` 或 `Remove-Item ... -Recurse -Force $/`(排除了正常清理如 `rm -rf $HOME/.cache`)

## 文件结构

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

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

md
只报警 `eval(req.|body.|input.|data.|params.|query.|headers.|cookies).` 模式(用户输入进入 eval)

### 根目录删除
只报警 `rm -rf /` 或 `Remove-Item ... -Recurse -Force $/`(排除了正常清理如 `rm -rf $HOME/.cache`)

## 文件结构

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
83% confidence
Finding

The skill documentation advertises behavior that reads environment-related data/capabilities, but it declares no explicit tool scope or permission boundaries. In an agent ecosystem, missing scope declarations can cause the host or user to grant broader access than intended, increasing the blast radius if the monitoring scripts are modified or abused.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill states that every check automatically saves snapshots into a home-directory audit folder, but it does not warn that these snapshots may copy sensitive identity, memory, or skill files. Security-monitoring artifacts can themselves become a concentration point for secrets, private prompts, or credentials if stored unredacted.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

This code emits user-facing status and alert text in Chinese, such as file status details and report messages, without offering any language or locale selection. The policy for this audit flags skills that force a specific language without user opt-in, and this behavior appears throughout the script's natural-language strings.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This code emits multiple user-facing alerts and status messages in Chinese, such as anomaly descriptions and console output, without any opt-in, fallback, or documented locale constraint. That creates a natural-language policy issue because the skill effectively forces a specific language on all users.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The natural-language metadata is entirely in Chinese, with no indication that users can opt into another language or locale. Under the policy, language constraints should either offer user choice or be clearly documented as region-specific and justified.

Content

No source excerpt is available for this finding.