Safeguard
Supply Chain Security•

Apache Tomcat Release History: 3.x to 11, Jakarta and Support Dates

Tomcat began as Sun's servlet reference code, given to Apache in 1999. Today 11.0, 10.1 and 9.0 are supported; 9.0 support ends 31 March 2027.

Safeguard Security Team
39 min read

Apache Tomcat began as Sun Microsystems' reference implementation of the Servlet and JSP specifications, which Sun donated to the Apache Software Foundation in 1999; the first Apache release was Tomcat 3.0. As of October 2026 three branches are supported: 11.0 (Jakarta EE 11, Java 17 and later), 10.1 (Jakarta EE 10, Java 11 and later) and 9.0 (Java EE 8, Java 8 and later), whose support ends on 31 March 2027.

Every other branch, from 3.x through 8.5 and 10.0, is end of life. Security fixes ship only as new releases on a supported branch, never as binary patches, and each branch has its own vulnerabilities page listing affected and fixed versions. Every date and version below was checked against tomcat.apache.org, the Tomcat source repository, or the Apache Software Foundation's own pages.

Key takeaways

  • Three live branches. 11.0.27, 10.1.61 and 9.0.123, all released on 12 October 2026, are the current versions. Everything older is unsupported.
  • 9.0 has a date. On 11 February 2026 the Tomcat team announced that 9.0.x support ends on 31 March 2027. A 9.1.x branch for Java EE users follows, with releases until 31 December 2030, but without the APR/native connectors.
  • Tomcat 10 changed the package name. Tomcat 9 and earlier implement Java EE (javax.*). Tomcat 10 and later implement Jakarta EE (jakarta.*). Applications must be recompiled or converted; an Apache migration tool does the conversion.
  • Specification and Java move together. Servlet 4.0 on Java 8 is 9.0; Servlet 6.0 on Java 11 is 10.1; Servlet 6.1 on Java 17 is 11.0.
  • Defaults got safer over time. The AJP connector is commented out in the default configuration, listens only on loopback when enabled and refuses to start without a secret (since February 2020). The Server header has not been sent by default since 8.5. The Manager application has no users by default.
  • Most Tomcat in production is embedded. Applications built on frameworks such as Spring Boot ship tomcat-embed-core inside the application, so the Tomcat version comes from the framework's dependency management, not from a server install.
  • Security fixes ship as releases. Reports go privately to security@tomcat.apache.org, the ASF security team (a CVE Numbering Authority) assigns the CVE, and the fix is announced with the release that contains it.

How did Tomcat begin?

A reference implementation at Sun

Tomcat started at Sun Microsystems as the reference implementation of the Java Servlet and JavaServer Pages specifications. According to the project's heritage page, Sun donated the code base to the Apache Software Foundation in 1999, and the first Apache Tomcat release was version 3.0. Tomcat lived under the ASF's Jakarta umbrella of Java projects until 2005, when it became its own top level project. That "Jakarta" is unrelated to the later Jakarta EE name.

Why the version numbers started at 3

The code arrived with history, so numbering started at 3.0. All 3.x releases implement Servlet 2.2 and JSP 1.1. 3.1 added servlet reloading, WAR file support and connectors for the IIS and Netscape web servers; 3.2 and 3.3 refactored the internals into a modular design. 3.3.2 was the final release, and the branch reached end of life on 9 March 2004.

Catalina, Coyote and Jasper: the names that stuck

Tomcat 4.0 replaced the 3.x internals with a new servlet container called Catalina, built on a new architecture and implementing Servlet 2.3 and JSP 1.2. Tomcat 4.1 refactored 4.0 and brought in the Coyote connector (HTTP/1.1, AJP 1.3 and JNI support), a rewritten Jasper JSP compiler, JMX based administration and custom Ant tasks for the manager application.

Those three names still describe Tomcat today: Catalina is the container, Coyote is the connector layer that speaks HTTP and AJP, and Jasper compiles JSPs. Our Tomcat and Coyote vulnerabilities explainer covers how bugs in each layer show up; this post stays with the release history and the processes around it.

How do Tomcat versions map to the Servlet and Jakarta EE specifications?

The rule: the specification picks the major version

Tomcat is not a full Java EE or Jakarta EE application server. It implements a subset: Servlet, Pages (formerly JSP), Expression Language, WebSocket, Authentication (formerly JASPIC) and Annotations. A new major version usually follows a new Servlet specification. The table comes from the project's "Which version do I want?" page.

