Back to skill

Security audit

mermaid-maker

Security checks for vulnerabilities and agentic risk

Overview

This Mermaid diagram skill is mostly purpose-aligned, but it can upload diagram contents to a third-party service and run automatic dependency installation without strong user safeguards.

Install only if you are comfortable with its setup and rendering behavior. Prefer local rendering for confidential diagrams, avoid Kroki for internal architecture or sensitive labels unless you explicitly approve the upload, and review or pin the npm dependencies before running the bundled scripts.

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)

T08 · Insecure Dependencies

Error
Location
scripts/render.mjs:11
Finding

Automatic Unpinned Dependency Installation Enables Supply-Chain Code Execution

Content
View full analysis

Vulnerability Details

File Location: scripts/render.mjs:11-34; duplicated in scripts/batch.mjs:11-34 and scripts/themes.mjs:10-33
Vulnerability Type: Automatic installation of unpinned third-party dependencies
Risk Level: High

Vulnerable Code

javascript
async function loadBeautifulMermaid() {
  try {
    return await import('beautiful-mermaid');
  } catch {}

  console.error('[beautiful-mermaid] Dependency not found. Installing automatically...');
  try {
    execSync('npm install --no-fund --no-audit', {
      cwd: skillRoot,
      stdio: ['pipe', 'pipe', 'inherit'],
      timeout: 120000,
    });
    console.error('[beautiful-mermaid] Installed successfully.\n');
  } catch (e) {
    console.error(`[beautiful-mermaid] Auto-install failed: ${e.message}`);
    console.error(`Manual fix: cd ${skillRoot} && npm install`);
    process.exit(1);
  }

  try {
    const pkgPath = join(skillRoot, 'node_modules', 'beautiful-mermaid', 'dist', 'index.js');
    return await import(pkgPath);
  } catch (e) {
    console.error(`[beautiful-mermaid] Failed to load after install: ${e.message}`);
    process.exit(1);
  }
}

Technical Analysis

All three executable scripts automatically invoke npm install when the initial import of beautiful-mermaid fails. The audited project does not contain a package.json or lockfile that pins the package version and integrity.

Consequently, installation behavior is not reproducible or constrained to an audited dependency graph. npm may use package metadata or configuration from the surrounding environment, contact configured registries, and execute dependency lifecycle scripts. The --no-audit option also disables npm's vulnerability audit for this operation.

Although the installation behavior is documented, it creates a supply-chain execution boundary without an approval step or integrity verification.

Attack Path

...[truncated 990 chars]

Remediation
View remediation

Remediation Suggestions

  1. Add a minimal package.json that declares beautiful-mermaid at an exact reviewed version.
  2. Commit a lockfile containing registry URLs and integrity hashes.
  3. Replace automatic npm install with a clear failure message and require explicit user approval before modifying dependencies.
  4. In controlled deployments, install dependencies ahead of execution with npm ci --ignore-scripts.
  5. If lifecycle scripts are required, audit them and enable them only during a dedicated installation phase.
  6. Use a trusted registry allowlist and avoid inheriting uncontrolled npm configuration from parent directories or user-level configuration.
  7. Remove --no-audit from approved installation workflows and run dependency vulnerability and provenance checks.
  8. Apply the same correction consistently to render.mjs, batch.mjs, and themes.mjs.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/batch.mjs:65
Finding

Unvalidated Worker Count Can Cause an Infinite Batch Loop

Content
View full analysis

Vulnerability Details

File Location: scripts/batch.mjs:65 and scripts/batch.mjs:147-151
Vulnerability Type: Improper numeric input validation leading to denial of service
Risk Level: Medium

Vulnerable Code

