Back to skill

Security audit

Excalidraw Cli

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its diagram-generation purpose, but its install instructions fetch executable Python from a mutable remote GitHub branch without verification.

Install from the bundled reviewed excalidraw_cli.py rather than curling the latest file from GitHub. Be cautious exporting SVG from Excalidraw JSON you did not create, and run the CI verifier only in a sandbox or disposable environment when checking untrusted packages.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T03 · Remote Payload Retrieval and Execution

Error
Location
SKILL.md:31
Finding

Mutable Remote Python Payload Downloaded Without Integrity Verification

Content
View full analysis
Remediation
View remediation
/excalidraw_cli.py ``` 3. Publish a SHA-256 checksum through a separately protected release channel and verify it before execution: ```bash echo " excalidraw_cli.py" | sha256sum --check - ``` 4. Prefer signed, versioned releases with verifiable provenance. 5. Apply the same correction to both `SKILL.md` and `README.md`. 6. Ensure automated release checks reject installation commands that reference mutable branches without integrity verification. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
excalidraw_cli.py:646
Finding

Untrusted Excalidraw Properties Can Inject Arbitrary SVG Attributes

Content
View full analysis
str: """Convert elements to a basic SVG string for export.""" bg = app_state.get("viewBackgroundColor", "#ffffff") # ... lines: List[str] = [] lines.append(f'') lines.append(f' ') for el in elements: typ = el.get("type", "") ex = el.get("x", 0) ey = el.get("y", 0) ew = el.get("width", 0) eh = el.get("height", 0) sc = el.get("strokeColor", "#000") bc = el.get("backgroundColor", "transparent") sw = el.get("strokeWidth", 2) text = el.get("text", el.get("label", {}).get("text", "")) rot = el.get("angle", 0) transform = f' transform="rotate({math.degrees(rot)} {ex + ew / 2} {ey + eh / 2})"' if rot else "" if typ == "rectangle": rx = "8" if el.get("roundness") else "0" lines.append(f' ') if text: lines.append(f' {_xml_escape(text)}') elif typ == "diamond": points = f"{ex + ew / 2},{ey} {ex + ew},{ey + eh / 2} {ex + ew / 2},{ey + eh} {ex},{ey + eh / 2}" lines.append(f' ') ``` Text content is escaped later: ```python def _xml_escape(s: str) -> str: return s.replace("&", ...[truncated 2247 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
excalidraw_cli.py:616
Finding

Optional Image Export Dependencies Are Recommended Without Version or Integrity Pinning

Content
View full analysis
Remediation
View remediation
--hash=sha256: CairoSVG== --hash=sha256: ``` 3. Pin and review transitive dependencies through a lock-file workflow. 4. Recommend installation in an isolated virtual environment rather than a global or shared Agent environment. 5. Use automated dependency scanning and update pinned versions through reviewed changes. 6. Avoid presenting unconstrained installation commands as the primary remediation for missing dependencies. ]]>
Vulnerability Patterns
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill is presented as an Excalidraw generator, yet the detected behavior includes scanning repository contents, reading SKILL.md/Python files, executing Python via subprocess, running tests, and checking for secrets or deploy readiness. In an agent environment, concealed execution and repo-wide inspection substantially raise risk because they can expose sensitive code/data and trigger unexpected command execution under the guise of a benign content-generation tool.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill is presented as an Excalidraw generator, yet the detected behavior includes scanning repository contents, reading SKILL.md/Python files, executing Python via subprocess, running tests, and checking for secrets or deploy readiness. In an agent environment, concealed execution and repo-wide inspection substantially raise risk because they can expose sensitive code/data and trigger unexpected command execution under the guise of a benign content-generation tool.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The skill is presented as an Excalidraw generator, yet the detected behavior includes scanning repository contents, reading SKILL.md/Python files, executing Python via subprocess, running tests, and checking for secrets or deploy readiness. In an agent environment, concealed execution and repo-wide inspection substantially raise risk because they can expose sensitive code/data and trigger unexpected command execution under the guise of a benign content-generation tool.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill advertises executable shell/Python usage and likely file read/write behavior, but the manifest declares no explicit tool scope or permission boundaries. In an agent setting, this can cause the orchestrator or user to underestimate the skill's ability to access the filesystem or invoke commands, increasing the chance of overbroad execution and unsafe use.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
95% confidence
Finding

This helper executes an arbitrary Python file from the target product folder as part of verification, which means an untrusted repository can run attacker-controlled code during CI or local validation. Although shell injection is avoided by passing an argument list, the core issue is unsafe execution of untrusted code, enabling remote code execution in the verifier environment.

Content

Scanner excerpt · ci/verify_product.py (reported line 37)May include surrounding context.

python
def has_self_test(fp):
    r = subprocess.run([sys.executable, fp, "self-test"], capture_output=True, text=True, timeout=30)
    return r.returncode == 0 and "PASS" in r.stdout

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · ci/verify_product.py (reported line 67)May include surrounding context.

python
all_ok &= axis(False, "frontmatter (no SKILL.md)")
        all_ok &= axis(False, "docs (no SKILL.md)")
    # 3 compiles
    comp_ok = all(subprocess.run([sys.executable, "-m", "py_compile", fp],
                                capture_output=True).returncode == 0 for fp in files)
    all_ok &= axis(comp_ok, "compiles (py_compile all .py)")
    # 4 self-test (any of 3 valid forms)

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
97% confidence
Finding

This code executes any discovered test_*.py or *_test.py file in the target folder, allowing a malicious skill package to run arbitrary code merely by being verified. In CI or developer environments, that can expose secrets, modify files, or pivot to other systems despite the absence of shell metacharacter injection.

Content

Scanner excerpt · ci/verify_product.py (reported line 79)May include surrounding context.

python
tests = [os.path.join(folder, f) for f in os.listdir(folder)
                 if (f.startswith("test_") or f.endswith("_test.py")) and f.endswith(".py")]
        if tests:
            st_ok = all(subprocess.run([sys.executable, t], capture_output=True, text=True,
                                      timeout=30).returncode == 0 for t in tests)
            st_note = f"{len(tests)} test_*.py"
        elif re.search(r"(?im)^test\s*:", skill_txt):

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · ci/verify_product.py (reported line 92)May include surrounding context.

python
# 7 deploy-ready
    ci = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ci_check.py")
    if os.path.isfile(ci) and os.path.isfile(skill):
        r = subprocess.run([sys.executable, ci], cwd=folder, capture_output=True, text=True)
        all_ok &= axis(r.returncode == 0, "deploy-ready (ci/ci_check.py PASS)")
    else:
        all_ok &= axis(True, "deploy-ready (skipped)")

Static analysis

No suspicious patterns detected.