Back to skill

Security audit

Voko Subagent

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real VOKO customer-service subagent tool, but it gives callers too much control over which local visitor data is read and how replies are routed.

Install only in a controlled Gateway where callers are trusted and filesystem permissions limit access to the intended VOKO database. Before production use, restrict dbPath to an approved directory, bind requested messages to visitorUid, prevent model output from choosing to_uid, add privacy guidance for visitor data, and update vulnerable dependencies.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
Findings (4)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
src/handler.js:31
Finding

Unrestricted Database Path Permits Access to Unintended Local Databases

Content
View full analysis
{ const db = new sqlite3.Database(dbPath, (err) => { if (err) reject(err); else resolve(db); }); }); } ``` ### Technical Analysis The `--db-path` argument is accepted directly from the caller and stored as the active database path. The path is subsequently passed to `sqlite3.Database` without canonicalization, an allowlisted root directory, file ownership validation, symlink checks, or caller authorization. SQL parameterization elsewhere prevents SQL injection, but it does not mitigate this access-control problem. A caller who can invoke the Skill can select any SQLite-compatible file readable by the OpenClaw Gateway process. If that database contains the expected `visitors` and `messages` tables, its records can be collected and incorporated into a subagent prompt. The database is opened using the Gateway process's privileges rather than privileges restricted to the invoking user. This creates a confused-deputy condition and violates least privilege. ### Attack Path 1. An attacker obtains permission to invoke the `voko-subagent` Skill. 2. The attacker supplies `--mode=build-and-handle` and an arbitrary `--db-path` pointing to another accessible SQLite database. 3. `handleVisitorMessage` accepts and stores the path without validating its location or ownership. 4. `buildPrompt` opens the selected file under the Gateway process's filesystem privileges. 5. Records from compatible `visitors` and `messages` tables are read and placed into the subagent task. 6. The subagent processe ...[truncated 553 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
src/prompt-builder.js:81
Finding

Caller-Supplied Message IDs Are Not Restricted to the Requested Visitor

Content
View full analysis
0) { const placeholders = messageIds.map(() => '?').join(','); currentMessages = await dbAll( db, `SELECT * FROM messages WHERE message_id IN (${placeholders}) ORDER BY timestamp ASC`, messageIds ); } ``` ### Technical Analysis When `messageIds` are supplied, the query selects records solely by `message_id`. It does not require the records to belong to `visitorUid`, originate from that visitor, target that visitor, or otherwise be authorized for the current request. The dynamically generated placeholders and bound parameters prevent direct SQL injection. However, parameterization does not enforce record ownership. This is a broken object-level authorization issue: possession or discovery of a message identifier is treated as sufficient authority to access the corresponding record. The selected rows are serialized into the prompt and delivered to a spawned subagent, extending the disclosure boundary beyond the database query itself. ### Attack Path 1. An attacker obtains or guesses one or more message IDs belonging to another visitor. 2. The attacker invokes the Skill in `build-and-handle` mode with an attacker-selected `visitorUid`. 3. The attacker supplies the victim's identifiers through `messageIds`. 4. The SQL query retrieves every matching message without checking its relationship to `visitorUid`. 5. The victim's records are serialized into the current-message prompt block. 6. The subagent processes those records and may summarize, quote, classify, or otherwise reveal their content in its response. ### Impact Assessment The vulnerability can expose messages belonging to other visitors in the same selected database. Accessible data may include message content and any additi ...[truncated 267 chars]
Remediation
View remediation

T01 · Skill Instruction Hijacking

Error
Location
src/prompt-builder.js:130
Finding

Untrusted Conversation and Prompt Content Is Embedded Directly into Subagent Instructions