javascript
case '--workers': case '-w': opts.workers = parseInt(val); i++; break;
javascript
// Process in batches of `workers` size
for (let i = 0; i < files.length; i += opts.workers) {
  const batch = files.slice(i, i + opts.workers);
  const results = await Promise.allSettled(
    batch.map(file => renderFile(file, opts.inputDir, opts.outputDir, opts, lib))
  );

Technical Analysis

The value supplied through --workers is converted with parseInt but is never checked to ensure that it is a finite positive integer. The parsed value is then used both as the loop increment and as a slicing boundary.

If the value is 0, i += opts.workers never advances, producing an infinite loop. A negative value can move the loop counter backward, while a nonnumeric value produces NaN and invalid loop behavior. With zero workers, each iteration processes an empty batch and repeatedly emits progress-related work without terminating.

Attack Path

  1. An attacker, automation system, or mistaken caller controls the arguments passed to batch.mjs.
  2. The script is invoked with a value such as --workers 0.
  3. parseInt("0") assigns zero to opts.workers.
  4. The loop executes with i += 0, so the index never advances.
  5. The process remains active indefinitely until externally terminated, consuming runtime and potentially generating excessive output.

Impact Assessment

Exploitation affects availability of the rendering process and any Agent workflow waiting for it to complete. It does not grant additional filesystem or operating-system privileges. In automated environments, the hang may consume execution slots, exhaust logs, trigger job timeouts, or block depen ...[truncated 21 chars]

Remediation
View remediation

Remediation Suggestions

Validate the option immediately after parsing:

javascript
const workers = Number(val);
if (!Number.isInteger(workers) || workers < 1 || workers > 32) {
  console.error('Error: --workers must be an integer between 1 and 32.');
  process.exit(1);
}
opts.workers = workers;

Also enforce the invariant before entering the processing loop, even if argument parsing is later refactored. Apply a conservative upper bound to prevent excessive concurrent rendering and resource exhaustion. Add tests for zero, negative, missing, fractional, nonnumeric, and excessively large values.

other

Warning
Location
SKILL.md:54
Finding

Remote Rendering Can Disclose Complete Diagram Source to a Third Party

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:54-64 and SKILL.md:76-82; expanded guidance in reference/RENDERING.md:86-116
Vulnerability Type: Potential sensitive-data disclosure through an external rendering service
Risk Level: Medium

Vulnerable Instructions

markdown
| Need | Backend | One-line command |
|------|---------|------------------|
| Themed SVG, ASCII, or batch | **beautiful-mermaid** | `node scripts/render.mjs -i d.mmd -o d.svg --theme tokyo-night` |
| PNG or PDF, offline | **mmdc** | `mmdc -i d.mmd -o d.png -w 2048 --backgroundColor white` |
| No install (just curl) | **Kroki** | `curl -X POST -H "Content-Type: text/plain" --data-binary @d.mmd https://kroki.io/mermaid/svg -o d.svg` |
bash
curl -s -X POST -H "Content-Type: text/plain" --data-binary @diagram.mmd https://kroki.io/mermaid/svg -o /tmp/test.svg && echo Valid || echo Invalid

Technical Analysis

The Kroki backend uploads the complete Mermaid source file to https://kroki.io. Diagram source may contain internal service names, network topology, database schemas, endpoint paths, authentication sequences, operational procedures, or customer-related labels.

The documentation identifies Kroki as an external API, so the behavior is not hidden. However, it does not require explicit user consent, classify diagram sensitivity, warn against transmitting confidential content, or define retention and trust requirements. The validation workflow can also upload a diagram merely to test its syntax.

Attack Path

  1. An Agent generates or receives a diagram containing confidential architectural or operational information.
  2. The local rendering dependency is unavailable, or Kroki is selected as the convenient no-install backend.
  3. The documented curl command reads the entire local .mmd file.
  4. The complete source is transmitted to the third-party Kroki endpoint.
  5. The data leaves the local trust ...[truncated 508 chars]
Remediation
View remediation

Remediation Suggestions

  1. Prefer local rendering by default and treat Kroki as an explicit opt-in backend.
  2. Display a warning that the complete diagram source will be transmitted to a third party.
  3. Require affirmative user consent immediately before the first remote submission.
  4. Do not use remote validation for files marked confidential or containing secrets, internal hostnames, private schemas, customer information, or security architecture.
  5. Offer a redaction step that replaces sensitive labels before upload.
  6. Support organization-approved self-hosted Kroki endpoints and endpoint allowlisting.
  7. Document the external service's applicable privacy, logging, and retention considerations.
  8. Ensure failed remote responses are not treated as successful validation solely because curl completed; use curl --fail-with-body and verify the returned content type.
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (16)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 63)May include surrounding context.

md
- **Batch** a folder: `node scripts/batch.mjs -i ./diagrams -o ./out --theme dracula -w 4`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 72)May include surrounding context.

md
List all: `node scripts/themes.mjs`. Full catalog, custom palettes, and a decision tree: [THEMES.md](reference/THEMES.md).

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill description says to proactively use this skill when explaining nearly any system with 3+ components, API flows, schemas, or state machines. That trigger is broad enough to cause unintended invocation in routine conversations, increasing the chance of unnecessary file creation, tool execution, dependency installation, or network use without a clear user request.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
97% confidence
Finding

This command posts @d.mmd directly to https://kroki.io/mermaid/svg, which transmits the entire diagram content to an external service. In the context of an agent skill for architecture and flow diagrams, that content may include proprietary topology, trust boundaries, or operational details, making unintended exfiltration a realistic risk.

Content

