---
title: "Tomcat Ghostcat AJP (CVE-2020-1938)"
canonical: https://trickest.com/library/cve-2020-1938-tomcat-ghostcat-ajp
description: "Flag Apache Tomcat hosts for CVE-2020-1938 by reading Apache Tomcat/x.y.z from a GET 404 probe. Floors 7.0.100 / 8.5.51 / 9.0.31. No AJP."
---

# Tomcat Ghostcat AJP (CVE-2020-1938)

## Overview

This workflow finds Apache Tomcat and sorts each host by whether its version falls below the CVE-2020-1938 Ghostcat fixed floors. CVE-2020-1938 is an AJP connector flaw that can allow file read or remote code execution on misconfigured Tomcat. This check never opens AJP port 8009 and never reads a file. Give it hostnames, IP addresses, or URLs you are authorised to test. The workflow GETs `/nonexistent-ghostcat-probe-404`, fingerprints Tomcat from the default 404 page, parses `Apache Tomcat/x.y.z`, and compares that number to the per-branch floors in the graph (7.0.100, 8.5.51, 9.0.31, with 6.0 and 8.0 treated as EOL stubs). Every host comes back affected or not, so a fleet advisory becomes an evidenced list for [exposure management](/use-cases/exposure-management). There is no AJP handshake and no confirm step.

Run it on a schedule when app servers turn over. A restored container image that still ships an unpatched 8.5 line is the reason the same fingerprint stays useful.

## Pipeline

1. Read the target list. Hosts, URLs, or ranges, one per line, become the scope.
2. GET `/nonexistent-ghostcat-probe-404` on each host and fingerprint Tomcat from the 404 page body that embeds `Apache Tomcat/x.y.z`.
3. Parse the version and compare it to the CVE-2020-1938 per-branch floors in the graph.
4. Collect the per-host rows: product match, version, vulnerable flag, and any fetch error.
5. Emit the summary counts: hosts checked, product hits, vulnerable, and errors.

## Inputs

- **Target scope.** Hostnames, IP addresses, CIDR ranges, or URLs, one per line. Full URLs and host:port entries work too, since the workflow normalizes each into a bare host. Point it at scope you are authorised to test.

## Outputs

- **results.jsonl.** One row per host: URL, whether Tomcat was detected, the version read, the vulnerable flag, and detail text.
- **findings.jsonl.** The same per-host verdict shaped for triage, with severity set from the vulnerable flag.
- **summary.json.** Counts across the list: targets, product hits, vulnerable, and errors, plus the detection notes from the graph.

## Integrations

- HTTP. Unauthenticated GET of `/nonexistent-ghostcat-probe-404` only. No AJP:8009 connect and no file-read probe.

## Sample output

The records below are illustrative and do not come from a real run. They show one Tomcat host below a CVE-2020-1938 floor, one at or above its branch floor, and one host that is not the product.

```jsonl
{"url": "https://app.example.com", "is_product": true, "product_version": "8.5.40", "vulnerable": true, "detail": "below branch floor 8.5.51"}
{"url": "https://app.example.org", "is_product": true, "product_version": "9.0.31", "vulnerable": false, "detail": "at or above fixed release"}
{"url": "https://shop.example.net", "is_product": false, "product_version": null, "vulnerable": false, "detail": "not identified as Apache Tomcat"}
```

```json
{"cve": "CVE-2020-1938", "total_targets": 3, "product_detected": 2, "vulnerable": 1, "errors": 0}
```

## FAQ

### Which Tomcat versions does this flag?

Builds below the per-branch floors in the graph: 7.0.100, 8.5.51, and 9.0.31. The 6.0 and 8.0 lines are EOL stubs in the same table. A version picks the matching band, then compares to that band's floor. The compare uses the string the 404 page itself served.

### Does an affected row mean Ghostcat AJP worked?

No. The check only GETs `/nonexistent-ghostcat-probe-404` and reads `Apache Tomcat/x.y.z`. It does not connect to AJP:8009, does not read a file, and does not confirm RCE.

### Is this check safe on production?

Yes. It is a read-only unauthenticated GET that expects a 404. It does not touch the AJP connector.

### Does the check need credentials?

No. It fingerprints the public HTTP error page the way an external scanner would.

### What is CVE-2020-1938?

Ghostcat, an AJP connector vulnerability in Apache Tomcat that can allow file read or remote code execution. This workflow maps hosts to that CVE by HTTP version exposure only.

## Related workflows

- [Tomcat PUT JSP RCE (CVE-2017-12617)](/library/cve-2017-12617-tomcat-put-jsp-rce). Reach for it when you need the earlier Tomcat HTTP PUT fingerprint.
- [Tomcat JMX RCE (CVE-2016-8735)](/library/cve-2016-8735-tomcat-jmx-rce). Reach for it when the next Tomcat flag is JMX, not Ghostcat.
- [Tomcat Partial PUT (CVE-2025-24813)](/library/tomcat-rce-check-cve-2025-24813). Reach for it when you need the later Partial PUT path check.

---
_Markdown source of https://trickest.com/library/cve-2020-1938-tomcat-ghostcat-ajp._