Content
View full analysis
{ const isVisitor = m.direction === 'in'; return `${isVisitor ? '访客' : '客服'}: ${m.content}`; }).join('\n'); ``` ```javascript function buildSubagentTask(params) { return `你是 VOKO 智能客服助手。 【任务】 根据提供的访客信息和对话历史,回复访客消息。 ${params.prompt} 【重要】 1. 仔细分析访客的需求和情绪 2. 回复要简洁、友好、专业 3. 不确定的内容标记 need_owner_attention=true 4. 必须返回合法的 JSON 格式`; } ``` ### Technical Analysis Historical message content is concatenated into plain text and later interpolated directly into the subagent task. The subagent receives trusted behavioral instructions and untrusted conversation content in the same instruction channel. Although the generated prompt contains a safety statement for the Base64-encoded current-message block, historical conversation content is not encoded or isolated in the same manner. A malicious stored message can therefore resemble system-level or task-level instructions and attempt to override response requirements. The direct `--prompt` mode has the same trust-boundary weakness. The caller's Base64 input is decoded into arbitrary UTF-8 text and inserted as `params.prompt` into the task. Base64 is only an encoding and provides no validation, authentication, or isolation. A successful injection can influence all model-generated fields. The model output is later treated as structured application data, including routing, tags, intimacy suggestions, and owner-attention decisions. ### Attack Path 1. An attacker sends a visitor message containing instruction-like text, such as directions to ignore prior requirements or emit attacker-selected JSON fields. 2. The message is stored in conversation history. 3. A later `build-and-handle` invocation retrieves t ...[truncated 1111 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/response-parser.js:38
Finding

Model Output Can Override the Trusted Response Recipient

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (17)

Known Vulnerable Dependency: tar==6.2.1 — 12 advisory(ies): CVE-2026-59873 (node-tar: Decompression/parse DoS via unlimited input); CVE-2026-24842 (node-tar Vulnerable to Arbitrary File Creation/Overwrite via Hardlink Path Trave); CVE-2026-26960 (Arbitrary File Read/Write via Hardlink Target Escape Through Symlink Chain in no) +9 more

Critical
Category
Supply Chain
Confidence
98% confidence
Finding

tar 6.2.1 is a real high-risk dependency concern because multiple advisories include path traversal, arbitrary file overwrite, and DoS conditions during archive handling. This is especially relevant here because sqlite3 has an install script and pulls in prebuild-install/tar-related tooling, increasing the chance that archive extraction paths are exercised during install or update workflows.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: brace-expansion==1.1.12 — 4 advisory(ies): CVE-2026-13149 (brace-expansion: DoS via exponential-time expansion of consecutive non-expanding); CVE-2026-33750 (brace-expansion: Zero-step sequence causes process hang and memory exhaustion); CVE-2026-14257 (brace-expansion: DoS via unbounded expansion length causing an out-of-memory pro) +1 more

High
Category
Supply Chain
Confidence
95% confidence
Finding

brace-expansion 1.1.12 is flagged with multiple high-severity DoS issues involving pathological pattern expansion. Although it is a transitive optional dependency, any reachable use on attacker-controlled glob or brace patterns can trigger excessive CPU or memory consumption and destabilize the process.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: ip-address==10.1.0 — 2 advisory(ies): CVE-2026-69192 (ip-address: Address4 decodes leading-zero octets as decimal while resolvers deco); CVE-2026-42338 (ip-address has XSS in Address6 HTML-emitting methods)

High
Category
Supply Chain
Confidence
83% confidence
Finding

ip-address 10.1.0 is reported with advisories affecting parsing ambiguity and XSS in HTML-emitting methods. In this lockfile it appears as an optional transitive dependency under socks tooling, so exploitability depends on whether the application actually uses SOCKS proxy features or renders Address6 HTML output, but the vulnerable package is genuinely present.

Content

No source excerpt is available for this finding.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · src/prompt-builder.js (reported line 115)May include surrounding context.

js
console.log('[PromptBuilder] ✅ Prompt 组装完成');
    console.log(`[PromptBuilder] 长度: ${prompt.length} 字符`);
    
    return prompt;
    
  } finally {
    await closeDb(db);

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

This markdown file documents a CLI invocation and parameters that include user identifiers, a local database path, and prompt content, all of which may contain sensitive user or system data. The description does not include any warning about privacy, data handling, or the impact of supplying these values to the skill.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The documentation explicitly states the skill reads a local SQLite database and may assemble a prompt from that data for a subagent, but it provides no privacy boundary, minimization rule, consent requirement, or warning about forwarding visitor data to another agent. This creates a real data-handling risk because operators may expose personal or sensitive visitor information to downstream processing without understanding retention, disclosure, or least-privilege expectations.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The file’s user-facing strings, comments, and operational messages are entirely in Chinese, including the startup/help context and returned reply text. The policy requires flagging language or locale constraints when the skill forces a specific language without offering user choice or documenting a justified region-specific limitation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This JavaScript file uses Chinese-only natural-language comments, error strings, and operational logs throughout the handler, including user-visible or operator-visible messages such as the thrown error and processing status lines. Under the policy, forcing a specific language without offering a locale choice or documenting a justified region-specific constraint is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The embedded prompt and comments instruct the assistant to act as a Chinese customer-service agent and return reply content in Chinese-style wording, but the file does not offer any user language/locale choice or explain a justified region-specific restriction. This is a natural-language policy concern because it forces a specific language context by default.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The prompt tells the downstream model that incoming messages are Base64-encoded and should be treated as inert data, but the code actually Base64-encodes the entire JSON wrapper of currentMessages rather than safely isolating or decoding trusted content fields. This creates a false sense of safety: an agent that decodes the blob will recover attacker-controlled message text and may still treat embedded prompt-injection instructions as authoritative context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The natural-language content throughout the file is exclusively Chinese, including user-facing fallback text at L67 and operational messages in comments/logs. Per the policy, forcing a specific language without offering user choice or documenting a justified locale constraint is a language/locale policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The task prompt instructs the spawned sub-agent entirely in Chinese and fixes its role and response behavior in that language, with no indication that the user can choose another language. This is a natural-language locale policy issue because it imposes a specific language without opt-in or a documented region-specific need.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The natural-language instructions and examples are presented only in Chinese, which can amount to forcing a specific language without user opt-in under the stated policy. There is no indication that the skill is intentionally region-specific or that alternative language support is available.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
75% confidence
Finding

The natural-language documentation is entirely in Chinese and does not indicate that other languages are supported or that Chinese is a deliberate, justified locale constraint. Under the policy, forcing a specific language without opt-in can be a locale-policy concern.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: @tootallnate/once==1.1.2 — 1 advisory(ies): CVE-2026-3449 (@tootallnate/once vulnerable to Incorrect Control Flow Scoping)

Low
Category
Supply Chain
Confidence
73% confidence
Finding

The lockfile pins @tootallnate/once 1.1.2, which static analysis reports as having a low-severity advisory. Even though this package is only a transitive, optional dependency, shipping a version with a known CVE is still a real supply-chain exposure if the affected code path is reached during dependency use or install-time tooling.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The description is written entirely in Chinese, which may indicate the skill is intended to operate or be presented in a fixed language without user opt-in. The file does not provide any indication of language selection, multilingual support, or a documented justification for the locale constraint.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
91% confidence
Finding

The sqlite3 dependency is specified with a caret range (^5.1.6), which allows automatic installation of newer compatible releases. This can introduce supply-chain risk because future dependency updates may pull in vulnerable or malicious code without explicit review, especially for a package intended to run inside a gateway and create sub-agents.

Content

Scanner excerpt · package.json (reported line 13)May include surrounding context.

json
"author": "",
  "license": "MIT",
  "dependencies": {
    "sqlite3": "^5.1.6"
  }
}

Static analysis

No suspicious patterns detected.