-
Notifications
You must be signed in to change notification settings - Fork 15
Remote Image Archiving
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.
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.
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).
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/httpsonly. Nofile:,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.
- 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
403a serverβside fetch. So it is bestβeffort localisation, never "always works" β the UI copy must say so honestly.
- 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.
- Wire it into the import path, reusing
saveAttachment()+ theget_attachment.phpcidβrewrite mechanism, so localised remote images ride the same tenantβgated serving path as inline ones. - A perβmailbox (or global) "Archive remote images" toggle, defaulting off, with honest bestβeffort help text.
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.
- Email Rendering & Images β inline vs remote images, the serving pipeline, CSS isolation
- Security β encryption and access control
- Basic IMAP mailboxes
FreeITSM β an open-source IT Service Management platform Β· github.com/edmozley/freeitsm Β· MIT licence
- Installation
- β° Scheduled tasks (cron jobs)
- Architecture
- AI Providers
- Internationalisation (i18n)
- Timezones & Time Handling
- Theming & Dark Mode
- β¨οΈ Command palette (βK)
- π Searching inside tickets
- π Attached documents
- MobileβFriendly
-
Security
- Layer 1 β which modules you can enter
- β³ π§© Module Access Control
- β³ π οΈ Module Access β Developer Guide
- Layer 2 β what you can administer
- β³ π Roles & Permissions
- β³ π οΈ Roles β Developer Guide
- β³ π€ Why capabilities are constants
- Layer 3 β the System module
- β³ π Admin Access Control
- Hardening
- β³ π Security review response 2026-08
- β³ π‘οΈ Security hardening 2026-08
- β³ π οΈ Security hardening 2026-08 β Developer Guide
- β³ π‘οΈ Round three β plain English
- β³ π οΈ Round three β Developer Guide
- Single Sign-On (SSO)
- ποΈ LDAP & Active Directory
- Browser Extension
- API Reference
-
π REST API β how it works
- β³ π« REST API: Tickets
- β³ π» REST API: Assets
- β³ π΄ REST API: Problems
- β³ π REST API: Changes
- β³ π REST API: Knowledge
- β³ β REST API: Tasks
- β³ ποΈ REST API: CMDB
- β³ π REST API: Contracts
- β³ ποΈ REST API: Calendar
- β³ πΏ REST API: Software
- β³ π¦ REST API: Service Status
- β³ βοΈ REST API: Morning Checks
- β³ π REST API: Forms
- β³ βοΈ REST API: Workflow
- β³ πΊοΈ REST API: Network Mapper
- β³ π§ Using the API docs page
- β³ π OpenAPI specification
- β³ β OpenAPI: kept correct
- β³ π οΈ Maintaining the catalogue
- Watchtower
-
Tickets
- β³ Mailbox Authentication
- β³ π€ Email send log
- β³ Basic IMAP mailboxes
- β³ Email rendering & images
- β³ SLA Management
- β³ WhatsApp channel
- β³ π¬ Web chat channel
- β³ π£ Slack channel
- β³ π Linking tickets
- β³ ποΈ Canned responses
- β³ βοΈ Limiting replies to particular senders
- β³ βοΈ Email signatures
- β³ π The public web address
- β³ π Raising a ticket for someone else
- β³ π Merging tickets
- β³ β Splitting tickets
- β³ β Selecting several tickets
- β³ π οΈ Snoozing tickets β Developer Guide
- β³ π₯ Collision detection
- β³ β±οΈ Time tracking
- Problem Management
- Tasks
- Assets
- Knowledge
- Change Management
- Calendar
- Morning Checks
- Reporting
- Software
- Forms
- Contracts
- Service Status
- π Notifications
- π¨ War Room
- Self-Service Portal
- LMS
- Process Mapper
- CMDB
- Network Mapper
- Workflows
- Issue trackers (Jira, Azure DevOps)
- System
-
Overview
- β³ π Progress tracker
- β³ Concepts & vocabulary
- β³ Email routing & mailboxes
- β³ Settings: global vs per-company
- β³ Users & self-service
- β³ Staff cross-company access
- β³ Worked examples
- β³ Pitfalls & gotchas
- β³ Scope: what it's for
- β³ π οΈ Developer Guide (make a module multi-company)
- β³ ποΈ Case study: CMDB (a linked graph)
- β³ π§ͺ Test harness (prove it's isolated)