Skip to content

Remote Image Archiving

Ed Mozley edited this page Jul 11, 2026 · 2 revisions

Remote Image Archiving β€” parked idea

Warning

Status: PARKED. May never be built. This page records a design idea and, just as importantly, why we are wary of it. The core is genuinely useful; one part of it (fetching arbitrary URLs server‑side) is a Server‑Side Request Forgery (SSRF) risk serious enough that the feature only ships if that part is done to a very high standard β€” and it's entirely reasonable that it never does. Do not implement a naive version.

Related background: Email Rendering & Images explains the difference between inline (cid:) and remote (https://) email images. This page is about the remote ones.


The idea

Today, remote images in an email (<img src="https://cdn.sender.com/logo.png">) are loaded live from the sender's server by the analyst's browser each time the ticket is opened. The proposal: an opt‑in toggle that, on import, downloads those remote images into FreeITSM and rewrites the body to serve them locally (via the existing get_attachment.php pipeline) β€” so the ticket renders from local copies instead.

Why it's attractive

Three real benefits, all of which matter more for an ITSM record than for casual webmail:

  • Archival integrity. Remote image URLs rot β€” CDNs expire links, senders delete assets. A ticket is a long‑lived record; reopened months later, its remote images may be dead boxes. Local copies preserve the ticket as it arrived.
  • Privacy / anti‑tracking. Remote images are open‑tracking pixels. Every open pings the sender's server. Fetching once, server‑side, at import stops per‑view tracking leaking the analyst's activity. (This is exactly why Gmail proxies every remote image and Apple Mail caches them.)
  • Offline / resilience. The ticket renders with no route to the sender.

There's also neat reuse: FreeITSM already stores attachments and rewrites <img src> to get_attachment.php (built for inline cid: images). Localising a remote image is the same pipeline β€” only the source differs (an HTTP fetch instead of a MIME part).

Why it's dangerous β€” the SSRF landmine

The naive implementation is "the server downloads whatever URLs appear in the email." That is a textbook Server‑Side Request Forgery vulnerability. An unauthenticated stranger emails the service desk:

<img src="http://169.254.169.254/latest/meta-data/iam/security-credentials/">
<img src="http://192.168.0.1/admin/reboot">
<img src="file:///etc/passwd">

…and the server β€” from inside your firewall β€” fetches cloud‑metadata credentials, hits internal admin endpoints, or reads local files, all triggered by inbound email. It turns a convenience feature into a remote internal‑network scanner and credential‑stealer. This is the reason the feature is parked, not merely deferred.

It is mitigable, but the mitigation is the feature β€” it cannot be an afterthought:

  • Scheme allowlist: http/https only. No file:, gopher:, data:, etc.
  • Address filtering: resolve the hostname and block loopback / private / link‑local / cloud‑metadata ranges (127.0.0.0/8, 10/8, 172.16/12, 192.168/16, 169.254/16, ::1, fc00::/7, …). Re‑check after every redirect, and ideally pin the resolved IP for the actual connection to defeat DNS rebinding (resolve β†’ validate β†’ connect to that exact IP).
  • Resource caps: a few‑second timeout and a few‑MB max size per fetch, so a slow or huge target can't hang the mailbox poll or fill the disk.
  • Content validation: confirm the bytes are actually an image (content‑type and magic bytes). Treat SVG as hostile (it can carry script) β€” skip or sanitise it.

Secondary concerns (manageable, not dealbreakers)

  • Storage growth. Newsletters carry many images; importing lots of them balloons the attachments store. This is a big part of why the toggle must default off.
  • Import latency. Fetching N images per email during the poll adds time; the timeouts above bound it, and it could be deferred to a background pass rather than run inline in the poll.
  • Not a guarantee. Some remote images are auth/referer/cookie‑gated and will 403 a server‑side fetch. So it is best‑effort localisation, never "always works" β€” the UI copy must say so honestly.

If it were ever built β€” shape

  1. A hardened safe‑fetch helper (the SSRF‑guarded downloader above). This is the crux and would need explicit tests against private‑IP, redirect‑to‑private, DNS‑rebinding and non‑image cases.
  2. Wire it into the import path, reusing saveAttachment() + the get_attachment.php cid‑rewrite mechanism, so localised remote images ride the same tenant‑gated serving path as inline ones.
  3. A per‑mailbox (or global) "Archive remote images" toggle, defaulting off, with honest best‑effort help text.

The bar to ship

This feature ships only if the safe‑fetch helper is implemented and reviewed to a high standard, with the SSRF guards and their tests in place. Absent that, the correct state is parked β€” and staying parked indefinitely is an acceptable outcome. A convenient feature is not worth a server‑compromise vector.


Related pages

FreeITSM

Getting Started

Modules

Multi-tenancy (planned)

Blue sky thinking

Bugs resolved

Links

Clone this wiki locally