Tomcat branchServletJSP / PagesELWebSocketAuthentication (JASPIC)Platform
3.3.x2.21.1N/AN/AN/AJ2EE era
4.1.x2.31.2N/AN/AN/AJ2EE era
5.5.x2.42.0N/AN/AN/AJ2EE 1.4 era
6.0.x2.52.12.1N/AN/AJava EE 5 era
7.0.x3.02.22.21.1N/AJava EE 6 era
8.0.x3.12.33.01.1N/AJava EE 7 era
8.5.x3.12.33.01.11.1Java EE 7 era
9.0.x4.02.33.01.11.1Java EE 8
10.0.x5.03.04.02.02.0Jakarta EE 9
10.1.x6.03.15.02.13.0Jakarta EE 10
11.0.x6.14.06.02.23.1Jakarta EE 11

The "Platform" column for 3.3 through 8.5 is our guide to the era; the Tomcat page names the platform only for 9.0 onwards.

The two exceptions: 8.5 and 10.0

Tomcat 8.5 was forked in March 2016 from the 9.0.0.M4 milestone, because the specifications Tomcat 9 targeted were not final for years and a stable 9.0 could not ship. 8.5 carried 9.0's HTTP/2 (with Tomcat Native), OpenSSL for the NIO and NIO2 connectors and SNI at the 8.0 specification level, dropped the BIO connectors and the Comet API, and replaced 8.0. That is why 8.0 ended in 2018 while 8.5 lasted until 2024.

Tomcat 10.0 delivered Jakarta EE 9, whose main purpose was the javax.* to jakarta.* rename. Once 10.1 arrived with Jakarta EE 10, 10.0 was superseded and reached end of life on 31 October 2022, less than two years after its first stable release.

Alpha, beta and stable

Each release is labelled alpha, beta or stable when it is voted on, and the "Which version" page says a release cannot be stable until its specifications are final. That is why first stable releases carry numbers such as 7.0.6, 8.0.9, 9.0.4 and 10.0.2.

Tomcat release timeline: first releases and end of life

The table below lists, for each branch, the earliest release the Tomcat news archive records, the first release the project called stable, the final or latest version and the end of life date. First release dates come from tomcat.apache.org news pages; end of life dates come from the end of life announcements and the "Which version" page.

BranchMinimum JavaFirst release recordedFirst stable releaseFinal or latest versionEnd of life
3.3.x1.1Before 2010 (not in the news archive)Not recorded3.3.29 March 2004
4.1.x1.3Before 2010Not recorded4.1.4025 June 2009
5.5.x1.4Before 2010Not recorded5.5.3630 September 2012
6.0.x5Before 2010 (archive directory for 6.0.0 dated October 2006)Not recorded6.0.5331 December 2016
7.0.x6 (7 for WebSocket)7.0.0, 29 June 20107.0.6, 14 January 20117.0.10931 March 2021
8.0.x78.0.0 RC1, 5 August 20138.0.9, 25 June 20148.0.5330 June 2018
8.5.x78.5.0 (beta), 24 March 20168.5.3, 13 June 2016 (first without a beta label)8.5.10031 March 2024
9.0.x89.0.0.M1 (alpha), 19 November 20159.0.4, 22 January 20189.0.123 (12 October 2026)31 March 2027 (announced)
10.0.x810.0.0 M1, 20 February 202010.0.2, 2 February 202110.0.27 (10 October 2022)31 October 2022
10.1.x1110.1.0 M1, 15 June 202110.1.0, 26 September 202210.1.61 (12 October 2026)Not announced
11.0.x1711.0.0 M1, 5 December 202211.0.0, 9 October 202411.0.27 (12 October 2026)Not announced

Two notes on the sources. The "Which version" page lists the 5.5 end of life as "2012-09-31", a date that does not exist; the announcement of 10 August 2011 says 30 September 2012, and we use that. The news archive starts in 2010, so first release dates for 3.x through 6.0 are left as "before 2010" rather than guessed.

How long does a Tomcat branch last?

The "Which version" page says major versions are "typically supported" for 10 years: 7.0 ran from 2010 to 2021, and 9.0 runs from 2015 (first milestone) to 2027. Branches replaced by a near twin (8.0 by 8.5, 10.0 by 10.1) ended much sooner.

End of life notices arrive 13 to 15 months ahead and follow a fixed shape. After the end date, releases are "highly unlikely", bugs affecting only that branch are not fixed, and security reports are not checked against it. About three months later the download pages, mirror copies and documentation links go, but every release stays in the Apache archive, which is why old versions keep turning up in images and build caches.

What happens to Tomcat 9 after March 2027?

