# Insufficient Entropy Vulnerability (2878)

## Description

February 2026 - [CVE-2026-2878](https://www.cve.org/CVERecord?id=CVE-2026-2878)

* Progress® Telerik® UI for AJAX 2026 Q1 (2026.1.211) or earlier.

### What Are the Impacts

In Progress® Telerik® UI for AJAX, versions prior to 2026.1.225, an insufficient entropy vulnerability exists in RadAsyncUpload, where a predictable temporary identifier, based on timestamp and filename, can enable collisions and file content tampering.

## Issue

* CWE-331: Insufficient Entropy
* CAPEC-149: Explore for Predictable Temporary File Names => CAPEC-26: Leveraging Race Conditions

## Solution

We have addressed the issue and the Progress Telerik team strongly recommends performing an upgrade to the latest version listed in the table below.

| Current Version                               | Update to                     |
| --------------------------------------------- | ----------------------------- |
| `>= v2011.2.712` && `<= 2026.1.211` (2026 Q1) | `>= 2026.1.225` (2026 Q1 SP1) |

Follow the [update instructions](https://www.telerik.com/products/aspnet-ajax/documentation/upgrade-compatibility/upgrading-instructions/upgrading-a-trial-to-a-developer-license-or-to-a-newer-version) for precise instructions. All customers who have a license for UI for AJAX can access the downloads here [Product Downloads | Your Account](https://www.telerik.com/account/downloads/product-download).

## Mitigation

If you are unable to upgrade to a product version which contains the fix (`2026.1.225` \[2026 Q1 SP1] or later), there are two ways mitigate the issue. Choose the option that best appropriate for your scenario.

> important The per-session temporary-folder isolation described in this article addresses the predictable temporary identifier in **CVE-2026-2878**. It is not a substitute for the separate mitigations or fixes for the July 2026 CVEs affecting upload metadata, persistence storage, or persistence type resolution. See the [July 2026 security bulletin](https://www.telerik.com/products/aspnet-ajax/documentation/knowledge-base/kb-security-critical-rce-chain-bulletin-july-2026) for those advisories.

* [Option 1 \[server-side\]. Per-Session Temporary Folder Isolation](https://www.telerik.com/products/aspnet-ajax/documentation/knowledge-base/kb-security-insufficient-entropy-cve-2026-2878#option-1-per---session-temporary-folder-isolation)
* [Option 2 \[disablement\]. Disable the AsyncUpload Handler](https://www.telerik.com/products/aspnet-ajax/documentation/knowledge-base/kb-security-insufficient-entropy-cve-2026-2878#option-2-disable-the-asyncUpload-handler)

### Option 1. Per-Session Temporary Folder Isolation

This approach assigns each user session a unique, unpredictable temporary upload folder, thus an attacker cannot exploit the collision because they cannot determine the victim's temporary folder path.

> **Important:** Do **not** set the `TargetFolder` property in the markup when using this approach. Use `file.SaveAs()` in the code-behind instead. Setting both `TargetFolder` and calling `SaveAs()` will result in a `FileNotFoundException` because the control moves the file to `TargetFolder` before your code executes.

1. In the code-behind of the page(s) that use `RadAsyncUpload`, set the `TemporaryFolder` dynamically in `Page_Init`:

   ```C#
   using System;
   using System.IO;
   using Telerik.Web.UI;

   ...

   protected void Page_Init(object sender, EventArgs e)
   {
       if (Session["RadUploadTempFolder"] == null)
       {
           Session["RadUploadTempFolder"] = "~/App_Data/RadUploadTemp/"
               + Guid.NewGuid().ToString("N").Substring(0, 12) + "/";
       }

       string sessionFolder = (string)Session["RadUploadTempFolder"];

       // Ensure the session-specific folder exists before assigning it,
       // otherwise the control's permission check will throw.
       string physicalPath = Server.MapPath(sessionFolder);
       if (!Directory.Exists(physicalPath))
           Directory.CreateDirectory(physicalPath);

       RadAsyncUpload1.TemporaryFolder = sessionFolder;
   }
   ```

   ```VB
   Imports System
   Imports System.IO
   Imports Telerik.Web.UI

   ...

   Protected Sub Page_Init(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Init
       If Session("RadUploadTempFolder") Is Nothing Then
           Session("RadUploadTempFolder") = "~/App_Data/RadUploadTemp/" _
               & Guid.NewGuid().ToString("N").Substring(0, 12) & "/"
       End If

       Dim sessionFolder As String = CStr(Session("RadUploadTempFolder"))

       ' Ensure the session-specific folder exists before assigning it,
       ' otherwise the control's permission check will throw.
       Dim physicalPath As String = Server.MapPath(sessionFolder)
       If Not Directory.Exists(physicalPath) Then
           Directory.CreateDirectory(physicalPath)
       End If

       RadAsyncUpload1.TemporaryFolder = sessionFolder
   End Sub
   ```

2. Ensure that the `TargetFolder` property is not set in the markup and save files manually:

   ```xml
   <telerik:RadAsyncUpload runat="server" ID="RadAsyncUpload1" />

   <asp:Button ID="btnSubmit" Text="Submit" runat="server" OnClick="btnSubmit_Click" />
   ```

   ```C#
   protected void btnSubmit_Click(object sender, EventArgs e)
   {
       foreach (UploadedFile file in RadAsyncUpload1.UploadedFiles)
       {
           string targetPath = Server.MapPath("~/App_Data/RadUploadTarget/");
           if (!System.IO.Directory.Exists(targetPath))
               System.IO.Directory.CreateDirectory(targetPath);

           file.SaveAs(System.IO.Path.Combine(targetPath, file.GetName()), true);
       }
   }
   ```

   ```VB
   Protected Sub btnSubmit_Click(ByVal sender As Object, ByVal e As EventArgs)
       For Each file As UploadedFile In RadAsyncUpload1.UploadedFiles
           Dim targetPath As String = Server.MapPath("~/App_Data/RadUploadTarget/")
           If Not Directory.Exists(targetPath) Then
               Directory.CreateDirectory(targetPath)
           End If

           file.SaveAs(Path.Combine(targetPath, file.GetName()), True)
       Next
   End Sub
   ```

#### How It Works

The original vulnerability relies on the attacker being able to predict the full path to the victim's temporary file: `<known temp folder>/<predictable UploadID>`. With per-session folders, the path becomes `<known temp folder>/<unpredictable session subfolder>`. The 12-character hex subfolder name (48 bits of entropy, \~281 trillion combinations) is generated server-side using `Guid.NewGuid()` and is never exposed to the client in any HTTP response, header, or cookie.

#### Considerations

* **Cleanup:** Telerik's built-in cache-based cleanup automatically deletes individual temporary **files** when they expire (default: 4 hours, configurable via `TemporaryFileExpiration`). However, it does **not** remove the session-specific **subdirectories**. Over time, empty folders will accumulate. Implement a periodic cleanup using a background timer in `Global.asax` or a scheduled task to remove stale subdirectories:

  ```C#
  using System;
  using System.IO;

  ...

  // In Global.asax
  private static System.Threading.Timer _cleanupTimer;
  private static string _tempRoot;

  void Application_Start(object sender, EventArgs e)
  {
      _tempRoot = Server.MapPath("~/App_Data/RadUploadTemp");

      // Run cleanup once at startup, then every 4 hours
      CleanupStaleTempFolders(null);

      _cleanupTimer = new System.Threading.Timer(CleanupStaleTempFolders, null, 
          TimeSpan.FromHours(4), TimeSpan.FromHours(4));
  }

  private static void CleanupStaleTempFolders(object state)
  {
      if (!Directory.Exists(_tempRoot)) return;

      foreach (string dir in Directory.GetDirectories(_tempRoot))
      {
          if (Directory.GetCreationTimeUtc(dir) < DateTime.UtcNow.AddHours(-24))
          {
              try { Directory.Delete(dir, true); } catch { }
          }
      }
  }

  void Application_End(object sender, EventArgs e)
  {
      if (_cleanupTimer != null)
      {
          _cleanupTimer.Dispose();
          _cleanupTimer = null;
      }
  }
  ```

* **Folder creation:** The session-specific folder must exist **before** `RadAsyncUpload` renders, otherwise the control's built-in permission check (`TestTemporaryFolderPermissions`) will throw a `DirectoryNotFoundException`. This is why `Directory.CreateDirectory()` is called in `Page_Init` before setting `TemporaryFolder`.

* **TargetFolder conflict:** Do not combine this approach with the `TargetFolder` property. When `TargetFolder` is set, the control automatically moves uploaded files out of the temporary folder during postback processing — before any `FileUploaded` event or button click handler executes. This causes `file.SaveAs()` to fail with a `FileNotFoundException`.

* **ASP.NET process permissions:** Ensure the ASP.NET worker process has write permissions to create subdirectories under the configured parent folder (`App_Data/RadUploadTemp` by default).

* **MAX_PATH:** The per-session subfolder adds 13 characters (12-character hex name + path separator) to the temporary file path, therefore deeply nested base paths combined with long filenames may still approach the Windows `MAX_PATH` limit of 260 characters. Verify that your configured `TemporaryFolder` base path leaves sufficient headroom.

### Option 2. Disable the AsyncUpload Handler

If your application does not use `RadAsyncUpload` (or `RadCloudUpload`), you can eliminate the vulnerability entirely by [disabling the upload handler](https://www.telerik.com/products/aspnet-ajax/documentation/controls/asyncupload/security#disableasyncuploadhandler). Add the following key to the `<appSettings>` section of your `web.config`:

```xml
<appSettings>
  <add key="Telerik.Web.DisableAsyncUploadHandler" value="true" />
</appSettings>
```

When set to `true`, the handler returns HTTP 404 for all upload requests, completely removing the attack surface.

#### Considerations

* This disables **all** `RadAsyncUpload` and `RadCloudUpload` functionality across the entire application. Do not use this option if any page relies on asynchronous file uploads.
* Other Telerik handler functionality (script resources, dialogs, etc.) served by `Telerik.Web.UI.WebResource.axd` is **not** affected — only upload requests (`?type=rau`) are blocked.

## Notes

* If you have any questions or concerns related to this issue, open a new Technical Support case in [Your Account | Support Center](https://www.telerik.com/account/support-center/contact-us/). Technical Support is available to customers with an active support plan.
* We would like to thank the team at the Monetary Authority of Singapore for their responsible disclosure and cooperation.

## External References

[CVE-2026-2878](https://www.cve.org/CVERecord?id=CVE-2026-2878) (MEDIUM)

**CVSS:** 5.3

In Progress® Telerik® UI for AJAX, versions prior to 2026.1.225, an insufficient entropy vulnerability exists in RadAsyncUpload, where a predictable temporary identifier, based on timestamp and filename, can enable collisions and file content tampering.

Discoverer Credit: Monetary Authority of Singapore
