Closed general

SVG files don't render in README/markdown (served as application/octet-stream; sanitizer also strips inline-SVG + data-URI)

John Lauer · 22d ago ·closed by Colby Knox

Use case. I author architecture / flow diagrams as the lead image on app README pages (e.g. adom/adom-chip-fetcher). They start life as SVG so they stay crisp at any zoom, scale on retina, weigh little, and carry on-brand fonts. I want to reference them in README.md like any other image.

What I tried (three ways to render an SVG), all failed on this wiki:

  1. ![diagram](diagram.svg) referencing a .svg committed to the page repo. The file serves with Content-Type: application/octet-stream, so the browser refuses to paint it and img.naturalWidth is 0x0 (broken-image). PNG/JPG serve fine (image/png). Verified: curl .../api/pages/adom/adom-chip-fetcher/files/chip-fetcher-flow.svg returns content-type: application/octet-stream.

  2. Inline <svg>...</svg> directly in README.md. The README sanitizer (sanitize-html, strict allowlist) strips <svg> entirely (and <style> / style=), so nothing renders.

  3. ![diagram](data:image/svg+xml;base64,...) data-URI. I pushed this live and checked the rendered DOM: the sanitizer drops data: image sources too (0 data-URI images survived).

Net effect. There is currently no way to show an SVG in a README. I fell back to rendering each SVG to PNG, which loses crisp vector, bloats the repo, and forced me to re-embed brand fonts + render at 2x to avoid an ugly fallback-font raster.

Proposed fix (smallest first):

  • Add .svg to the file-serving MIME map so it's served as image/svg+xml (it already maps .png to image/png). That alone makes ![](diagram.svg) render as true vector.
  • Optionally, allow a data: image scheme and/or a safe <svg> subset through the README sanitizer for inline diagrams.

Examples below. These are PNG renders so they display here; the SVG sources are committed at adom/adom-chip-fetcher as chip-fetcher-flow.svg and chip-fetcher-stack.svg. The first is a flow diagram I wanted as the README lead image; the second is the app-stack diagram that was showing as a broken image until I converted it to PNG.

issue-flow

3 Replies

John Lauer · 22d ago

Second example: the app-stack diagram (adom-chip-fetcher orchestrating its tier of apps). Same story — authored as SVG (chip-fetcher-stack.svg) but rendered as a broken image until converted to PNG. Shown here as PNG.

issue-stack

Colby Knox · 22d ago

Fixed and live on wiki.adom.inc.

.svg files now serve as image/svg+xml (under a no-script CSP: default-src 'none'; style-src 'unsafe-inline'; img-src data:; sandbox), across all three serving paths (the files API, /blob, and /render). An /README embed renders it as true vector; a direct navigation is sandboxed so the SVG can't run script in the wiki origin. The cause was not the MIME map (it had svg) but the untrusted-file downgrade that forced svg to octet-stream+attachment for XSS safety; SVG is now the documented exception.

So renders, no more broken image. Verified: GET /api/pages/adom/hook/files/docs/shot.svg returns content-type image/svg+xml (was application/octet-stream).

Scoped out for now (separate XSS-surface decision, not needed for the README-diagram use case): allowing inline or data: image URIs through the markdown sanitizer. If you want those too, open a follow-up and we will weigh the sanitizer subset.

Colby Knox · 22d ago

Confirmed live on prod: .svg files now serve as image/svg+xml (with a sandboxed CSP), so a reference renders as true vector in a README. Thanks John.

Log in to reply.