Scanner excerpt · SKILL.md (reported line 60)May include surrounding context.

md
|------|---------|------------------|
| Themed SVG, ASCII, or batch | **beautiful-mermaid** | `node scripts/render.mjs -i d.mmd -o d.svg --theme tokyo-night` |
| PNG or PDF, offline | **mmdc** | `mmdc -i d.mmd -o d.png -w 2048 --backgroundColor white` |
| No install (just curl) | **Kroki** | `curl -X POST -H "Content-Type: text/plain" --data-binary @d.mmd https://kroki.io/mermaid/svg -o d.svg` |

- **ASCII** (terminal / README): `node scripts/render.mjs -i d.mmd -f ascii --use-ascii`
- **Batch** a folder: `node scripts/batch.mjs -i ./diagrams -o ./out --theme dracula -w 4`

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill instructs sending the full diagram source to the Kroki API via curl, but does not warn the user that diagram contents will leave the local environment. Mermaid diagrams often encode internal architecture, credentials placeholders, endpoints, database names, or other sensitive design details, so silent transmission to a third-party service can leak confidential information.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
97% confidence
Finding

The validation step also posts @diagram.mmd to Kroki, meaning even a 'syntax check' can exfiltrate diagram contents externally. Because validation is marked as required, users or agents may perform this network transfer routinely and without realizing they are disclosing potentially sensitive internal design data.

Content

Scanner excerpt · SKILL.md (reported line 81)May include surrounding context.

bash
node scripts/render.mjs -i diagram.mmd -o /tmp/test.svg          # beautiful-mermaid
mmdc -i diagram.mmd -o /tmp/test.png 2>&1                        # mmdc
curl -s -X POST -H "Content-Type: text/plain" --data-binary @diagram.mmd https://kroki.io/mermaid/svg -o /tmp/test.svg && echo Valid || echo Invalid

A Could not find Chrome error from mmdc is a setup problem, not a syntax error — don't rewrite valid .mmd; fix the browser or validate via another backend.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding

The skill recommends running npx puppeteer without pinning a specific version, which can fetch and execute whatever package version is current at invocation time. That creates a supply-chain risk and harms reproducibility, especially in an agent skill that may be run automatically in diverse environments.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The Kroki examples instruct users to POST raw .mmd diagram contents to a third-party service but do not clearly warn that the diagram data leaves the local environment. Diagrams often contain architecture, internal service names, endpoints, credentials-in-comments, or other sensitive design details, so silent transmission to an external service can cause data exposure.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
95% confidence
Finding

The documented curl command sends the contents of diagram.mmd to https://kroki.io/mermaid/svg, which is an external network transmission of potentially sensitive user data. In a diagram-generation skill, this is contextually more dangerous because users may render proprietary architecture, workflows, or infrastructure relationships and may not realize the public API receives the full source diagram.

Content

Scanner excerpt · reference/RENDERING.md (reported line 90)May include surrounding context.

bash
# SVG
curl -X POST -H "Content-Type: text/plain" --data-binary @diagram.mmd https://kroki.io/mermaid/svg -o diagram.svg

# PNG
curl -X POST -H "Content-Type: text/plain" --data-binary @diagram.mmd https://kroki.io/mermaid/png -o diagram.png

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script automatically runs npm install via execSync when a dependency is missing, which introduces package management and subprocess execution at runtime rather than limiting behavior to diagram rendering. This expands the attack surface: installation lifecycle scripts from dependencies can execute arbitrary code, network access is triggered implicitly, and users may run unexpected code simply by invoking the batch renderer.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script automatically runs npm install when a dependency is missing, which causes network access and execution of package installation logic in the skill's directory without explicit user approval. This expands the trust boundary at runtime and can lead to execution of malicious lifecycle scripts, dependency confusion, or installation of tampered packages if the environment or dependency resolution is compromised.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill modifies its execution environment by installing packages at runtime, but this side effect is not part of the expected behavior of a theme-listing utility. Hidden environment mutation increases risk because users or higher-level agents may invoke the script assuming it is read-only, while it can instead fetch and execute external package code and alter the dependency tree.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script automatically runs npm install in a subprocess when a dependency is missing, which changes the local environment and executes package-install lifecycle behavior without explicit user approval. This creates supply-chain and unexpected code-execution risk, especially if lockfiles or dependency sources are compromised, even though the command is scoped to the skill directory and appears intended as convenience rather than abuse.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

SQP-3 applies to all file types and covers language or locale policy violations. This markdown file presents all instructions, examples, and guidance only in Chinese, with no indication that the skill is region-specific or that users can opt into another language.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/batch.mjs:18

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/render.mjs:18

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/themes.mjs:17