Tomcat 9 is the last branch that implements Java EE (javax.*), and many applications cannot move to Jakarta EE quickly. The 9.0.x end of support notice, dated 11 February 2026, sets out the plan:

  • 9.0.x support ends on 31 March 2027, with a final 9.0.x release expected shortly before that.
  • Shortly before 9.0.x ends, releases from a new 9.1.x branch begin, and they continue until 31 December 2030.
  • The difference between 9.0.x and 9.1.x is meant to be small. The APR/native connectors for HTTP, HTTPS and AJP are not available in 9.1.x, and Tomcat Native 1.3.x is not supported; Tomcat Native 2.0.x continues to work for NIO with OpenSSL.
  • For users not relying on Tomcat Native, or on Tomcat Native 2.0.x, moving from 9.0.x to 9.1.x should look like a normal point release upgrade.

The notice still recommends that Tomcat 9 users move to a newer major version with the help of the Jakarta EE migration tool rather than settle on 9.1.x. One inconsistency to be aware of: the "Which version" page, at the time of writing, still says the 9.1.x end date "has not been determined" and that 9.0.x support ends "no earlier than" 31 March 2027, while the newer notice and the home page give the firm dates above. We use the dated notice.

What changed in each branch?

The specification table above covers the API levels. What each branch added beyond them, per the project's own descriptions:

  • 5.0 and 5.5: a refactored deployer, monitoring through JMX and the manager application, integrated session clustering and native Windows and Unix wrappers. 5.5 kept 5.0's specification levels but reworked the internals.
  • 6.0: memory use optimisations, advanced IO and refactored clustering.
  • 7.0: web application memory leak detection and prevention, tighter security for the Manager and Host Manager applications and a generic CSRF protection filter. WebSocket support needs Java 7, although the rest of 7.0 runs on Java 6.
  • 8.0: a single common resources implementation replacing several older resource extension features.
  • 9.0: HTTP/2 (on Java 9 or later since 9.0.0.M18, or with the Tomcat Native library), OpenSSL for TLS on the NIO and NIO2 connectors, and SNI based TLS virtual hosting. Its security page has the most release entries of any branch, 72 at the time of writing, because it has been maintained the longest.
  • 10.0 and 10.1: little new function at first; the change that mattered was the package rename, covered below. 10.1 raised the minimum to Java 11.
  • 11.0: Java 17 as the minimum and no Security Manager. The 11.0 migration guide explains that the Security Manager is deprecated from Java 17 and that the Jakarta EE 11 specifications removed support for it, so Tomcat removed it too. The 11.0 security guide suggests running one web application per Tomcat instance in a container or VM instead.

The project already mentions a future Tomcat 12 in release notes. For example, the 9.0.121 notes (18 August 2026) introduce a setting that controls whether URL patterns in web.xml are treated as encoded or decoded, and say Tomcat 12 will always treat them as decoded. No Tomcat 12 release appears on the download or "Which version" pages as of this writing.

What did the javax to jakarta change in Tomcat 10 mean for applications?

What moved, and why it breaks binaries

Tomcat's release notes explain the change as a result of the transfer of Java EE to the Eclipse Foundation: with Jakarta EE, the primary package for every API Tomcat implements changed from javax.* to jakarta.*. The Tomcat 10.0 migration guide calls it "a significant breaking change" and says web applications must be recompiled against the new APIs.

In practice that means:

  • A servlet compiled against javax.servlet.http.HttpServlet does not load as a servlet on Tomcat 10 or later, because Tomcat 10 only knows jakarta.servlet.http.HttpServlet.
  • Libraries that touch the Servlet API (filters, web frameworks, JSP tag libraries, WebSocket libraries) need Jakarta builds too, not only your own code.
  • Only the Java EE packages moved. The migration tool's documentation stresses that not all javax.* packages are part of Java EE; packages that belong to the JDK itself (such as javax.crypto or javax.net.ssl) keep their names.
  • XML schema references in deployment descriptors do not need to change; Jakarta EE 9 still accepts the older schemas.

Our javax to jakarta migration post covers what the rename does to dependency trees and scanner output. Here we focus on the Tomcat side: what the project ships to help.

How the Apache Tomcat migration tool for Jakarta EE works

The Apache Tomcat migration tool for Jakarta EE takes a web application written for Java EE 8 that runs on Tomcat 9 and converts it so it runs on Tomcat 10 or later. It renames each Java EE 8 package to its Jakarta EE replacement in class files, string constants, configuration files, JSPs, TLDs and similar resources. Version 1.0.13 is the current release on the project's download page, signed with the Tomcat release managers' keys and published with SHA-512 checksums.

It works on a compressed archive, a folder or a single file, and writes the result as the same type of resource at the destination:

# Verify the download first (signature and SHA-512), then:
java -jar jakartaee-migration-1.0.13-shaded.jar \
  -profile=TOMCAT \
  myapp.war myapp-jakarta.war

The options, from the tool's own usage text:

