Serve Active Storage SVGs as images, not as binary

Last night, I was building a print view for physical sticker tags, which included rendering SVG assets uploaded to ActiveStorage. I ran into a problem I’ve run into a few times before but haven’t written about yet when I added the uploaded SVG into a <img> tag, the browser downloaded the file instead of showing it. When I checked the network tab, I saw that the blob URL had a Content-Disposition: attachment header, and was being served as application/octet-stream, so the browser was treating it as a download.

Active Storage keeps image/svg+xml in content_types_to_serve_as_binary. SVG can include script, so Rails serves the blob as application/octet-stream with Content-Disposition: attachment by default.

If you understand the risk profile of SVG and want to serve it as an image, you can configure ActiveStorage to serve it as an image instead of a binary:

# config/application.rb
config.active_storage.content_types_to_serve_as_binary -= ["image/svg+xml"]

The blob then keeps image/svg+xml, and an <img> can display it.

This is a different SVG issue to re-enabling the libvips SVG loader after the Active Storage vips advisory. That one is converting SVG. This one is serving it. If you’re handling SVG ActiveStorage blobs, you’re likely to need to consider both.

Note Only do this for low-risk, trusted files. In this case, the SVGs are seeded from an asset catalog, not user uploads, so I consider this safe for my purposes.