Back to skill

Security audit

Feishu ClawBot Card

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its Feishu business-card purpose, but rendered cards can include unsafe copy-paste commands built from untrusted card text.

Review before installing. Treat received cards as untrusted data, and do not run rendered import commands from unknown cards without rewriting them into a safe file or stdin-based import. Expect the skill to modify its local rolodex files, and consider updating or pinning dependencies before use.

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

T09 · Insecure Skill Coding Practices

Error
Location
index.js:171
Finding

Shell Command Injection in Rendered Card Import Instruction

Content
View full analysis

Vulnerability Details

File Location: index.js:171-174
Vulnerability Type: Shell command injection through unsafe interpolation of untrusted card data
Risk Level: High

Vulnerable Code

js
[{ tag: "text", text: "💾 Save:  ", style: ["bold"] }, { tag: "text", text: "Copy the code below & send to your bot:" }],

// Row 7: Code Block (The Command)
[{ tag: "text", text: `node skills/feishu-clawbot-card/index.js import '${JSON.stringify(CardProtocolSchema.parse(card))}'` }],

The affected command includes values accepted by the schema in src/CardProtocol.js, including attacker-controlled strings:

js
display_name: z.string().min(1).max(50),
bio: z.object({
  species: z.string().min(1),
  mbti: z.enum(['INTJ','INTP','ENTJ','ENTP','INFJ','INFP','ENFJ','ENFP','ISTJ','ISFJ','ESTJ','ESFJ','ISTP','ISFP','ESTP','ESFP']).optional(),
  desc: z.string().max(500).optional().describe("Dynamic description of persona, quirks, and role. Detailed descriptions encouraged."),
  gender: z.enum(['Female', 'Male', 'Non-binary', 'Other']).optional(),
}).optional(),
capabilities: z.array(z.string()).default([]),

Technical Analysis

The render command serializes a stored card using JSON.stringify() and interpolates the result into a single-quoted shell command. JSON serialization protects JSON syntax but does not perform POSIX shell escaping.

The schema permits apostrophes and shell metacharacters in fields such as display_name, bio.species, bio.desc, and entries in capabilities. An apostrophe in any serialized value can terminate the shell's single-quoted argument. The remaining text can then introduce shell operators and arbitrary commands.

For example, an otherwise valid card field can contain a value shaped like:

text
'; attacker-command; #

The generated output explicitly instructs recipients to copy and execute the command. Consequently, an attacker-controlled card can transform a legitimate-looking import instruction int ...[truncated 1598 chars]

Remediation
View remediation

Remediation Suggestions

  1. Stop generating executable shell commands from untrusted card content. Emit the validated JSON as data and instruct users to save it to a file or provide it through standard input.

  2. Add a file-based import interface, for example:

bash
node skills/feishu-clawbot-card/index.js import-file ./card.json

The implementation should read the file directly through Node.js without constructing or invoking a shell command.

  1. Support standard input so callers can pass structured data without embedding it in command syntax:
bash
node skills/feishu-clawbot-card/index.js import-stdin < card.json
  1. If a copyable command is unavoidable, apply a well-reviewed shell-escaping library designed for the exact target shell. Do not treat JSON.stringify(), backslash replacement, or ad hoc quote substitution as shell escaping.

  2. Consider encoding the serialized payload, such as Base64, and passing only a strictly validated encoded alphabet to an import option. Decode it internally as data and never evaluate the decoded content as code.

  3. Add regression tests covering malicious values containing:

    • Single and double quotes
    • Semicolons and ampersands
    • Backticks and command substitutions
    • Pipes and redirection operators
    • Newlines and carriage returns
    • Shell comments and escape characters
  4. Clearly label rendered content as data rather than an executable command, and avoid instructions encouraging users or agents to execute attacker-derived text.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (6)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The render command wraps output only in a zh_cn structure, which forces a specific locale in the generated Feishu post. This is a natural-language locale policy issue because the skill provides no opt-in, fallback, or alternative language selection for users.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The save() method writes registry data to disk, creates a backup copy, and replaces the main rolodex file, but there is no confirmation prompt, user-facing log, or explanatory comment aimed at informing the user that persistent local files will be modified. This is a safety-relevant data mutation operation on a code file, so some visible disclosure is expected under the rule.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The delete() method removes a card from the in-memory registry and immediately persists the change to disk via save(), making the deletion durable. Although the method name implies deletion, the code provides no confirmation, user-facing log, or explicit warning about the destructive effect.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
90% confidence
Finding

The dependency version is specified with a caret range (^11.0.0), which permits automatic installation of newer semver-compatible releases rather than a single fixed version. In a registry-like skill that manages identities and assets, this weakens supply-chain control and can unexpectedly pull in vulnerable or behavior-changing package versions during future installs.

Content

Scanner excerpt · bot-registry/package.json (reported line 13)May include surrounding context.

json
"delete": "node delete.js"
  },
  "dependencies": {
    "uuid": "^11.0.0"
  },
  "author": "Shutiao (OpenClaw)",
  "license": "ISC"

Known Vulnerable Dependency: uuid==13.0.0 — 1 advisory(ies): CVE-2026-41907 (uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided)

Low
Category
Supply Chain
Confidence
60% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: uuid==13.0.0 — 1 advisory(ies): CVE-2026-41907 (uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided)

Low
Category
Supply Chain
Confidence
92% confidence
Finding

The lockfile pins uuid to 13.0.0, which the supplied advisory identifies as affected by a missing buffer bounds check in certain UUID generation/parsing paths when a buf argument is provided. Even though package-lock.json alone does not prove the vulnerable API usage is reachable, retaining a known vulnerable version is a real supply-chain risk because downstream code may invoke the affected functions and trigger crashes or memory-safety issues in dependent environments.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.