OptionWhat it does
-profile=TOMCATDefault. Converts only the Java EE APIs that Tomcat provides
-profile=EEConverts all Java EE APIs
-profile=SERVLETConverts only the Servlet API
-profile=JEE8Converts back to Java EE 8 names; classes that use Jakarta EE 10 additions will not work
-exclude=patternSkips matching files; can be repeated; * and ? wildcards; case sensitive
-matchExcludesAgainstPathNameMatches exclusions against the full path rather than the file name
-zipInMemoryProcesses archives in memory, for zip structures the streaming mode cannot handle
-logLevel=FINEMore detailed logging (INFO is the default)

Three behaviours matter for security and compliance:

  1. Signatures are removed. The tool strips cryptographic signatures from JAR files it changes, because the rewritten classes no longer match them, and logs a warning for each one. If you rely on signed JARs, plan to re sign or to replace those libraries with Jakarta builds from their maintainers.
  2. Third party code is modified. The project's README warns that the tool may change third party content and recommends checking that each library's license permits modification, especially if you distribute the result.
  3. It is a bridge, not a destination. A converted WAR runs, but your source still says javax. Every rebuild needs the conversion again until the source and dependencies move to Jakarta artifacts.

The tool is also available as an Ant task (javax2jakarta), and Debian, Ubuntu and Fedora package it as tomcat-jakartaee-migration with a javax2jakarta command.

Conversion at deployment time: webapps-javaee

Tomcat 10 and later can also run the conversion for you. The 10.0 migration guide and every 10.x release announcement describe it: place a Java EE web application in the Host's legacyAppBase folder, $CATALINA_BASE/webapps-javaee by default, and Tomcat converts it to Jakarta EE and copies the result into webapps.

This is useful for one off legacy applications. It is a poor fit for applications you build yourself, because the artifact you tested is not the artifact that runs, and an SBOM built from the original WAR describes javax libraries that, after conversion, carry rewritten bytecode.

How does the Tomcat security process work?

Reporting privately

The Tomcat security page asks reporters to use the private list, security@tomcat.apache.org, before any public disclosure. It is only for undisclosed vulnerabilities in Tomcat; configuration questions go to the public users list. Under the ASF committer guide, project security lists copy every message to the foundation wide security@apache.org list automatically.

What counts as a Tomcat vulnerability

The Tomcat security model sets the boundaries. Administrative users are trusted, so reports that assume the attacker already controls Tomcat's binaries, configuration, logs, work directories, session store, Manager applications, JMX or the Java attach API are rejected; tricking an administrator, as in CSRF, is accepted. Deployed web applications are trusted too: a flaw in your application, or an unsecured WebDAV or PUT feature, is an application vulnerability. Flaws in the applications that ship with Tomcat are accepted. Data arriving through a connector is untrusted, apart from documented exceptions such as permitted AJP request attributes and headers processed by RemoteIpValve.

How a fix is made and announced

The ASF publishes a default process that every project follows unless it documents another. At concept level:

  1. Work in private. No public tickets, and commit messages must not reveal that a change is a security fix.
  2. Acknowledge. The project confirms receipt to the reporter, investigates, and accepts or rejects the report with an explanation.
  3. Assign a CVE. The Apache Security Team is a CVE Numbering Authority for all Apache projects and the only group that can allocate CVE IDs to them.
  4. Resolve. The team agrees the fix privately, drafts the announcement, shares both with the reporter and agrees a release schedule. An unresponsive reporter does not block a severe fix.
  5. Release. The fix is committed and shipped in a normal, voted release.
  6. Announce. With or after the release announcement, the vulnerability is announced to the release lists, the reporter and the oss-security list. The ASF notes this is the first point at which any detail becomes public.
  7. Complete. The project updates its security pages and the CVE record gets a link to the public announcement.

Announcements are written to let people assess their own risk "and no more"; the ASF guide says they do not normally include reproduction steps.

Reading a branch security page

Tomcat keeps one security page per major version: 11.x, 10.x (covering 10.0 and 10.1), 9.x, and archived pages for 8.x back to 3.x, plus pages for the JK connectors, the APR/native connector and Taglibs. Each page is organised by fixing release, newest first ("Fixed in Apache Tomcat 11.0.27" with its date). Each entry gives an impact rating, a description with the conditions that matter, the fixing commits, reporting and disclosure dates, and an "Affects" version range.

The ratings are the team's own. Critical means potential remote code execution. Important (or High) covers data compromise or availability, such as easy remote denial of service or access to protected files. Moderate applies when significant mitigation exists, such as unlikely configurations or authenticated attackers. Low covers the rest. Each rating is the worst case across platforms.

