Feb 14, 2026·7 min read·15 visits
Umbraco Forms uploads processed by ImageSharp get tagged with 'public' cache headers. CDNs respect this, caching private data at the edge. Attackers who guess the URL can download sensitive files without authentication.
A subtle but dangerous interaction between Umbraco Forms, ImageSharp, and Content Delivery Networks (CDNs) allows sensitive user uploads—such as passport scans or medical documents—to be cached publicly at the edge. While the files are stored in a protected directory on the server, the image processing library inadvertently tags them with aggressive public caching headers. If an administrator views these files in the backoffice, the CDN caches the response, allowing unauthenticated attackers with knowledge of the file URL to bypass server-side authentication entirely and retrieve the data directly from the CDN.
We live in an era where "make it fast" often supersedes "make it safe." In the .NET ecosystem, ImageSharp is the darling of performance enthusiasts. It resizes, crops, and optimizes images on the fly, ensuring your heavy assets don't bog down the client's browser. To do this effectively, it relies heavily on HTTP caching. After all, why resize the same image twice when you can tell the browser (or a CDN) to hold onto it for a year?
Enter Umbraco Forms. This isn't your standard "Contact Us" plugin; enterprises use it to collect CVs, medical history forms, identity documents, and financial records. These files are stored in a protected directory (/media/forms/upload/), guarded by authentication checks that ensure only authorized backoffice users can view them.
But here is the cosmic joke: When an administrator logs into the secure backoffice to view these sensitive uploads, the CMS often requests a thumbnail version of the file via ImageSharp. ImageSharp does exactly what it was designed to do—it processes the image and stamps it with Cache-Control: public, max-age=31536000.
If the site sits behind a CDN like Cloudflare or Azure Front Door (and let's be honest, who isn't these days?), that CDN sees the header and dutifully caches the file. Suddenly, your "protected" passport scan is sitting on an edge server in Frankfurt, accessible to anyone who requests that specific URL, completely bypassing your server's authentication logic. It’s like locking your front door but handing a copy of the key to the valet parker who leaves it on the dashboard.
The root cause here is a classic conflict of interest between components. Umbraco Forms believes it is saving files to a secure location. ImageSharp believes it is serving public assets that should be cached aggressively. The breakdown happens because ImageSharp's default middleware doesn't distinguish between "public media" (like your logo) and "protected media" (like a user's driver's license upload).
Technically, the vulnerability maps to CWE-524: Use of Cache Containing Sensitive Information. When the application serves the processed image, the HTTP response headers look something like this:
HTTP/1.1 200 OK
Content-Type: image/jpeg
Cache-Control: public, max-age=31536000
Last-Modified: Wed, 21 Oct 2025 07:28:00 GMT
...The public directive is the smoking gun. It explicitly tells intermediate caches (CDNs, proxies) that "this response may be stored by any cache, even if the response would normally be non-cacheable or cacheable only within a private cache."
The CDN, being a good compliant robot, ignores the fact that the original request contained an authentication cookie (from the admin). It keys the cache based on the URL. Subsequent requests for that same URL—even from an attacker in a private browsing window—will hit the CDN cache (HIT) and receive the file. The origin server (Umbraco) is never even consulted.
Let's look at why this happens and how the fix works. In a standard ASP.NET Core pipeline, middleware runs in a specific order. ImageSharp intercepts requests matching its parameters before they hit the static file authorization logic, or rather, it handles the response headers independently.
The fix involves intercepting the response specifically for the sensitive path and stripping those dangerous headers. If you can't upgrade immediately, you have to write your own "Header Police" middleware.
Here is what the vulnerable flow looks like:
/media/forms/upload/...Cache-Control: public.Here is the mitigation logic (The Band-Aid):
app.Use(async (context, next) =>
{
var path = context.Request.Path.Value;
// Detect if we are accessing the sensitive vault
if (!string.IsNullOrEmpty(path) &&
path.StartsWith("/media/forms/upload/", StringComparison.OrdinalIgnoreCase))
{
context.Response.OnStarting(() =>
{
// NUKE THE CACHE HEADERS
// Force the browser and CDN to never store this
context.Response.Headers["Cache-Control"] = "private, no-store, no-cache, must-revalidate";
context.Response.Headers["Pragma"] = "no-cache";
context.Response.Headers["Expires"] = "0";
return Task.CompletedTask;
});
}
await next();
});> [!NOTE] > The official patch in Umbraco Forms 13.9.0+ likely implements similar logic internally, ensuring that any file served from the Forms directory context explicitly overrides the ImageSharp defaults.
Exploiting this requires a bit of luck or insider knowledge, hence the "Low" CVSS score (3.1). The attacker needs the URL. In Umbraco, these URLs typically look like:
/media/forms/upload/{FormGuid}/{EntryGuid}/{filename.jpg}?width=200
The Attack Chain:
server: cloudflare or similar headers).curl -I -H "Host: target.com" "https://target.com/media/forms/upload/d3b07384.../photo.jpg?width=500"If they see CF-Cache-Status: HIT (or X-Cache: HIT), they know the file is sitting on the edge. They can then download it without providing any cookies or authentication tokens.
Re-exploitation Potential: Even with the patch, if the middleware only checks for /media/forms/upload/, a clever attacker might try URL obfuscation like /media/forms//upload/ or /media/%66orms/upload/ to bypass the string check, depending on how normalized context.Request.Path is before the check runs. (Note: ASP.NET Core Path is usually normalized, but it's a vector worth testing).
The impact here is purely Confidentiality, but don't let the low CVSS score fool you. The business impact can be catastrophic. We are talking about data that users trusted the organization to keep safe.
Imagine a scenario where a hospital uses Umbraco Forms for patient intake. Users upload photos of their insurance cards or visible symptoms. Because of this flaw, those images could be sitting in public CDN nodes. If an attacker gains access to a list of URLs (perhaps via a compromised log file or a careless backup), they can scrape every single image without ever touching the backend server or triggering a single IDS alert.
Furthermore, removing data from a CDN is notoriously difficult. Even if you patch the server today, the file might live in the CDN cache until its TTL expires (which was set to 1 year by ImageSharp). You have to manually purge the CDN cache to stop the bleeding.
There is no fancy workaround here. You need to tell the server to stop shouting "CACHE THIS" to the world.
Update Umbraco Forms:
Emergency Middleware: If you can't deploy a binary update, copy-paste the middleware provided in the "Code" section into your Startup.cs or Program.cs. Ensure it is placed after app.UseStaticFiles() but early enough in the pipeline to catch the response headers.
The Critical Step: Purge the CDN: Patching the code stops new items from being cached improperly. It does not remove the items already sitting on the edge. You MUST issue a "Purge All" or selective purge for the /media/forms/upload/* path on your CDN immediately after patching.
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Umbraco Forms Umbraco | < 13.9.0 | 13.9.0 |
Umbraco Forms Umbraco | 14.0.0 - 16.3.x | 16.4.0 |
Umbraco Forms Umbraco | 17.0.0-rc1 - 17.0.x | 17.1.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-524 |
| CVSS Score | 3.1 (Low) |
| Vector | CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N |
| Attack Complexity | High (Requires GUID knowledge) |
| Exploit Status | Theoretical / Context Dependent |
| Impact | Confidentiality Loss (Sensitive Data Exposure) |
The application saves sensitive information in a cache, but the cache is accessible to unauthorized actors or the information is stored in a way that allows retrieval.