GHSA-7JXJ-RPX7-PH2C

Cache Me If You Can: Umbraco Forms & The ImageSharp Betrayal

Alon Barad
Alon Barad
Software Engineer

Jan 23, 2026·5 min read·8 visits

Executive Summary (TL;DR)

Umbraco Forms protects your sensitive uploads, but the ImageSharp library—optimized for performance—tells CDNs to cache them publicly. If an admin views a protected file, it gets stored on the CDN edge, allowing anyone with the direct link to bypass authentication and download the file.

A Web Cache Deception vulnerability exists in Umbraco Forms where sensitive uploaded files are inadvertently cached by CDNs due to aggressive caching headers set by the ImageSharp library, potentially allowing unauthenticated access to private data.

The Hook: Performance vs. Privacy

You build a fortress. Thick walls, guards at the gate (Authentication), and a vault for the jewels (Sensitive Form Uploads). Then, because you want the guards to see the jewels clearly, you hire an optician (ImageSharp) who hands out photos of the jewels to anyone passing by on the street, provided they ask nicely.

This is essentially what happened with Umbraco Forms. It is a classic tale of two systems working perfectly in isolation but disastrously together. Umbraco Forms handles sensitive data—think job applications, medical forms, or identity verifications. ImageSharp handles image processing to make things snappy, generating thumbnails and resizing images on the fly.

The conflict arises because these two systems have opposing goals. The security system wants to verify every request. The image processing system wants to serve static assets as fast as possible. When you introduce a Content Delivery Network (CDN) into this mix, the "private" data inadvertently becomes "publicly cached" data. It is a race condition of logic: performance vs. privacy, and in this specific configuration, performance won.

The Flaw: The Indifferent Cache

The vulnerability isn't a buffer overflow or a SQL injection. It is a logic flaw in how HTTP headers are propagated through the stack. Umbraco Forms saves uploaded files in the /media/forms/upload/ directory. By design, these paths are protected; if you try to access them directly without a valid session cookie, the Umbraco core kicks you out.

However, when an administrator views these files in the back-office (e.g., viewing a list of recent submissions), they often trigger ImageSharp to generate a thumbnail. ImageSharp is designed for high-performance web delivery. It assumes that if you are serving an image, you want it cached forever to save server bandwidth. Consequently, it stamps the HTTP response with headers like Cache-Control: public, max-age=31536000 (one year).

Here is the breakdown:

  1. The Admin (authorized) requests the thumbnail.
  2. The Server generates the image and attaches the public cache header.
  3. The CDN sits in the middle. It sees public and caches the response at the edge.
  4. The Attacker requests the exact same URL.
  5. The CDN serves the file immediately from its cache, completely bypassing the Umbraco authentication layer.

The CDN doesn't know about your backend login logic. It only knows it has a valid file that it was told to store for 365 days.

The Code: Stomping the Headers

Since we cannot easily change ImageSharp's internal philosophy without breaking performance for non-sensitive assets, the fix involves intercepting the HTTP response before it leaves the server. The patch (or manual workaround) acts as a middleware bouncer for the HTTP headers.

Below is the logic required to fix the vulnerability in Startup.cs. It specifically targets the sensitive forms directory and overrides the permissive headers:

app.Use(async (context, next) =>
{
    var path = context.Request.Path.Value;
 
    // Detect if we are touching the sensitive area
    if (!string.IsNullOrEmpty(path) && 
        path.StartsWith("/media/forms/upload/", StringComparison.OrdinalIgnoreCase))
    {
        context.Response.OnStarting(() =>
        {
            // Nuke the permissive headers from orbit
            // Force the CDN and Browser to re-validate every time
            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();
});

The key mechanism here is context.Response.OnStarting. We hook into the response lifecycle just before headers are flushed to the client. We overwrite whatever ImageSharp tried to set with private, no-store. This tells the CDN: "Do not touch this. Do not look at it. Do not save it."

The Exploit: Needle in a Haystack

Why is this rated CVSS 3.1 (Low)? Because exploiting it is akin to finding a specific needle in a stack of needles. The attack requires the adversary to know the exact URL of the uploaded file. In Umbraco Forms, that structure typically looks like this:

https://target.com/media/forms/upload/{FormGuid}/{EntryGuid}/{FileName}

To successfully exploit this, an attacker needs three pieces of information:

  1. The Form GUID: Often visible in the HTML source if the form is public on the site.
  2. The Entry GUID: This is the hard part. It is a random UUID generated per submission.
  3. The Filename: The original name of the uploaded file.

However, "Low" severity does not mean "Impossible." In a targeted attack scenario, if an attacker can trigger an error page that leaks context, finds a backup of the database, or exploits a separate IDOR vulnerability to list directory contents, they get the keys to the kingdom. Once they have the URL, they simply request it. If the admin has looked at that submission recently (priming the cache), the CDN hands over the sensitive document without asking for a password.

The Impact: Privacy Implosion

While the likelihood of exploitation is low due to the complexity of guessing GUIDs, the impact of a successful exploit is significant. We are talking about the potential exposure of PII (Personally Identifiable Information) or sensitive corporate data.

Imagine a scenario where a user uploads a passport scan for identity verification. The administrator views it to approve the account. An attacker, perhaps an insider with access to logs or a previous employee who knows the GUID patterns, can access that passport scan from anywhere in the world. This is a direct violation of GDPR and other privacy regulations, all because a library was trying to be helpful by caching an image.

Technical Appendix

CVSS Score
3.1/ 10
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N
EPSS Probability
0.04%
Top 100% most exploited

Affected Systems

Umbraco CMS (using Umbraco Forms)ImageSharp MiddlewareContent Delivery Networks (CDN)

Affected Versions Detail

Product
Affected Versions
Fixed Version
Umbraco Forms
Umbraco
< 13.9.013.9.0
Umbraco Forms
Umbraco
< 16.4.016.4.0
Umbraco Forms
Umbraco
< 17.1.017.1.0
AttributeDetail
Attack VectorNetwork (CDN Cache Deception)
CVSS Score3.1 (Low)
ComplexityHigh (Requires GUID knowledge)
PrivilegesNone (Unauthenticated)
ImpactConfidentiality (Information Disclosure)
Vulnerability TypeWeb Cache Deception / Insecure Storage
CWE-524
Information Exposure Through Caching

The application allows sensitive information to be cached by an intermediary (CDN), allowing unauthorized access.

Vulnerability Timeline

Vulnerability Published
2026-01-22

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.