Back to skill

Security audit

token-optimizer

Security checks for vulnerabilities and agentic risk

Overview

The skill is a mostly coherent token-usage audit tool, but it needs review because one write helper can modify Markdown files outside the intended workspace and the docs include high-risk cross-agent write/shell delegation patterns.

Install only if you are comfortable with a local OpenClaw diagnostic reading agent session usage logs and workspace context files. Run the audit commands first, review output manually, avoid cross-agent write/shell delegation unless the receiving owner explicitly approves it, and do not use md-slim.js --apply with paths containing .. or absolute paths until path containment is fixed.

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

Warning
Location
scripts/md-slim.js:60
Finding
Workspace Path Traversal Enables Out-of-Scope File Modification<![CDATA[ ## Vulnerability Details **File Location**: `scripts/md-slim.js`, lines 60-92 and 122-130 **Vulnerability Type**: Path traversal and insufficient filesystem boundary validation **Risk Level**: Medium ### Vulnerable Code ```js function applySlim(file, titles, dry) { const p = path.join(L.WORKSPACE, file); const text = fs.readFileSync(p, 'utf8'); const { preamble, sections } = splitSections(text); const picked = sections.filter((s) => titles.includes(s.title)); if (!picked.length) { console.error(`❌ 未找到指定小节:${titles.join(' / ')}`); process.exit(1); } const date = new Date().toISOString().slice(0, 10); const dir = path.dirname(p); const archiveDir = path.join(dir, 'archive'); const base = path.basename(file, '.md'); const results = []; if (!dry) { const bakDir = path.join(L.WORKSPACE, 'backups', 'md-slim'); fs.mkdirSync(bakDir, { recursive: true }); fs.copyFileSync(p, path.join(bakDir, `${base}.${new Date().toISOString().replace(/[:.]/g, '-')}.bak`)); fs.mkdirSync(archiveDir, { recursive: true }); } const before = Buffer.byteLength(text, 'utf8'); let newText = text; for (const s of picked) { const slug = s.title.replace(/[^\w\u4e00-\u9fa5-]+/g, '-').slice(0, 30); const arcRel = path.relative(L.WORKSPACE, path.join(archiveDir, `${base}-${slug}-${date}.md`)); const arcContent = `# ${base} · ${s.title}(归档 ${date})\n\n> 由 md-slim.js 从 \`${file}\` 移出。\n> 原文完整保留于此;主文件保留指针,仍可用 memory_search 检索到。\n\n${s.body}\n`; if (!dry) fs.writeFileSync(path.join(L.WORKSPACE, arcRel), arcContent); const pointer = `## ${s.title}\n\n> 📦 已归档:\`${arcRel}\`(${(s.bytes / 1024).toFixed(1)}KB,内容完整保留,可用检索取回)\n`; newText = newText.replace(s.body, pointer.trimEnd()); results.push({ title: s.title, kb: (s.bytes / 1024).toFixed(1), archive: arcRel, movedBytes: s.bytes, arcBytes: Buffer.byteLength(arcContent, 'utf8') }); } if (!dry) fs.writeFileSync(p, newText); } ``` The command-line value is passed int ...[truncated 3052 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Resolve and validate every source and destination against a canonical workspace root before performing any filesystem operation: ```js function resolveInsideWorkspace(relativePath) { const root = path.resolve(L.WORKSPACE); const target = path.resolve(root, relativePath); if (target !== root && !target.startsWith(root + path.sep)) { throw new Error('The requested path must remain inside the workspace'); } return target; } ``` Use it for the source file and all generated archive and backup paths: ```js const p = resolveInsideWorkspace(file); ``` Additional hardening should include: 1. Restrict `--file` to `L.WORKSPACE_CONTEXT_FILES` unless arbitrary workspace files are explicitly required. 2. Reject absolute paths and any input containing traversal components. 3. Use `fs.realpathSync()` for existing files and verify containment after resolving symbolic links. 4. Reject symbolic-link source files or destinations when symlinks are not required. 5. Validate the parent of newly created archive files through `realpathSync()` before writing. 6. Add tests for `../`, absolute paths, nested traversal, and symlinks escaping the workspace. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/md-slim.js:64
Finding
Predictable Archive Names Permit Silent Overwriting of Archived Content<![CDATA[ ## Vulnerability Details **File Location**: `scripts/md-slim.js`, lines 64-104 **Vulnerability Type**: Predictable filename collision and insufficient integrity verification **Risk Level**: Medium ### Vulnerable Code ```js const date = new Date().toISOString().slice(0, 10); const dir = path.dirname(p); const archiveDir = path.join(dir, 'archive'); const base = path.basename(file, '.md'); const results = []; // ... for (const s of picked) { const slug = s.title.replace(/[^\w\u4e00-\u9fa5-]+/g, '-').slice(0, 30); const arcRel = path.relative(L.WORKSPACE, path.join(archiveDir, `${base}-${slug}-${date}.md`)); const arcContent = `# ${base} · ${s.title}(归档 ${date})\n\n> 由 md-slim.js 从 \`${file}\` 移出。\n> 原文完整保留于此;主文件保留指针,仍可用 memory_search 检索到。\n\n${s.body}\n`; if (!dry) fs.writeFileSync(path.join(L.WORKSPACE, arcRel), arcContent); const pointer = `## ${s.title}\n\n> 📦 已归档:\`${arcRel}\`(${(s.bytes / 1024).toFixed(1)}KB,内容完整保留,可用检索取回)\n`; newText = newText.replace(s.body, pointer.trimEnd()); results.push({ title: s.title, kb: (s.bytes / 1024).toFixed(1), archive: arcRel, movedBytes: s.bytes, arcBytes: Buffer.byteLength(arcContent, 'utf8') }); } if (!dry) fs.writeFileSync(p, newText); // Self-verification let ok = true; if (!dry) { for (const r of results) { const abs = path.join(L.WORKSPACE, r.archive); if (!fs.existsSync(abs) || Buffer.byteLength(fs.readFileSync(abs, 'utf8'), 'utf8') < r.movedBytes) { ok = false; console.error(`❌ 自证失败:${r.archive} 字节数异常`); } } } ``` ### Technical Analysis Archive filenames are derived only from: - The source file basename. - A normalized and truncated section title. - The current calendar date. No exclusive creation flag, unique identifier, high-resolution timestamp, or collision check is used. `fs.writeFileSync()` therefore overwrites an existing archive at the same path. Collisions can occur when: - The same section is archived more than once on the same day. - Multipl ...[truncated 1918 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Create archive files exclusively and fail safely on collisions: ```js fs.writeFileSync(archivePath, arcContent, { encoding: 'utf8', flag: 'wx' }); ``` Generate a unique archive name using a high-resolution timestamp, random identifier, or collision-resistant hash: ```js const unique = `${Date.now()}-${crypto.randomUUID()}`; const archiveName = `${base}-${slug}-${unique}.md`; ``` Replace the byte-length check with content verification. For example: ```js const crypto = require('crypto'); function hash(value) { return crypto.createHash('sha256').update(value, 'utf8').digest('hex'); } ``` After writing, read the archive and verify that its embedded section body exactly matches `s.body`, or store and compare a SHA-256 digest. The source file should not be rewritten until all archives have been created and verified successfully. If any archive operation fails: 1. Delete only newly created archive files. 2. Leave the source untouched. 3. Restore from the automatic backup if the source was already changed. 4. Exit with a failure status. Tests should cover repeated same-day execution, duplicate titles, slug truncation collisions, pre-existing archives, and interrupted writes. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/cron-migrate-isolated.js:53
Finding
Ambiguous Cron Job Name Matching Can Modify an Unintended Scheduled Task<![CDATA[ ## Vulnerability Details **File Location**: `scripts/cron-migrate-isolated.js`, lines 53-67 **Vulnerability Type**: Ambiguous object selection and insufficient authorization targeting **Risk Level**: Low ### Vulnerable Code ```js const byName = Object.fromEntries(jobs.map((j) => [j.name, j])); let ok = 0, fail = 0; for (const name of picked) { const j = byName[name] || jobs.find((x) => x.name.includes(name)); if (!j) { console.log(` ⚪ 未找到: ${name}`); continue; } const msg = ((j.payload && (j.payload.text || j.payload.message)) || '').trim(); const argv = ['cron', 'edit', j.id, '--session', 'isolated', '--message', msg, '--no-deliver']; if (LIGHT) argv.push('--light-context'); try { execFileSync('openclaw', argv, { encoding: 'utf8' }); console.log(` ✅ ${j.name} → isolated${LIGHT ? ' + lightContext' : ''}`); ok++; } catch (e) { console.log(` ❌ ${j.name}: ${String(e.stderr || e.message).slice(0, 160)}`); fail++; } } ``` Candidate identification is performed earlier, but applied jobs are selected from the complete job list rather than the validated candidate list: ```js const candidates = jobs.filter((j) => { if (j.sessionTarget !== 'main') return false; const t = (j.payload && (j.payload.text || j.payload.message)) || ''; return SCRIPT_RE.test(t) && RUN_RE.test(t); }); ``` ### Technical Analysis The Skill documents `--jobs` as an explicit job-selection safeguard. However, if an exact name does not exist, the implementation silently falls back to the first job whose name contains the supplied text: ```js jobs.find((x) => x.name.includes(name)) ``` When multiple names contain the same substring, selection depends on the order returned by `openclaw cron list --json`. The script does not detect ambiguity or require confirmation of the resolved job ID. Furthermore, the apply loop searches the full `jobs` array rather than `candidates`. A selected job therefore does not need to satisfy the migration heuris ...[truncated 1671 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Require an exact job name or immutable job ID. Remove the substring fallback: ```js const j = byName[name]; if (!j) { console.error(`No exact cron job match: ${name}`); fail++; continue; } ``` A stronger interface would require IDs: ```bash node scripts/cron-migrate-isolated.js --job-ids "job-id-1,job-id-2" --apply ``` Additional safeguards should include: 1. Restrict apply-mode selections to entries in `candidates`. 2. If partial matching is retained, collect all matches and reject zero or multiple matches. 3. Print the complete selected job ID, name, session target, payload, delivery settings, and proposed changes before execution. 4. Require a second confirmation when a selected job is not a validated migration candidate. 5. Save a machine-readable backup of the complete original cron configuration. 6. Generate an exact rollback command for each modified job. 7. Avoid applying `--no-deliver` unless the operator explicitly requests that delivery change. 8. Add tests for exact names, duplicate names, overlapping names, ambiguous substrings, and non-candidate selections. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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 (28)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared description promises a broader token-consumption diagnostic tool covering four categories of issues and producing optimization guidance from actual usage data. The supplied code chunk is much narrower: it reads cron job metadata, estimates run frequency, counts jobs targeting the main session, and recommends isolating some cron tasks. That aligns with only the 'cron 灌主会话' portion of the description, but not the overall stated functionality. Because the primary purpose as implemented is a cron audit rather than a comprehensive token-usage optimization scan, this is a material description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The description presents a broader analysis/diagnostic tool for token consumption that inspects conversation usage and identifies multiple classes of waste, then recommends optimization steps. The actual code chunk does only one narrow operational action: discover candidate cron jobs and optionally rewrite their session target from main to isolated. While cron rerouting is mentioned in the declared purpose as one possible optimization step, this code does not implement the core declared behavior of scanning usage logs, diagnosing token issues, or handling the other listed categories such as excessive API calls, context bloat analysis, or oversized workspace files. It also has an undeclared write capability: editing cron configuration. Therefore the code chunk does not accurately represent the declared purpose on its own.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The description promises an analysis/diagnostic skill focused on token consumption across AI agent sessions, logs, usage, call counts, cron routing, and workspace file size, with executable optimization recommendations. The actual code chunk only implements one narrow helper: slimming markdown workspace files by moving whitelisted sections such as changelogs/appendices into archive files. While this partially aligns with the mentioned 'md 瘦身脚本' sub-feature, it does not implement the primary declared behavior of scanning usage logs, identifying the four token issues, or recommending cron and API-call optimizations. Therefore the code chunk materially under-delivers relative to the declared purpose and represents only a small subset of it.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The declared description promises a broader token-consumption diagnostic tool covering four distinct problem categories and corresponding optimization actions. The actual code chunk implements only one narrow check: current session context size based on latest usage data. It does not analyze call frequency, cron routing, or file obesity, and it does not implement the mentioned optimization scripts. While the implemented behavior is related to one subset of the declared purpose (context bloat), the overall description materially overstates the functionality present in this code chunk.

Ae1

High
Category
analysis-evasion
Content
node scripts/audit.js
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/audit.js
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/audit.js
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/md-audit.js # 工作台注入文件体积 & 瘦身建议
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/md-slim.js # 【执行器】工作台瘦身:只移动不删除+备份+自证
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/md-slim.js # 【执行器】工作台瘦身:只移动不删除+备份+自证
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/cron-audit.js # cron 构成:多少任务在灌主会话
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/cron-migrate-isolated.js --dry # 纯脚本类任务改道 isolated(先 dry-run)
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/cron-migrate-isolated.js --dry # 纯脚本类任务改道 isolated(先 dry-run)
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/cron-migrate-isolated.js --dry # 纯脚本类任务改道 isolated(先 dry-run)
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The entire skill description and safety self-audit are written only in Chinese, with no indication that users may choose another language or that the skill is intended exclusively for a Chinese-speaking or region-specific context. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The skill documentation is written entirely in Chinese and does not indicate that the user can choose another language or that the skill is intended only for a Chinese-speaking or region-specific audience. Under the policy rule for language or locale constraints, this is a natural-language policy violation because it effectively imposes a language without opt-in or justification.

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The documentation expands a token-optimization skill into cross-agent delegation with `scope=write|shell`, which materially exceeds a read-only audit/remediation advisory purpose. Even though the text repeatedly mentions consent and L3 confirmation, embedding executable remote-action patterns inside this skill normalizes and operationalizes high-risk capabilities that could be reused for unauthorized code execution or filesystem changes in another instance.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The template catalog includes ready-to-use remote actions such as `token-optimize-shell`, `md-slim`, `cron-migrate`, and `upgrade-a2a`, turning documentation into an actionable playbook for remote write/shell operations. In the context of a skill advertised as token-cost optimization, these templates broaden capability far beyond diagnosis and create a clear path to destructive or unauthorized changes if invoked against another agent or environment.

Description-Behavior Mismatch

Medium
Confidence
84% confidence
Finding
The section describing direct modification of shared code in another component (`git pull` to pick up a fix, changed timeout logic, adapter behavior) documents operational changes outside the stated token-usage optimization remit. While presented as legitimate engineering remediation, it implicitly couples this skill to cross-component code alteration and may encourage operators to apply broader code changes under the guise of token optimization.

Natural-Language Policy Violations

Medium
Confidence
84% confidence
Finding
The document title and all instructional content are written in Chinese, with no indication that other languages are supported or that Chinese is required for a documented region-specific purpose. Under the language/locale policy, forcing a specific language without user opt-in can be a natural-language policy violation.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The document title and core instructions are written in Chinese and explicitly target '任何一个 OpenClaw agent', but there is no indication that the user can choose another language or that the locale restriction is required for a region-specific purpose. This creates a natural-language policy concern because it effectively forces a specific language without user opt-in.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The file’s header comments and all user-facing console output are written in Chinese, which imposes a specific language on users. Under the policy, this is a natural-language locale violation because the script does not offer opt-in language selection or explain that it is intended only for a Chinese-speaking context.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The file’s header comments, usage guidance, and subsequent console messages are written in Chinese, which imposes a specific language on operators without any opt-in or indication that the skill is intended only for a Chinese-speaking environment. This matches the language/locale policy violation category because the script does not provide an alternative language path or justify the restriction.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This library enumerates agent session logs under ~/.openclaw/agents, reads JSONL conversation records, inspects usage metadata, and reads workspace context files from ~/.openclaw/workspace. Even though it appears intended for token-usage diagnostics, it accesses potentially sensitive conversation and workspace content without any consent check, scope restriction, sanitization, or user-facing notice, which can expose private prompts, metadata, and operational details if the skill is invoked unexpectedly or by another component.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/cron-migrate-isolated.js:61