T09 · Insecure Skill Coding Practices
- 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: HighVulnerable 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
rendercommand serializes a stored card usingJSON.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 incapabilities. 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
-
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.
-
Add a file-based import interface, for example:
bash node skills/feishu-clawbot-card/index.js import-file ./card.jsonThe implementation should read the file directly through Node.js without constructing or invoking a shell command.
- 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-
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. -
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.
-
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
-
Clearly label rendered content as data rather than an executable command, and avoid instructions encouraging users or agents to execute attacker-derived text.
-
