Back to skill

Security audit

Diagrams

Security checks for vulnerabilities and agentic risk

Overview

This diagram skill is mostly purpose-aligned, but its optional PNG conversion path contains an unsafe shell command that can be abused through crafted file or folder names.

Review this skill before installing if you will render diagrams from other people or shared repositories. Use it only on trusted diagram files and safe filenames, avoid `--png` until the shell invocation is fixed, and pin `elkjs` in a lockfile for reproducible installs.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/render-elk.mjs:273
Finding
Shell Command Injection During PNG Conversion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/render-elk.mjs:273-281` **Vulnerability Type**: OS command injection through shell-interpreted file paths **Risk Level**: High ### Vulnerable Code ```js if (doPng) { try { const pngName = file.replace('.json', '.png'); execSync(`sips -s format png "${join(outDir, svgName)}" --out "${join(outDir, pngName)}" 2>/dev/null`); console.log(` ✅ ${file} → svg/${svgName} + svg/${pngName}`); } catch { console.log(` ✅ ${file} → svg/${svgName} (PNG conversion failed — sips not available?)`); } } ``` ### Technical Analysis The script constructs a shell command by interpolating the user-selected directory and discovered JSON filename into a string passed to `execSync`. Node.js executes this string through a shell. Although the paths are surrounded by double quotes, double quotes do not suppress shell command substitution such as `$(...)`. Embedded quotes can also terminate the intended quoted argument. Consequently, a malicious directory name or `.json` filename containing shell metacharacters can cause arbitrary commands to be evaluated. The `.json` filename filter does not prevent exploitation because a malicious filename can contain shell syntax while still ending in `.json`. The broad `catch` block may also obscure exploitation by reporting a normal PNG conversion failure after the injected command has run. ### Attack Path 1. An attacker creates or supplies a diagram directory containing a valid JSON file whose filename includes shell command-substitution syntax and ends in `.json`. 2. A user runs the documented batch conversion command with PNG generation enabled: ```bash node scripts/render-elk.mjs --dir <attacker-controlled-folder> --png ``` 3. The malicious filename is used to construct `svgName` and `pngName`. 4. The interpolated command is passed to `execSync`. 5. The shell evaluates the attacker-controlled syntax before invoking `sips`. 6. The injected command exe ...[truncated 529 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Avoid invoking a shell. Replace `execSync` with an argument-based process API such as `execFileSync`: ```js import { execFileSync } from 'child_process'; execFileSync( 'sips', ['-s', 'format', 'png', join(outDir, svgName), '--out', join(outDir, pngName)], { stdio: 'ignore' } ); ``` Additional hardening should include: 1. Reject filenames containing control characters. 2. Resolve and normalize input and output paths. 3. Verify that generated output paths remain inside the intended output directory. 4. Avoid broad error handling that conceals the actual failure reason; report conversion errors safely without exposing sensitive environment data. 5. Add regression tests using filenames containing spaces, quotes, dollar signs, parentheses, semicolons, and newline characters. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/render-elk.mjs:149
Finding
Unvalidated Diagram Properties Permit Active SVG Markup Injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/render-elk.mjs:149-166` and `scripts/render-elk.mjs:213-218` **Vulnerability Type**: SVG/XML attribute and markup injection **Risk Level**: Medium ### Vulnerable Code ```js const edgeColor = edge.edgeColor || '#64748B'; const strokeWidth = edge.strokeWidth || 1.5; const isDashed = edge.dashed; for (const section of sections) { const start = section.startPoint; const end = section.endPoint; const bends = section.bendPoints || []; let d = `M ${start.x} ${start.y}`; for (const bend of bends) d += ` L ${bend.x} ${bend.y}`; d += ` L ${end.x} ${end.y}`; svg += ` <path d="${d}" fill="none" stroke="${edgeColor}" stroke-width="${strokeWidth}" marker-end="url(#arrowhead-${edgeColor.replace('#', '')})"${isDashed ? ' stroke-dasharray="5,3"' : ''}/>\n`; } ``` The same untrusted color value is later inserted into SVG marker definitions: ```js for (const color of edgeColors) { const id = color.replace('#', ''); svg += ` <marker id="arrowhead-${id}" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto">\n`; svg += ` <polygon points="0 0, 8 3, 0 6" fill="${color}"/>\n`; svg += ` </marker>\n`; } ``` ### Technical Analysis The `edgeColor` property originates in the input JSON and is inserted directly into several XML attributes without escaping or format validation. Calling `replace('#', '')` only removes one hash character; it does not make the value safe for use as an XML identifier or attribute value. An attacker can include quotation marks and XML markup in `edgeColor` to terminate the intended attribute and introduce additional attributes or SVG elements. This can produce event handlers, script elements, external references, or other active SVG content. Other style and geometry properties, including `strokeWidth` and layout-produced coordinates, are also interpolated into SVG markup without explicit finite-number and range validation. The clearest directly attacker ...[truncated 1414 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce a strict allowlist for edge colors before layout or rendering. For example: ```js function validateColor(value) { if (typeof value !== 'string' || !/^#[0-9A-Fa-f]{6}$/.test(value)) { throw new Error('Invalid edgeColor'); } return value; } ``` 2. Generate marker identifiers independently of input, such as using a numeric index or a cryptographic digest of an already validated color. 3. XML-escape every string inserted into SVG attributes or text nodes. 4. Require geometry and style values to be finite, bounded numbers: ```js if (!Number.isFinite(value) || value < MIN || value > MAX) { throw new Error('Invalid numeric property'); } ``` 5. Validate the entire input document against a strict JSON Schema with unknown properties rejected where practical. 6. Sanitize the final SVG with an allowlist-based SVG sanitizer before writing or publishing it. 7. Serve generated SVGs with a restrictive Content Security Policy and safe content disposition when they may originate from untrusted input. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:14
Finding
Unpinned npm Dependency Installation Creates Supply-Chain Exposure<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:14-18` **Vulnerability Type**: Unpinned third-party dependency installation **Risk Level**: Low ### Vulnerable Code ```bash cd <project>/docs/diagrams && npm init -y && npm install elkjs # Set "type": "module" in package.json ``` ### Technical Analysis The installation instructions use `npm install elkjs` without an exact version or a committed lockfile. The installed package and its transitive dependency graph therefore depend on the registry state at installation time. This makes installations non-reproducible and exposes users to future compromised releases, malicious maintainer changes, or unexpected dependency updates. npm package installation can also execute package lifecycle scripts, increasing the potential impact of a compromised dependency. The reviewed project does not itself demonstrate that `elkjs` is malicious. The issue is the unsafe, mutable dependency acquisition process documented by the Skill. ### Attack Path 1. A future `elkjs` release or one of its resolved transitive dependencies is compromised or introduces unsafe behavior. 2. A user follows the Skill documentation and runs `npm install elkjs`. 3. npm resolves the current registry version rather than a previously audited exact version. 4. The changed package is downloaded and installed; applicable lifecycle scripts may run during installation. 5. Malicious or vulnerable dependency code subsequently executes during installation or diagram rendering. ### Impact Assessment The maximum impact depends on the behavior of a compromised package. Dependency installation scripts and runtime code execute with the privileges of the user performing installation or running the renderer. Potential consequences include source-code modification, credential theft, environment-variable exposure, or arbitrary user-level code execution. No present compromise of the named dependency was established during this audit. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `elkjs` to an audited exact version rather than using an unconstrained installation command: ```bash npm install --save-exact elkjs@<audited-version> ``` 2. Commit `package.json` and `package-lock.json` with the Skill or its supported project template. 3. Direct users to run `npm ci` so installation follows the reviewed lockfile exactly. 4. Review dependency integrity metadata and periodically audit the locked dependency tree. 5. Use automated dependency monitoring, but require review and testing before updating the lockfile. 6. Where compatible with the package, consider disabling lifecycle scripts during installation using `npm ci --ignore-scripts`. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (2)

Vague Triggers

Medium
Confidence
95% confidence
Finding
The manifest description says to use the skill when the user asks for flowcharts, architecture diagrams, system diagrams, interaction maps, or "any visual diagram." That final phrase is very broad and lacks limiting context or exclusion examples, which could cause the skill to activate for generic diagram-related requests beyond its intended ELK/JSON rendering workflow.

Context-Inappropriate Capability

Medium
Confidence
85% confidence
Finding
The skill manifest describes generating diagrams and rendering them to SVG/PNG, but this file achieves PNG output by spawning an external system command with `child_process.execSync`. Executing subprocesses is a broader capability than pure diagram rendering and is not explicitly declared in the manifest, making it context-inappropriate for the stated purpose.