SvgSanitizer (svg_sanitizer v0.1.0)

Copy Markdown View Source

Vetted SVG sanitizer for Elixir.

Wraps the Rust svg-hush crate from Cloudflare in a precompiled NIF. Use it to neutralize user-uploaded SVG before storing or serving — strips <script>, event handlers, foreign objects, external references, and other XSS vectors.

Example

iex> {:ok, _clean} = SvgSanitizer.sanitize("<svg xmlns='http://www.w3.org/2000/svg'/>")

Embedded raster data URLs (PNG/JPEG/GIF/WebP) are preserved so sanitized SVGs remain self-contained; all other URL schemes (including javascript: and arbitrary data: types) are stripped.

The NIF runs on a dirty CPU scheduler so a slow sanitization does not block normal schedulers, and surfaces parse/IO errors as {:error, atom} rather than crashing the VM.

Summary

Types

Why sanitization didn't yield a clean binary. Always an atom — stable for pattern matching, doesn't leak internal parser state.

Functions

Returns a sanitized copy of the given SVG.

Types

reason()

@type reason() ::
  :invalid_input | :input_too_large | :parse_error | :panic | :alloc_failed

Why sanitization didn't yield a clean binary. Always an atom — stable for pattern matching, doesn't leak internal parser state.

  • :invalid_input — input wasn't a binary.
  • :input_too_large — input over 5242880 bytes; rejected without parsing.
  • :parse_error — svg-hush rejected the input (malformed XML, unsupported encoding, etc.). Treat as "reject this upload".
  • :panic — Rust layer panicked (caught at the NIF boundary, BEAM unaffected). Stack overflow is not caught and aborts the node; svg-hush's iterative parser keeps stack usage bounded in practice.
  • :alloc_failed — out of memory while copying the sanitized output.

Functions

sanitize(svg)

@spec sanitize(term()) :: {:ok, binary()} | {:error, reason()}

Returns a sanitized copy of the given SVG.

Accepts a binary up to 5242880 bytes. Returns {:ok, sanitized_binary} on success, {:error, reason} on rejection. See reason/0 for the full set of error atoms.

Always handle {:error, _}. Non-binary input, oversized input, malformed XML, and adversarial payloads all land there; pattern-matching only on {:ok, _} is a MatchError waiting to happen.