Back to skill

Security audit

HandDraw Skill

Security checks for vulnerabilities and agentic risk

Overview

The skill has a clear video-rendering purpose, but it should be reviewed because it renders unsanitized SVG/HTML content and can send narration text to an external TTS service.

Install only if you trust the project JSON and SVG assets you render. Avoid rendering third-party SVGs without review, because SVG content is inserted into a browser renderer. Do not put sensitive or proprietary narration text in projects unless you are comfortable sending it to Edge TTS; omit narration for local-only rendering. Review dependency installation and sync scripts before use because they install packages and update local agent skill directories.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (7)

Description-Behavior Mismatch

Medium
Confidence
87% confidence
Finding
The function invokes Edge TTS via `python3 -m edge_tts`, which transmits narration text to an external service. That expands the skill from deterministic local rendering into networked processing and can expose user-provided script content without an explicit trust boundary or disclosure.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
The renderer inserts object.assetContent directly into the DOM with dangerouslySetInnerHTML and performs no sanitization or allowlisting. In a skill that renders user-supplied JSON animation content, this enables arbitrary HTML/SVG injection, which can lead to script execution, event-handler injection, external resource loading, or hostile SVG behaviors depending on the runtime environment.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
`clip.text` is passed to Edge TTS without any user-facing warning that the text may leave the local system. If users provide sensitive narration content, the skill can unintentionally disclose private or proprietary information to a third-party service.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
When narration is present, the CLI sends project narration text to `synthesizeEdgeNarration(...)`, which implies transmission to an external TTS service, yet this file provides no user-facing notice, consent, or offline/opt-in boundary. If narration contains sensitive or proprietary text, users may unknowingly exfiltrate that content to a third party during rendering.

Vague Triggers

Medium
Confidence
81% confidence
Finding
The Hermes instructions explicitly say the skill can be invoked by a broad natural-language request such as asking for a hand-drawn explainer video. Broad triggers increase the chance of unintended activation, especially in agents that map user intent loosely to installed skills. In this context, the skill installs runtime dependencies and uses networked TTS, so accidental invocation can lead to unexpected code execution, dependency use, or external requests.

Unvalidated Output Injection

High
Category
Output Handling
Content
const visibleText = characters.slice(0, Math.ceil(characters.length * writeProgress)).join("");
    return <div style={{ ...style, width: object.width ?? 1200, height: "auto", fontFamily: narrative ? "Kaiti SC, STKaiti, KaiTi, serif" : "PingFang SC, Microsoft YaHei, sans-serif", fontWeight: narrative ? 500 : 700, fontSize: object.height ?? 48, lineHeight: 1.48, letterSpacing: narrative ? "0.08em" : "0.045em", color: narrative ? "#1c1917" : "#172033", textShadow: narrative ? "0.4px 0.4px 0 #a8a29e" : "0.8px 0.8px 0 #dbe3eb", whiteSpace: "pre-wrap" }}>{visibleText}</div>;
  }
  return <><div style={style} className="handdraw-svg" dangerouslySetInnerHTML={{ __html: object.assetContent ?? "" }} />{!narrative && <DrawingHand object={object} progress={draw} />}</>;
}

function SceneLayer({ scene, time, opacity, narrative }: { scene: PreparedProject["scenes"][number]; time: number; opacity: number; narrative: boolean }) {
Confidence
99% confidence
Finding
This is a direct unvalidated output injection sink: attacker-controlled assetContent is written into the DOM via dangerouslySetInnerHTML. Because this renderer is explicitly driven by a JSON DSL for generated animations, the skill context makes the issue more dangerous: untrusted project content is likely to flow here, turning malformed animation assets into active DOM payloads rather than passive media.

Unpinned Dependencies

Low
Category
Supply Chain
Content
edge-tts>=7.2.0
Confidence
94% confidence
Finding
The dependency is specified with a lower-bound version constraint only, which allows future unreviewed versions of edge-tts to be installed. This weakens build reproducibility and increases supply-chain risk because a malicious or breaking upstream release could be pulled in without explicit approval.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/check-environment.mjs:13

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/handdraw.mjs:14