For thirteen years, nearly every Apache Tomcat server shipped with a network service most operators never thought about. The AJP (Apache JServ Protocol) connector listened on TCP port 8009 by default, waiting for a reverse proxy such as mod_jk or mod_proxy_ajp to forward requests to it. In February 2020, researchers at Chaitin Tech showed that this quiet, trusted connector could be spoken to directly by an attacker — and that a carefully crafted AJP message could read any file inside a web application and, under common conditions, execute code. The flaw, tracked as CVE-2020-1938 and nicknamed Ghostcat (also filed in China's national database as CNVD-2020-10487), affected essentially every supported Tomcat release at the time.
Vulnerability identity and severity
Ghostcat is a request-injection and file-inclusion flaw in the Tomcat AJP connector. The National Vulnerability Database assigns it a CVSS 3.x base score of 9.8 (Critical) with the vector AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H — network reachable, low complexity, no authentication, no user interaction, and full impact to confidentiality, integrity, and availability. That top-tier score reflects two outcomes chained together: unauthenticated arbitrary file read, escalating to remote code execution wherever an application also accepts file uploads.
Timeline and impact
- Late 2019 — Chaitin Tech's security team identifies the AJP request-attribute abuse and reports it to the Apache Software Foundation.
- February 20, 2020 — Apache publishes fixes and the advisory; the issue is disclosed publicly as Ghostcat.
- Weeks after disclosure — mass internet scanning for exposed port 8009 begins, and multiple proof-of-concept tools appear on public repositories.
The impact was broad precisely because the AJP connector was enabled by default. Any Tomcat instance that exposed 8009 to an untrusted network — directly, through a misconfigured firewall, or via a container port mapping — was reachable. Attackers used Ghostcat to pull WEB-INF/web.xml and configuration files containing database credentials, API keys, and framework secrets, then pivoted deeper.
Root cause: trusting AJP request attributes
AJP is a binary protocol designed for a trusted reverse proxy to forward already-parsed HTTP requests to Tomcat. Because the proxy is assumed to be trustworthy, AJP lets the sender specify request attributes that Tomcat's AjpProcessor maps onto internal servlet variables. Three of those attributes are dangerous when an attacker can set them directly:
javax.servlet.include.request_urijavax.servlet.include.path_infojavax.servlet.include.servlet_path
By supplying these, an attacker instructs the default servlet to treat an arbitrary path as an include target. The following is a safe, conceptual illustration of the attribute manipulation — not a working exploit:
AJP13_FORWARD request
method: GET
attribute javax.servlet.include.servlet_path = "/"
attribute javax.servlet.include.path_info = "WEB-INF/web.xml"
Because the path resolves inside the application root, Tomcat returns the contents of files that should never be web-served, including everything under WEB-INF. The escalation to RCE follows when the target application allows uploading files anywhere on the server — even non-executable types such as images or text. An attacker uploads a file containing JSP source, then uses the same include mechanism to point Tomcat at that uploaded file, causing it to be interpreted as a JSP and executed. No .jsp extension is required, which is what made the RCE path so widely reachable.
Detection
- Inventory exposure. Check whether TCP 8009 is listening and whether it is reachable from untrusted networks. In a shell,
ss -ltnp | grep 8009or an external port scan reveals a live AJP endpoint. - Read
server.xml. Look for an active connector line such as<Connector port="8009" protocol="AJP/1.3" ... />. If AJP is not actually being used by a fronting proxy, that connector should not be there. - Version fingerprint. Determine the exact Tomcat build; anything earlier than the patched releases below is vulnerable if AJP is enabled.
- Log review. Unusual requests resolving to
WEB-INFpaths, or bursts of AJP traffic from a single source, are strong indicators of scanning or exploitation attempts.
Remediation and patched versions
Apache addressed Ghostcat in these releases — upgrade to at least:
- Tomcat 9.0.31 (9.x line)
- Tomcat 8.5.51 (8.5.x line)
- Tomcat 7.0.100 (7.x line)
- Tomcat 6.x reached end of life and received no fix; migrate off it.
The fix hardened the AJP connector in two ways. AJP was no longer enabled by default in fresh configurations, and the connector gained a requiredSecret / secret attribute (with secretRequired="true" by default) so that a proxy must present a shared secret before Tomcat will accept AJP requests. Concrete steps:
- Upgrade Tomcat to the patched release for your line.
- Disable AJP if you do not use it. Remove or comment out the
Connector port="8009"element inserver.xml. Most modern deployments front Tomcat with HTTP reverse proxying and do not need AJP at all. - If you must keep AJP, bind it to localhost with
address="127.0.0.1", set a strongsecret, and firewall port 8009 so only the reverse proxy host can reach it. - Verify the change by re-scanning for an open 8009 and confirming the connector rejects unauthenticated requests.
How Safeguard helps
Ghostcat is a reminder that a "known" component version and its runtime configuration are two different risk surfaces, and you need both mapped. Safeguard's software composition analysis fingerprints the exact Tomcat version embedded in your services, container images, and application servers, then reconciles it against CVE-2020-1938 so a vulnerable 8.5.50 or 9.0.30 build surfaces as a specific, prioritized finding instead of hiding inside a base image. Because Ghostcat is only exploitable when the AJP endpoint is actually reachable, Safeguard's DAST engine complements the inventory by probing your deployed surface for an exposed AJP connector and confirming whether the finding is live rather than theoretical. The Safeguard CLI brings the same detection into CI and into your container build, so a vulnerable Tomcat layer fails the pipeline before it ships to production. And if you want to see how this unified component-plus-exposure model compares to point tools, compare Safeguard against the alternatives.
Ghostcat sat undisturbed for over a decade because nobody was watching the default connector. Continuous inventory is what turns that kind of latent, forgotten exposure into an actionable ticket. Create a free Safeguard account or read the documentation to start mapping your runtime components today.