Two consequences follow from this design:

  • No binary patches. The overview page says binary patches are not produced except in rare circumstances; the 9.x page says they are "never provided". The fix is to upgrade to the version where the issue is fixed.
  • Branch pages stop when the branch stops. Once a branch is end of life, reports are no longer checked against it. An issue fixed in 10.1 and 11.0 after 8.5 ended may well affect 8.5, but the 8.x page will never say so. "Not listed for my branch" on an archived page means "not checked", not "not affected".

Which defaults changed over time?

Tomcat's out of the box configuration has become steadily more conservative. The table summarises defaults that matter for exposure; details follow.

SettingOlder behaviourCurrent behaviourWhere documented
AJP connectorEnabled by default, listening on all addresses (before 9.0.31, 8.5.51, 7.0.100)Commented out in server.xml; listens on loopback by default; will not start without a secret unless secretRequired="false"9.x and 8.x security pages; AJP connector reference
Server HTTP headerApache-Coyote/1.1 in 4.1 to 8.0Not set by default from 8.511.0 security guide
Shutdown port8005 with command SHUTDOWNStill 8005 in the sample server.xml; can be disabled with port="-1"Server reference; security guide
Manager and Host ManagerShipped, protected by user configurationShipped, no users configured, RemoteCIDRValve restricts to localhostSecurity guide
Examples, docs, ROOT appsShippedStill shipped; guide says remove examples from any security sensitive installSecurity guide
Default servlet listingsDisabledlistings is false by defaultDefault servlet reference
Default servlet writesRead onlyreadonly is true, so PUT and DELETE are rejectedDefault servlet reference
TRACE methodDisabledallowTrace false by defaultSecurity guide
Error page versionShows Tomcat versionStill shows it; set showServerInfo="false" on ErrorReportValveSecurity guide
Security ManagerOptionalRemoved in 11.011.0 migration guide

AJP: from enabled by default to off and locked

AJP (Apache JServ Protocol) lets a front end web server pass requests to Tomcat. The connector reference warns that it allows "greater direct manipulation of Tomcat's internal data structures" than HTTP, and the security guide calls it a clear text protocol for trusted networks only.

Until February 2020, Tomcat shipped an AJP connector enabled by default on all configured addresses. After a reported issue in early 2020 (CVE-2020-1938, covered in our Tomcat and Coyote explainer), the project hardened the default in 9.0.31 and 8.5.51 (11 February 2020) and 7.0.100 (14 February 2020), warning that upgraders would likely need small configuration changes. Today the sample connector in conf/server.xml is commented out, address defaults to loopback, secretRequired defaults to true so a connector without a secret will not start, and forwarded requests with unknown attributes are blocked unless allowedRequestAttributesPattern allows them.

The shutdown port

Tomcat listens on a TCP port, 8005 in the sample server.xml, for a shutdown string (SHUTDOWN). Anyone who can reach that port from the host can stop the server. port="-1" disables it, but the Server reference warns the standard shutdown.sh and catalina.sh stop scripts then cannot stop Tomcat, so it suits installs run as a service through Apache Commons Daemon. If you keep the port, set a strong shutdown string.

Bundled web applications and the default servlet

A download still includes ROOT, the documentation, the examples, Manager and Host Manager. The security guide says to always remove the examples from security sensitive installs (the cookie examples can help an attacker chain other weaknesses). Manager and Host Manager have no users by default; if you enable them, use strong passwords and keep the LockOutRealm and the RemoteCIDRValve that limits access to localhost. ROOT and the docs are low risk but reveal the version.

The default servlet's documented defaults are safe: listings is false and readonly is true, so PUT and DELETE are rejected. Problems come from changing them for convenience, and the security model makes securing any write feature the application's responsibility.

Why does embedded Tomcat change where the version comes from?

Two ways to run Tomcat

A traditional install is a distribution with bin, conf, lib and webapps directories into which you deploy WAR files. An embedded deployment reverses that: your application JAR contains Tomcat's classes and starts Tomcat itself. Those classes are published to Maven Central under org.apache.tomcat.embed, mainly as tomcat-embed-core; its metadata lists 11.0.27, published on 12 October 2026, the same day as the distribution.

Frameworks pick the version for you

In Spring Boot, spring-boot-starter-web includes Tomcat through spring-boot-starter-tomcat. Spring Boot manages the versions of supported libraries through a bill of materials (BOM), spring-boot-dependencies, so you normally declare no version, and upgrading Spring Boot upgrades them "in a consistent way".

The managed version tracks the Tomcat branch that matches each Spring Boot generation. From Spring Boot's own dependency version tables:

Spring Boot docs versionManaged tomcat-embed-coreTomcat branchNamespace
2.7.189.0.839.0javax.*
3.5.1610.1.5510.1jakarta.*
4.1.211.0.2711.0jakarta.*

