# How the Mermaid securityLevel Configuration Impacts Diagram Rendering and XSS Protection

> Explore Mermaid's securityLevel effects on diagram rendering and XSS protection. Understand 'strict', 'loose', 'antiscript', and 'sandbox' options to secure your applications.

- Repository: [mermaid-js/mermaid](https://github.com/mermaid-js/mermaid)
- Tags: deep-dive
- Published: 2026-02-23

---

**The `securityLevel` configuration in Mermaid controls how much HTML and JavaScript is allowed in diagram source text, with options ranging from `'strict'` (full sanitization) to `'sandbox'` (isolated iframe rendering), directly determining the XSS attack surface of your application.**

The `mermaid-js/mermaid` library parses diagram definitions and injects the resulting SVG or HTML into web pages, making the `securityLevel` configuration critical for preventing cross-site scripting (XSS) attacks. This setting determines whether scripts execute, HTML tags render, or content remains isolated in sandboxed iframes. Understanding how each level impacts the rendering pipeline helps you balance visual flexibility against security requirements.

## The Four securityLevel Options Explained

Mermaid’s security model is defined in [`src/config.type.ts`](https://github.com/mermaid-js/mermaid/blob/main/src/config.type.ts) and enforced throughout the rendering pipeline in [`src/mermaidAPI.ts`](https://github.com/mermaid-js/mermaid/blob/main/src/mermaidAPI.ts). Each level triggers distinct sanitization behaviors in [`src/diagrams/common/common.ts`](https://github.com/mermaid-js/mermaid/blob/main/src/diagrams/common/common.ts) and [`src/utils.ts`](https://github.com/mermaid-js/mermaid/blob/main/src/utils.ts).

### Strict (Default) – Maximum Protection

When `securityLevel` is set to `'strict'`, Mermaid encodes all HTML tags and disables interactive features. In [`src/diagrams/common/common.ts`](https://github.com/mermaid-js/mermaid/blob/main/src/diagrams/common/common.ts), the `sanitizeMore` helper (lines 70-78) breaks markup into placeholders and escapes `<`, `>`, and `=` characters to neutralize any HTML injection attempts.

Additionally, [`src/mermaidAPI.ts`](https://github.com/mermaid-js/mermaid/blob/main/src/mermaidAPI.ts) runs DOMPurify sanitization on the generated SVG unless `isLooseSecurityLevel` is true. Click handlers defined via `click` directives in diagram syntax are completely disabled, ensuring no JavaScript execution occurs.

### Antiscript – HTML Without JavaScript

The `'antiscript'` level allows rich HTML markup such as `<b>`, `<div>`, or `<span>` tags while stripping all `<script>` elements. In `sanitizeMore`, when the level is detected as `'antiscript'`, the code calls `removeScript` which executes `DOMPurify.sanitize(txt)` specifically targeting script tags (lines 70-73).

Interactive features remain enabled, meaning `click` callbacks and hyperlinks function normally. However, the remaining HTML can still affect page styling or layout, requiring trust in the diagram source.

### Loose – Full HTML and JavaScript Support

Setting `securityLevel` to `'loose'` provides maximum flexibility but opens significant security vulnerabilities. In [`src/mermaidAPI.ts`](https://github.com/mermaid-js/mermaid/blob/main/src/mermaidAPI.ts) (lines 52-59), the DOMPurify step is entirely skipped when `isLooseSecurityLevel` evaluates to true.

Furthermore, [`src/utils.ts`](https://github.com/mermaid-js/mermaid/blob/main/src/utils.ts) (lines 55-58) shows that the `formatUrl` helper bypasses URL sanitization for `'loose'` mode, allowing `javascript:` protocol links and other potentially dangerous URLs. This enables embedding iframes, custom CSS, and inline event handlers, but exposes applications to full XSS attacks if malicious actors control the diagram text.

### Sandbox – Isolated Iframe Rendering

The `'sandbox'` option renders diagrams inside a sandboxed iframe to isolate potentially malicious content. In [`src/mermaidAPI.ts`](https://github.com/mermaid-js/mermaid/blob/main/src/mermaidAPI.ts) (lines 55-60), the code creates a `sandboxedIframe` when `config.securityLevel === SECURITY_LVL_SANDBOX`. The generated SVG is injected into this isolated document rather than the parent page.

Scripts execute within the iframe’s restricted context only, preventing access to the host page’s DOM, cookies, or localStorage. However, interactive features requiring parent context—such as `click` callbacks that trigger main page navigation or pop-ups—cease to function.

## Technical Implementation in the Source Code

### Configuration Definitions

The TypeScript type definition in [`src/config.type.ts`](https://github.com/mermaid-js/mermaid/blob/main/src/config.type.ts) declares the valid options:

```typescript
securityLevel?: 'strict' | 'loose' | 'antiscript' | 'sandbox'

```

The YAML schema in [`src/schemas/config.schema.yaml`](https://github.com/mermaid-js/mermaid/blob/main/src/schemas/config.schema.yaml) documents each enum value’s semantics and default behavior, which feeds into the official documentation at [`src/docs/config/usage.md`](https://github.com/mermaid-js/mermaid/blob/main/src/docs/config/usage.md).

### The Sanitization Pipeline

The core sanitization logic resides in [`src/diagrams/common/common.ts`](https://github.com/mermaid-js/mermaid/blob/main/src/diagrams/common/common.ts). The `sanitizeMore` function implements level-specific processing:

1. **For `'strict'`**: Removes `<script>` tags, then replaces `<`, `>`, and `=` with placeholders to escape remaining HTML
2. **For `'antiscript'`**: Strips scripts via DOMPurify but preserves other HTML markup
3. **For `'loose'`**: Performs no additional escaping beyond baseline processing

### URL Validation Bypass

In [`src/utils.ts`](https://github.com/mermaid-js/mermaid/blob/main/src/utils.ts), the `formatUrl` function demonstrates the security level’s impact on hyperlink handling:

```typescript
// Line 55-58: Conditional bypass for 'loose' mode
if (securityLevel === 'loose') {
  return url;
}

```

Under `'strict'`, `'antiscript'`, or `'sandbox'` modes, `javascript:` URLs and other dangerous protocols return `undefined`, effectively neutralizing them.

## Security Trade-offs and Recommended Usage

| Level | Attack Surface | Risk with Malicious Input | Recommended Use Case |
|-------|---------------|---------------------------|---------------------|
| **Strict** | Minimal | None—scripts removed, HTML escaped, clicks disabled | Public-facing sites, untrusted user content |
| **Antiscript** | Moderate | Layout/style manipulation possible, but no script execution | Internal documentation requiring rich formatting |
| **Loose** | High | Full XSS capability including script injection and cookie theft | Trusted environments only—internal tools with vetted authors |
| **Sandbox** | Low (isolated) | Scripts run in iframe only; cannot access parent page | Rendering untrusted diagrams where visual fidelity matters |

## Practical Configuration Examples

### Global Initialization

Configure the security level when initializing Mermaid:

```javascript
// Strict default—safest for public sites
mermaid.initialize({
  securityLevel: 'strict',
});

// Allow HTML formatting but block scripts
mermaid.initialize({
  securityLevel: 'antiscript',
});

// Maximum flexibility—use with caution
mermaid.initialize({
  securityLevel: 'loose',
});

// Isolated rendering for untrusted content
mermaid.initialize({
  securityLevel: 'sandbox',
});

```

### Per-Render Override

Override the global setting for individual diagram renders:

```javascript
mermaid.render(
  'diagram-id',
  'graph TD; A-->B; click B "https://example.com"',
  (svgCode) => {
    document.getElementById('output').innerHTML = svgCode;
  },
  null,
  { securityLevel: 'sandbox' } // Merges with global config via processAndSetConfigs
);

```

### URL Handling Comparison

Demonstrating `formatUrl` behavior across levels:

```javascript
// Returns undefined—sanitized
formatUrl('javascript:alert(1)', { securityLevel: 'strict' });

// Returns 'javascript:alert(1)'—dangerous
formatUrl('javascript:alert(1)', { securityLevel: 'loose' });

```

## Summary

- **`'strict'`** (default) encodes all HTML and disables click handling, providing maximum XSS protection via DOMPurify and character escaping in [`src/diagrams/common/common.ts`](https://github.com/mermaid-js/mermaid/blob/main/src/diagrams/common/common.ts).
- **`'antiscript'`** permits HTML markup while stripping `<script>` tags, balancing formatting flexibility with script security.
- **`'loose'`** bypasses DOMPurify in [`src/mermaidAPI.ts`](https://github.com/mermaid-js/mermaid/blob/main/src/mermaidAPI.ts) and URL sanitization in [`src/utils.ts`](https://github.com/mermaid-js/mermaid/blob/main/src/utils.ts), enabling full HTML/JS support but requiring complete trust in diagram sources.
- **`'sandbox'`** isolates rendering in a sandboxed iframe created in [`src/mermaidAPI.ts`](https://github.com/mermaid-js/mermaid/blob/main/src/mermaidAPI.ts), preventing parent page access while sacrificing some interactive features.

## Frequently Asked Questions

### What is the difference between 'strict' and 'antiscript' security levels?

The `'strict'` level encodes all HTML characters (converting `<` and `>` to entities) and disables click interactions entirely, while `'antiscript'` allows HTML tags like `<b>` or `<div>` to render but specifically removes `<script>` elements using DOMPurify. Choose `'strict'` when you want zero HTML rendering capability, or `'antiscript'` when you need formatting but must prevent script execution.

### When should I use the 'sandbox' security level?

Use `'sandbox'` when rendering diagrams from untrusted sources but where visual fidelity is important. According to the implementation in [`src/mermaidAPI.ts`](https://github.com/mermaid-js/mermaid/blob/main/src/mermaidAPI.ts), this level creates an isolated iframe that prevents scripts from accessing the parent page’s DOM or cookies, though it disables click callbacks that interact with the main window.

### Can I override securityLevel for individual diagrams?

Yes. While you can set a global default via `mermaid.initialize()`, the `render` function accepts an options parameter that merges with global configuration through `processAndSetConfigs`. Pass `{ securityLevel: 'sandbox' }` as the fifth argument to `mermaid.render()` to override the global setting for that specific diagram.

### Why does 'loose' mode pose an XSS risk?

In `'loose'` mode, Mermaid skips the DOMPurify sanitization step in [`src/mermaidAPI.ts`](https://github.com/mermaid-js/mermaid/blob/main/src/mermaidAPI.ts) (lines 52-59) and disables URL validation in [`src/utils.ts`](https://github.com/mermaid-js/mermaid/blob/main/src/utils.ts) (lines 55-58). This allows attackers to inject `<script>` tags, `javascript:` URLs, or inline event handlers into diagram text, enabling cookie theft, session hijacking, or arbitrary code execution in the user’s browser. Only use `'loose'` when you completely control and trust the diagram source.