SvgSanitizer
Vetted SVG sanitizer for Elixir. Thin precompiled NIF wrapping Cloudflare's
svg-hush Rust crate, so applications
can accept user-uploaded SVG without authoring their own allowlist scrubber
— <script>, event handlers, foreign objects, external references, and
javascript:/data: URL vectors are stripped, raster image data URLs (PNG /
JPEG / GIF / WebP) are preserved so sanitized SVGs stay self-contained.
The NIF runs on a dirty CPU scheduler and converts Rust panics into
{:error, term} rather than crashing the BEAM node.
Installation
def deps do
[
{:svg_sanitizer, "~> 0.1"}
]
end
Precompiled artifacts are published to GitHub releases for these targets;
mix deps.get downloads the right one — no Rust toolchain required:
aarch64-unknown-linux-gnux86_64-unknown-linux-gnu
OTP 26+ required (NIF 2.17). Earlier NIF versions will be added on demand.
macOS users: v0.1 doesn't ship precompiled macOS artifacts (the
rustler-precompiled-action mishandles cross on Apple Silicon; tracked
for v0.2). Build from source by setting SVG_SANITIZER_BUILD=1; you'll need
cargo installed.
Usage
case SvgSanitizer.sanitize(user_uploaded_svg) do
{:ok, clean} ->
store_asset(clean)
{:error, reason} ->
# reason is one of:
# :invalid_input — input wasn't a binary
# :input_too_large — over 5 MB; rejected without parsing
# :parse_error — svg-hush rejected as malformed
# :panic — Rust layer panicked (caught, BEAM safe)
# :alloc_failed — out of memory while building output
Logger.warning("svg sanitize failed: #{reason}")
reject_upload(reason)
end
Always handle {:error, _}. SVG input from users will hit one of those
branches eventually; pattern-matching only on {:ok, _} is a MatchError
waiting to happen.
Why a separate package
Elixir has no purpose-built SVG sanitizer; html_sanitize_ex is HTML-only
and pointing it at SVG amounts to hand-rolling an allowlist (which is what
makes SVG sanitization dangerous — the TYPO3 PSA-2025-001
advisory traces a
real-world bypass to exactly that). svg-hush is Cloudflare-maintained,
allowlist-based, and security-focused; this package is the thin glue that
makes it available to Phoenix / Plug / LiveView applications.
License
Apache-2.0 — matches the upstream svg-hush crate.