So a team that has not touched a Tomcat download in years can still have moved across three Tomcat branches, and from Java EE to Jakarta EE, through framework upgrades alone. The reverse also holds: an application pinned to an old framework release keeps an old Tomcat even after Apache ships fixes.

Why the SBOM says tomcat-embed-core

Because the embedded classes arrive as a Maven dependency, a software bill of materials built from the application lists org.apache.tomcat.embed:tomcat-embed-core at a specific version, typically as a transitive dependency of the framework starter. It does not list "Apache Tomcat" as an installed server, and a host level inventory will not find a Tomcat install at all.

That has two practical effects:

  • Vulnerability matching has to treat tomcat-embed-core and the Tomcat distribution as the same code. The Tomcat security pages list fixes by Tomcat version, and the embedded artifact uses the same version numbers.
  • Not every issue on a Tomcat security page applies to an embedded deployment. Issues in the Manager application, the examples or the AJP connector need features that embedded setups usually do not include. Read the conditions in each entry rather than assuming either way.

Overriding the managed version

When a Tomcat fix ships before your framework's next release, you can override the managed version. Spring Boot exposes a tomcat.version property for this when you use its parent POM. Spring Boot's Maven plugin documentation shows the pattern, and adds a warning worth taking seriously: each Spring Boot release is tested against a specific set of dependencies, and "overriding versions may cause compatibility issues".

<!-- pom.xml, when the project inherits from spring-boot-starter-parent -->
<properties>
  <tomcat.version>11.0.27</tomcat.version>
</properties>

If you import the BOM in dependencyManagement instead of inheriting the parent, the property does not work; the Spring Boot documentation says to add your own dependencyManagement entries before the spring-boot-dependencies import. Stay within the branch your framework expects. Raising 10.1.x to a later 10.1.x is a patch upgrade; forcing 11.0 under a framework built for 10.1 is an untested platform change.

Branch summary: specification, Java, release and end of life

BranchSpecification levelMinimum JavaFirst stable releaseEnd of lifeStatus (October 2026)
11.0Servlet 6.1, Jakarta EE 11179 October 2024Not announcedSupported, current focus
10.1Servlet 6.0, Jakarta EE 101126 September 2022Not announcedSupported
10.0Servlet 5.0, Jakarta EE 982 February 202131 October 2022Superseded by 10.1
9.0Servlet 4.0, Java EE 8822 January 201831 March 2027Supported; 9.1.x to follow until 31 December 2030
8.5Servlet 3.1, JASPIC 1.1713 June 2016 (8.5.3, first without beta label)31 March 2024End of life
8.0Servlet 3.1725 June 201430 June 2018End of life
7.0Servlet 3.0614 January 201131 March 2021End of life
6.0Servlet 2.55Not on tomcat.apache.org31 December 2016End of life
5.5Servlet 2.41.4Not on tomcat.apache.org30 September 2012End of life
4.1Servlet 2.31.3Not on tomcat.apache.org25 June 2009End of life
3.3Servlet 2.21.1Not on tomcat.apache.org9 March 2004End of life

Step by step: find your Tomcat version and plan the upgrade

These steps cover both a standalone install and an embedded application. None of them change anything until step 6.

1. Find the version of a standalone install

The distribution ships a version.sh script in bin that calls catalina.sh version. You can also run the ServerInfo class directly; it prints the server version, build date, version number and the JVM it ran on.

# Standalone install
"$CATALINA_HOME/bin/version.sh"

# Same information without the scripts
java -cp "$CATALINA_HOME/lib/catalina.jar" org.apache.catalina.util.ServerInfo

Do not rely on the Server header or the default error page. The header is not sent by default from 8.5 onwards, and the reported version can be changed with ServerInfo.properties, so a banner can be missing or wrong.

2. Find the version inside an embedded application

# Maven: show where tomcat-embed artifacts come from
mvn dependency:tree -Dincludes=org.apache.tomcat.embed

# Gradle: explain why a version was chosen
./gradlew dependencyInsight --dependency tomcat-embed-core --configuration runtimeClasspath

# A built Spring Boot fat jar: list the bundled Tomcat jars
unzip -l target/myapp.jar | grep tomcat-embed

If you already produce a CycloneDX SBOM for the build, the component is there too:

jq -r '.components[] | select(.name=="tomcat-embed-core") | "\(.group):\(.name) \(.version)"' bom.json

A Safeguard scan of the repository, an image or an SBOM file builds the same inventory and records which projects carry which version:

safeguard scan --dir .
safeguard scan --image registry.example.com/team/app:1.4.2
safeguard scan --sbom bom.json

3. Identify the branch and its status

Take the first two numbers of the version (9.0, 10.1, 11.0, 8.5) and look the branch up in the "Which version" table. If the branch is end of life, skip straight to step 7: no security page for that branch will tell you about issues found after its end date.

