CVE-2025-24813 is a path equivalence flaw in Apache Tomcat’s partial PUT handling that can lead to file disclosure, file tampering or remote code execution when the DefaultServlet is write-enabled. Fix it by upgrading to Tomcat 11.0.3, 10.1.35, 9.0.99 or later; until then keep readonly=true and set allowPartialPut=false in conf/web.xml.
What the scanner is actually detecting
Nessus reports this CVE through two kinds of plugin, and it matters which one fired.
| Plugin | Finding title | How it tests |
|---|---|---|
| 233297 | Apache Tomcat Path Equivalence RCE (CVE-2025-24813) | Remote active check (family CGI abuses, Critical, CVSS v3 9.8). Tenable lists it as “Exploited by Nessus”. |
| 232528 | Apache Tomcat 9.0.0.M1 < 9.0.99 | Version check (family Web Servers) based on the self-reported version |
| 232529 | Apache Tomcat 10.1.0.M1 < 10.1.35 | Version check (family Web Servers) |
| 232530 | Apache Tomcat 11.0.0.M1 < 11.0.3 | Version check (family Web Servers) |
The version plugins fire on every unpatched Tomcat, whether or not writes are enabled. Plugin 233297 is different: Tenable does not publish the exact request it sends, but as an active test it judges the host by how it responds rather than by the version string, so treat a 233297 hit as a likely live exposure and check the write settings below first. Tenable also maps many local package checks for Linux distributions to the same CVE.
How serious is it?
Apache rates the issue Important. Before the fix, a partial PUT (a PUT with a Content-Range header) wrote a temporary file into the application’s work directory, named after the request path with / replaced by .. Per the Apache advisory, file disclosure or content injection required all of the following:
- writes enabled for the default servlet (disabled by default);
- partial PUT support (enabled by default);
- an upload URL for sensitive files that sits below a public upload URL, with the attacker knowing the file names and those files also being uploaded by partial PUT.
Remote code execution required a write-enabled default servlet, partial PUT, Tomcat’s file-based session persistence with the default storage location, and a library on the classpath usable for a deserialization attack. The link is the directory: Tomcat’s FileStore keeps serialized sessions in the application’s work directory unless you configure another one.
So a stock installation, where the DefaultServlet is read-only, is not exposed to the published attack paths. The risk is real on servers where someone set readonly to false for uploads or WebDAV. Tenable notes public exploits exist, and CISA added the CVE to its Known Exploited Vulnerabilities catalog on 1 April 2025. The KEV entry also notes it can be chained with CVE-2026-34486, an EncryptInterceptor bypass that affects only Tomcat 9.0.116, 10.1.53 and 11.0.20, which is one more reason to install the current release rather than the minimum fixed one.
How to confirm it on the host
Set CATALINA_HOME and CATALINA_BASE first (for example /opt/tomcat for tarball installs, /var/lib/tomcat10 for Debian and Ubuntu packages, /usr/share/tomcat on RHEL). Then check the version, the write settings and session persistence:
# Version
"$CATALINA_HOME/bin/version.sh"
java -cp "$CATALINA_HOME/lib/catalina.jar" org.apache.catalina.util.ServerInfo
dpkg -l 'tomcat*' 2>/dev/null; rpm -qa 'tomcat*' 2>/dev/null
# Write-enabled DefaultServlet or WebdavServlet, and partial PUT setting
grep -n -A1 -E 'readonly|allowPartialPut' "$CATALINA_BASE/conf/web.xml"
"$CATALINA_BASE"/webapps/*/WEB-INF/web.xml
"$CATALINA_BASE"/webapps/*/WEB-INF/tomcat-web.xml 2>/dev/null
# File-based session persistence (RCE precondition)
grep -rn -E 'PersistentManager|FileStore' "$CATALINA_BASE/conf"
"$CATALINA_BASE"/webapps/*/META-INF/context.xml 2>/dev/null
# Embedded Tomcat (Spring Boot fat JARs keep it in BOOT-INF/lib)
find / -xdev ( -name 'catalina.jar' -o -name 'tomcat-embed-core-*.jar' ) 2>/dev/null
unzip -l app.jar | grep tomcat-embed-core
A readonly parameter followed by <param-value>false</param-value> means writes are enabled for that servlet. No readonly line means the default, true. WebdavServlet extends the DefaultServlet, so its declarations count too.
# Windows (PowerShell); use the java.exe Tomcat runs with if java is not on PATH
$tc = 'C:Program FilesApache Software FoundationTomcat 9.0'
Get-Service Tomcat*
java -cp "$tclibcatalina.jar" org.apache.catalina.util.ServerInfo
Select-String -Path "$tcconfweb.xml", "$tcwebapps*WEB-INFweb.xml" -Pattern 'readonly', 'allowPartialPut' -Context 0,1
Select-String -Path "$tcconf*.xml" -Pattern 'PersistentManager', 'FileStore'
From the network, a non-destructive check is the Allow header. Since Tomcat 9.0.3 the Default and WebDAV servlets only list PUT when it is permitted:
curl -si -X OPTIONS http://tomcat.example.com:8080/put-check.txt | grep -i '^Allow'
curl -si -X OPTIONS http://tomcat.example.com:8080/appname/put-check.txt | grep -i '^Allow'
Repeat per application context, because each application can override the global setting. If the application maps its own servlet to /, the answer comes from that servlet instead.
How to fix it
Back up conf/ and the install directory before changing anything.
Upgrade a tarball installation (Linux)
Install the current release of your branch, not just the minimum fixed version. At the time of writing, Apache lists 9.0.122, 10.1.60 and 11.0.26 as the latest releases.
VER=9.0.122 # use tomcat-10 or tomcat-11 in the URLs for other branches
cd /tmp
curl -fO https://dlcdn.apache.org/tomcat/tomcat-9/v$VER/bin/apache-tomcat-$VER.tar.gz
curl -fO https://dlcdn.apache.org/tomcat/tomcat-9/v$VER/bin/apache-tomcat-$VER.tar.gz.sha512
sha512sum -c apache-tomcat-$VER.tar.gz.sha512
sudo tar -xzf apache-tomcat-$VER.tar.gz -C /opt
If CATALINA_BASE is separate from CATALINA_HOME, point the service at the new directory, matching the old directory’s owner and permissions:
sudo systemctl stop tomcat
sudo ln -sfn /opt/apache-tomcat-$VER /opt/tomcat
sudo systemctl start tomcat
If conf/ and webapps/ live inside the old install directory, carry them over, compare server.xml, web.xml and context.xml with the new defaults instead of overwriting blindly, and copy only JARs you added to lib/. Older releases are on archive.apache.org/dist/tomcat/; the download CDN keeps only current ones.
Distribution packages
# Debian / Ubuntu
sudo apt update
sudo apt install --only-upgrade tomcat10 # or tomcat9
sudo systemctl restart tomcat10
# RHEL family
sudo dnf upgrade 'tomcat*'
sudo systemctl restart tomcat
Distributions often backport the fix without changing the upstream version number, so check your vendor’s advisory for the fixed package release.
Windows
(Get-FileHash .apache-tomcat-9.0.122-windows-x64.zip -Algorithm SHA512).Hash -eq (Get-Content .apache-tomcat-9.0.122-windows-x64.zip.sha512).Split(' ')[0]
Stop-Service Tomcat9
Copy-Item 'C:Program FilesApache Software FoundationTomcat 9.0' 'D:BackupTomcat 9.0' -Recurse
Install the new release with the .exe installer or the zip, carry over conf, webapps and any added lib JARs, then run Start-Service Tomcat9.
Embedded Tomcat, vendor products and end-of-life branches
For Spring Boot and other embedded use, raise tomcat-embed-core in the build to a fixed release and redeploy. For appliances that bundle Tomcat, follow the vendor’s advisory. Tomcat 8.5 reached end of life on 31 March 2024, and 8.5.0 through 8.5.100 are known affected with no fix; move to 9.0.x.
Interim hardening until you can upgrade
Apache’s only listed mitigation is upgrading, but both attack paths need a write-enabled DefaultServlet and partial PUT. In $CATALINA_BASE/conf/web.xml, inside the <servlet> element whose name is default, add:
<init-param>
<param-name>readonly</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>allowPartialPut</param-name>
<param-value>false</param-value>
</init-param>
An application that redefines the default servlet in WEB-INF/web.xml or WEB-INF/tomcat-web.xml replaces the global definition, so set the same parameters there. allowPartialPut was added in Tomcat 9.0.22; on older releases readonly=true is the control that matters. Restart Tomcat afterward. If an application uses PersistentManager with FileStore, reconsider whether it needs file-based persistence.
How to verify the fix and rescan
- Run
version.shorServerInfoagain and confirm the new version, or confirm the package is at the fixed release in your distribution’s advisory. - Repeat the
OPTIONScheck on each context; PUT should be missing fromAllowunless an application genuinely needs it. - Check
catalina.out,journalctl -u tomcat10or the Windows service logs for SEVERE errors, and test the applications. - Rescan with Nessus including 233297, 232528, 232529 and 232530. Plugin 233297 requires the KB item
installed_sw/Apache Tomcat, so keep Tomcat detection enabled in the policy.
What can break and how to roll back
- Branch changes. Tomcat 10.1 and 11.0 use the
jakarta.*namespace, sojavax.*applications need migration. Tomcat 9.0 needs Java 8, 10.1 needs Java 11 and 11.0 needs Java 17. Stay on 9.0.x if applications are not ready. - Large jumps within a branch. Many patch releases can bring stricter HTTP parsing and changed defaults. Read the changelog and test in staging.
- Uploads stop working. With
readonly=true, PUT and DELETE to the default servlet return 405. Re-enable writes only on the specific application, behind authentication, after upgrading. - Resumable uploads fail. With
allowPartialPut=false, a PUT carryingContent-Rangeis rejected with 400.
To roll back, move the symlink back to the old directory (or restore the backup folder on Windows), restore the web.xml backup and restart. A rollback restores a vulnerable version, so keep the interim hardening in place and reschedule the upgrade.
Common false positive reasons
- Read-only defaults. A version plugin on a server with no write-enabled servlet is not exploitable through the published paths, but the version is still affected. Record it as mitigated, not false.
- Distribution backports. Debian 12 fixed
tomcat10in10.1.34-0+deb12u2(DSA-5893-1), whose upstream version is still 10.1.34. See the Debian security tracker. - Wrong instance. Several instances on one host each have their own
CATALINA_BASEand port. Match the flagged port to the instance you upgraded. - Behind a proxy. The banner or response may come from a backend Tomcat, not the proxy host in the report.
- Stale results. Tomcat was upgraded on disk but not restarted, or the scan predates the change.
FAQ
Is a default Tomcat installation exploitable?
Not through the published attack paths, because the DefaultServlet is read-only by default. The version is still affected, so upgrade anyway.
Does allowPartialPut=false fix CVE-2025-24813?
It removes a precondition for both scenarios, but it is not a fix. Apache only lists upgrading, and the version plugins will keep reporting the host.
Is there a patch for Tomcat 8.5?
No. 8.5 is end of life and 8.5.0 through 8.5.100 are known affected. Tomcat 9.0 keeps the javax.* namespace, so it is usually the easiest move.
Which version should I install?
The latest release of your branch. Later Tomcat advisories, including CVE-2026-34486, affect builds after 9.0.99, 10.1.35 and 11.0.3.
Tracking this finding across many hosts
When the same Tomcat build runs on many servers, the version plugins tend to fire everywhere at once. SITEY, a self-hosted vulnerability management platform, imports findings from 16 scanners (Nessus results by uploading a .nessus export) and merges duplicates within each scanner, so plugin 233297 and the version plugins can be followed host by host. Nessus findings can be retested individually after each upgrade, and its AI triage can suggest likely false positives, such as distribution backports, with evidence, while a human makes the final decision.
Sources
- Apache Tomcat 9.x vulnerabilities (CVE-2025-24813, fixed in 9.0.99)
- Apache Tomcat 9: Default Servlet reference (readonly, allowPartialPut)
- Tenable: Apache Tomcat Path Equivalence RCE (CVE-2025-24813), plugin 233297
- Tenable: plugins for CVE-2025-24813
- CISA Known Exploited Vulnerabilities catalog: CVE-2025-24813