4. Compare against the branch security page

Open the security page for your major version (security-11, security-10 or security-9) and read every "Fixed in" entry newer than your version. For each, check the "Affects" range and the conditions in the description (AJP enabled, HTTP/2 enabled, a particular valve or servlet in use). Note the impact rating, remembering it is a worst case.

5. Check the configuration you actually run

# Is an AJP connector enabled? (commented lines are fine)
grep -n 'AJP/1.3' "$CATALINA_BASE/conf/server.xml"

# What is the shutdown port set to?
grep -n '<Server ' "$CATALINA_BASE/conf/server.xml"

# Which bundled applications are still deployed?
ls "$CATALINA_BASE/webapps"

If AJP is enabled, confirm it listens only on an address your proxy uses, has a secret, and is not reachable from untrusted networks. Remove examples, and remove docs, ROOT, manager and host-manager unless you use them.

6. Upgrade within the branch first

Moving from 10.1.x to the latest 10.1.x is the low risk change: same specifications, same minimum Java, same package names. For a standalone install, verify the download's signature and SHA-512 checksum against the published KEYS file, replace CATALINA_HOME, keep your CATALINA_BASE configuration and diff the new default conf files against yours. For an embedded application, upgrade the framework to a release that manages the fixed Tomcat version; if one is not out yet, override tomcat.version within the same branch, then run the full test suite.

7. Plan the branch move

A branch move is a project, not a patch. Use the migration guides on tomcat.apache.org (9.0 to 10.0, 10.0 to 10.1, 10.1 to 11.0) to list changes, and decide early:

  • Staying on Java EE past 2027? Plan for 9.1.x and move off the APR/native connectors now, as the 9.0 end of support notice advises.
  • Moving to Jakarta EE? Convert source code and dependencies, not only the WAR. Use the migration tool to test quickly, then replace javax libraries with Jakarta builds.
  • Moving to 11.0? Confirm Java 17 everywhere and remove any reliance on the Security Manager.

Common mistakes

Running 8.5 after 31 March 2024. 8.5 was the default in many images and installer scripts for years, and its archive downloads still work. Its security page stopped being checked when support ended, so newer issues are not listed for it at all.

Leaving the example and manager applications installed. The examples have no place on a security sensitive server, and a Manager application exposed with weak credentials is a well known target. Keep the RemoteCIDRValve and LockOutRealm defaults if you need it.

Exposing AJP. Re enabling the AJP connector by uncommenting an old server.xml, setting secretRequired="false" or binding it to all addresses undoes the 2020 hardening. Treat the AJP port as an internal interface between your proxy and Tomcat only.

Carrying an old server.xml across upgrades. Copying the whole conf directory from an old install keeps old defaults, including connector settings the new release would not use. Diff against the new defaults instead.

Overriding the framework's Tomcat version without testing. Bumping tomcat.version within a branch is often reasonable; jumping branches under a framework that expects another one, or forgetting the override after the framework moves on, causes subtle breakage. Remove the override once the framework catches up.

Assuming embedded applications are not affected because "we don't run Tomcat". If the SBOM lists tomcat-embed-core, you run Tomcat. Hosts and container inventories that only look for installed servers will miss it.

Converting at deploy time forever. webapps-javaee and the migration tool are bridges. Running rewritten bytecode indefinitely means your SBOM and your source describe a different application from the one in production.

FAQ

What is the latest version of Apache Tomcat?

As of 25 October 2026, the latest releases are 11.0.27, 10.1.61 and 9.0.123, all released on 12 October 2026. Only these three branches are supported; 8.5, 10.0 and everything older are end of life.

When does Tomcat 9 support end?

Support for 9.0.x ends on 31 March 2027, according to the end of support notice dated 11 February 2026. A 9.1.x branch for Java EE applications will follow, with releases until 31 December 2030 and without the APR/native connectors.

When did Tomcat 8.5 reach end of life?

31 March 2024. The announcement was published on 13 December 2022, and 8.5.100 is listed as the final release.

Which Java version does Tomcat 11 need?

Java 17 or later. Tomcat 10.1 needs Java 11 or later, and Tomcat 9.0 needs Java 8 or later.

Why does my application not start on Tomcat 10?

Most likely because it was compiled against javax.servlet and Tomcat 10 and later implement jakarta.servlet. Recompile against the Jakarta APIs with Jakarta builds of your libraries, or convert the WAR with the Apache Tomcat migration tool for Jakarta EE as a stopgap.

Does Tomcat provide patches for security vulnerabilities?

Not binary patches. You upgrade to the release where the issue is fixed. The security pages usually link the fixing commits, which you can apply and build yourself if you cannot upgrade.

How do I report a security vulnerability in Tomcat?

Email security@tomcat.apache.org privately before any public disclosure, and check the Tomcat security model first to see what the team treats as a vulnerability.

Is the AJP connector enabled by default in Tomcat?

No. Since 9.0.31, 8.5.51 and 7.0.100 (February 2020) the sample connector is commented out. If you enable it, it listens on loopback by default and will not start without a secret unless you set secretRequired="false".

Why does my SBOM show tomcat-embed-core instead of Tomcat?

Because your application embeds Tomcat as a library, usually through a framework starter. The version numbers match Tomcat releases, so the Tomcat security pages apply, subject to the conditions in each entry.

Where Safeguard fits

The fit depends on how you run Tomcat. For a Tomcat distribution installed on a host or provided by an operating system package, Safeguard does not upgrade the server, edit server.xml or remove bundled applications; those changes come from your own operations work, your distribution or the Tomcat project.

For embedded Tomcat, the fit is direct, because tomcat-embed-core is an ordinary open source dependency. Safeguard's SBOM and dependency scanning of repositories, container images and SBOM files finds it, records the version, and the platform shows which projects contain a given component and version. That answers the first question after a Tomcat release ("where do we run the affected branch?") across many services at once. Policies and gates evaluated in CI can stop builds that carry versions you have decided not to ship, such as any 8.5.x. Reachability analysis helps rank which findings involve code your application actually calls; how much that narrows the list depends on the codebase and should be measured during evaluation. For quick lookups without an account, Gold Open Source at gold.safeguard.sh gives free CVE intelligence with affected and fixed versions for open source components.

Tomcat rarely ships alone: the framework that embeds it, the base image it runs in and the JDK beneath it all bring open source components that age at different speeds. The options below apply to the dependencies and images you build, while fixes in Tomcat itself still come from Apache releases.

Fix it without waiting for upstream

Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.

1. Autonomous remediation: pull requests, not tickets

When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation categories include dependencies, licenses, security posture and findings, and each one is set separately. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.

2. Gold Open Source: the safe version in seconds, free

gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds.

3. Gold Registry: start from components that are already fixed

Gold Registry provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs and a completed license check, with signed build provenance (signed with Safeguard's key and verifiable with cosign, SLSA Build Level 3 as the design target) and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.

When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. Ask which packages it covers before you plan around it.

Your situationWhat to use
A fixed version existsAutonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version
You need to know today whether you are affectedGold Open Source lookup and "Am I affected?" checker, free and without login
You want vulnerable versions to stop shippingSafeguard policies and gates in CI
Upstream has no fix yet, or will not ship oneA custom Gold request; fork and patch
You want to start clean on new projectsPull hardened components and images from Gold Registry

One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.

See how Safeguard would help

The first demo is a real Safeguard CLI session in a repository. The assistant reads a finding and its advisory, asks before any command that changes something, edits a dependency version and runs the install and the tests, then prints a summary without pushing. For a Spring Boot service, the same flow fits a patch level Tomcat upgrade: the change is a framework version bump or a tomcat.version property, followed by the test run that tells you whether it is safe.

Click through it at your own pace, or open it full screen.

The second demo sets up the Safeguard runner on your own machine, approves it with its device code and then scans from the terminal. Scanning a built application JAR or image there shows the exact tomcat-embed-core version you are about to ship, before it leaves the build machine.

Click through it at your own pace, or open it full screen.

The third demo connects Claude to the Safeguard MCP server with OAuth and chooses which tools Claude can use. Once connected, a question such as "which of our services still carry a 9.0.x Tomcat" can be answered from your own Safeguard inventory as the March 2027 date approaches.

Click through it at your own pace, or open it full screen.

To try it on your own repositories and images, download Safeguard or read the CLI documentation. For the JDK underneath Tomcat, see how to install a Java JDK safely and whether a dependency scanner checks the JDK.

Quick check

Your service is on Tomcat 8.5.100 and the 8.x security page lists nothing newer. Is it safe?

No. 8.5 reached end of life on 31 March 2024, and after that date security reports are no longer checked against the 8.5 branch. An empty archived page means unchecked, not unaffected. Move to a supported branch.

Your Spring Boot 3.5 application's SBOM shows tomcat-embed-core 10.1.55. Which Tomcat security page applies?

The 10.x page, using the 10.1 entries. The embedded artifact shares Tomcat's version numbers, so compare 10.1.55 with every "Fixed in Apache Tomcat 10.1.x" entry newer than it, and check each entry's conditions against how your application uses Tomcat.

Sources

Last reviewed: 25 October 2026. Tomcat releases roughly monthly; check tomcat.apache.org and the security page for your branch for the latest version.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.