← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
tenable:83526 · CWE-310 · Disclosed 2015-01-08

Apache Tomcat 7

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is a smoke alarm wired to the wrong room

Plugin 83526 flags any Apache Tomcat 7.0.x < 7.0.60 as carrying a bundle of old OpenSSL bugs, especially FREAK (CVE-2015-0204). The practical exposure is much narrower: Tomcat BIO/NIO connectors use JSSE, while the APR/native connector uses OpenSSL. So the hit really matters only when the host loads tcnative / APR, exposes TLS through that path, and is linked against vulnerable OpenSSL (< 0.9.8zd, < 1.0.0p, or < 1.0.1k). On Windows, Tomcat Native 1.1.33 moved bundled binaries to OpenSSL 1.0.1m; that change aligns with the 7.0.60 era.

Tenable's version-only logic materially overstates real risk in modern enterprise fleets. FREAK is a man-in-the-middle downgrade problem, not unauthenticated Tomcat RCE, and even the broader CVE bundle here mostly lands as DoS / crypto weakness inherited from OpenSSL. If your Tomcat estate is standard Java TLS behind a reverse proxy or load balancer, this is usually backlog hygiene, not an emergency.

"Most 83526 hits are version-only noise unless Tomcat is actually using APR/native OpenSSL"
02 · The Attack Path

3 steps from start to impact.

STEP 01

Find a Tomcat node actually using APR/native OpenSSL

The attacker needs a Tomcat 7 host where TLS is handled by the APR/native path rather than JSSE. In practice that means tcnative is installed, the APR connector is active or auto-selected, and the linked OpenSSL build is old enough to include the 2015 bug set. The common weaponized validator here is testssl.sh or sslyze for cipher exposure, not an exploit framework.
Conditions required:
  • Tomcat 7.0.x before 7.0.60 is installed
  • APR/native (tcnative) is present and loaded
  • TLS is exposed through APR/native rather than JSSE
Where this breaks in practice:
  • Most Tomcat deployments use JSSE/NIO and never load APR/native
  • Many enterprise deployments terminate TLS on a reverse proxy or ADC instead of Tomcat itself
  • The plugin itself states detection is based only on self-reported version
Detection/coverage: Version scanners like Nessus catch the Tomcat version but do not prove APR/native is active. Config review, startup logs, server.xml, and TLS cipher scans are needed to confirm real exposure.
STEP 02

Get on path and force a downgrade

For the FREAK path, the attacker must sit between client and server and tamper with the handshake so the session falls back to RSA_EXPORT. The classic research tooling came from the SmackTLS / FREAK work; modern equivalents are custom MITM tooling or lab PoCs built around TLS downgrade testing. This is a network-adjacent attack, not direct internet-to-host exploitation.
Conditions required:
  • Attacker has man-in-the-middle position or equivalent network control
  • Server accepts export-grade RSA ciphers
  • Target client stack is susceptible to the downgrade pattern
Where this breaks in practice:
  • Requires prior network foothold, hostile Wi-Fi, malicious proxy, or other path control
  • Modern TLS configurations usually disable export ciphers entirely
  • Many browsers and clients were patched years ago
Detection/coverage: Server logs often look normal because the traffic still completes as TLS. TLS scanners can reveal export cipher support; network IDS may see anomalous cipher negotiation, but coverage is inconsistent.
STEP 03

Break session confidentiality, not the server

If the downgrade succeeds, the attacker can factor the temporary weak RSA key and read or tamper with the victim's TLS session. That compromises the intercepted connection, not the Tomcat process or the underlying host. There is no direct Tomcat code execution path here.
Conditions required:
  • Successful downgrade to export-grade RSA
  • Weak key factoring completed in useful time
  • Victim session remains active long enough to exploit
Where this breaks in practice:
  • Blast radius is per intercepted flow, not fleet-wide host takeover
  • No persistence or server compromise is obtained from FREAK alone
  • Operational payoff is much lower than a typical server-side RCE
Detection/coverage: You may only detect this indirectly through TLS posture audits, packet capture, or user-session anomalies. Endpoint agents on the Tomcat host usually will not see anything actionable.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo current KEV signal. OpenCVE shows KEV no for CVE-2015-0204, and this CVE does not appear in current CISA KEV searches. Historic attention was high in 2015, but this is not a modern mass-exploitation Tomcat item.
Proof-of-concept availabilityPublic PoCs exist. cvefeed reports 67 public GitHub PoC/exploit references for CVE-2015-0204, and the original public research came from the SmackTLS / FREAK work.
EPSSHigh EPSS, misleading here. Tenable's CVE page shows EPSS 0.91945; cvefeed shows percentile 0.99708 (~99.7th). That reflects broad historical exploit interest in FREAK as a TLS issue, not direct Tomcat-host compromise.
KEV statusNot KEV-listed. No CISA KEV entry for CVE-2015-0204 was found, and aggregator metadata reflects KEV no.
CVSS vectorCVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N from NVD for CVE-2015-0204. That vector already describes a limited confidentiality problem, not host takeover.
Affected versionsNessus flags Tomcat 7.0.x < 7.0.60. In reality, exposure depends on APR/native + OpenSSL; Tomcat docs state BIO/NIO use JSSE while APR/native uses OpenSSL.
Fixed versionsOpenSSL fixed FREAK in 0.9.8zd / 1.0.0p / 1.0.1k or later. Tomcat Native changelog shows Windows binaries in 1.1.33 used OpenSSL 1.0.1m; Tomcat 7.0.60+ is the plugin's cut line, but Linux/Unix builds may still rely on distro backports or locally linked OpenSSL.
Scanning / exposure dataInternet scanners test cipher posture, not Tomcat version. Shadowserver still publishes an SSL FREAK report for hosts that accept RSA_EXPORT ciphers and rates it LOW. This is a better exposure lens than the plugin's version-only check.
Disclosure dateCVE-2015-0204 was published by NVD on 2015-01-08. Nessus plugin 83526 was published on 2015-05-19 and updated 2024-05-06.
Reporting researchersThe FREAK research was disclosed by the SmackTLS team, with public attribution to researchers from IMDEA, INRIA, and Microsoft Research.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to LOW (3.1/10)

The decisive drag on severity is that this is usually not a real Tomcat exposure unless APR/native OpenSSL is actually in play; standard JSSE-based Tomcat deployments are outside the meaningful blast radius. Even when the FREAK path is real, the attacker still needs on-path network control to downgrade TLS, which makes this far less urgent than an internet-reachable server-side exploit.

HIGH APR/native vs JSSE is the key gating factor
HIGH FREAK is a MitM downgrade issue, not Tomcat RCE
MEDIUM Exact fraction of your estate still loading vulnerable `tcnative`

Why this verdict

  • Requires APR/native, not plain Tomcat: Tomcat's own docs say BIO/NIO use JSSE while APR/native uses OpenSSL; that sharply cuts the exposed population from the plugin's blanket 7.0.x < 7.0.60 claim
  • Requires on-path attacker: FREAK exploitation assumes a man-in-the-middle position, which implies hostile network control rather than direct unauthenticated internet exploitation
  • Impact is session compromise, not host compromise: the practical win is decrypting or tampering with an intercepted TLS session; there is no Tomcat code-execution chain here
  • Detection is version-only: Nessus explicitly says it relied on self-reported version and did not exploit or validate the OpenSSL path, which means false-positive volume can be high in large fleets

Why not higher?

A higher rating would make sense for a broadly reachable server-side bug with direct host impact, but this isn't that. The attack chain narrows hard at two points: most Tomcat installs are JSSE-backed, and FREAK still needs a network-adjacent MitM position even when APR/native is present.

Why not lower?

It isn't IGNORE because some older internet-facing Tomcat deployments really did run APR/native with vulnerable OpenSSL, and the plugin's CVE bundle includes more than a cosmetic cipher finding. If you confirm tcnative plus exposed TLS plus weak ciphers, there is still a real, attacker-usable weakness to clean up.

05 · Compensating Control

What to do — in priority order.

  1. Disable export-grade and legacy SSL ciphers — Remove RSA_EXPORT, SSLv2, and SSLv3 from any TLS policy on Tomcat or the upstream reverse proxy. For a LOW verdict there is no mitigation SLA under noisgate; handle this in normal backlog hygiene, but do it first on any internet-facing legacy node you confirm is using APR/native.
  2. Prefer JSSE or terminate TLS upstream — If APR/native is not a hard requirement, move TLS off the OpenSSL-backed connector path or terminate HTTPS on a modern load balancer / proxy. For LOW, there is no mitigation SLA; use your next routine change window.
  3. Inventory tcnative explicitly — Do not treat every Tomcat < 7.0.60 hit as real. Build a targeted inventory of hosts loading libtcnative-1 / tcnative-1.dll, because only those deserve deeper validation. For LOW, there is no mitigation SLA; this is a validation task to collapse scanner noise.
What doesn't work
  • Upgrading Tomcat alone on Linux/Unix without checking the linked OpenSSL or distro backport status; the risk lives in the crypto stack, not just the servlet container version string
  • Relying on EDR to catch the downgrade; a MitM TLS negotiation problem often leaves little or nothing useful on the Tomcat host
  • Assuming internal-only exposure makes it irrelevant; if clients traverse untrusted Wi-Fi, proxies, or hostile network segments, MitM risk can still exist
06 · Verification

Crowdsourced verification payload.

Run this on the target Tomcat host with python3 check_tomcat_83526.py /opt/tomcat or py check_tomcat_83526.py C:\Tomcat7. It needs read access to the Tomcat install tree; no admin rights are required unless your Tomcat files are restricted. The script checks Tomcat version, server.xml, APR/native indicators, native library presence, and the local openssl version command when available.

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
# check_tomcat_83526.py
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN

import os
import re
import sys
import zipfile
import subprocess
import platform
from pathlib import Path

PATCHED = 0
VULNERABLE = 1
UNKNOWN = 2


def read_text(path):
    try:
        return Path(path).read_text(encoding='utf-8', errors='ignore')
    except Exception:
        return ''


def parse_version_tuple(v):
    nums = re.findall(r'\d+', v or '')
    return tuple(int(x) for x in nums[:4]) if nums else tuple()


def version_lt(a, b):
    ta = parse_version_tuple(a)
    tb = parse_version_tuple(b)
    if not ta or not tb:
        return None
    la = list(ta) + [0] * (len(tb) - len(ta))
    lb = list(tb) + [0] * (len(ta) - len(tb))
    return tuple(la) < tuple(lb)


def get_tomcat_version(tomcat_home):
    candidates = [
        Path(tomcat_home) / 'lib' / 'catalina.jar',
        Path(tomcat_home) / 'server' / 'lib' / 'catalina.jar',
    ]
    for jar in candidates:
        if jar.exists():
            try:
                with zipfile.ZipFile(jar, 'r') as zf:
                    data = zf.read('META-INF/MANIFEST.MF').decode('utf-8', errors='ignore')
                    m = re.search(r'Implementation-Version:\s*([^\r\n]+)', data)
                    if m:
                        return m.group(1).strip()
            except Exception:
                pass
    for txt in ['RELEASE-NOTES', 'RUNNING.txt', 'NOTICE']:
        data = read_text(Path(tomcat_home) / txt)
        m = re.search(r'Apache Tomcat(?:/|\s+)Version\s*[:\-]?\s*([0-9][0-9.]+)', data, re.I)
        if m:
            return m.group(1)
        m = re.search(r'Apache Tomcat/?\s*([0-9][0-9.]+)', data, re.I)
        if m:
            return m.group(1)
    return None


def get_server_xml(tomcat_home):
    return read_text(Path(tomcat_home) / 'conf' / 'server.xml')


def apr_indicators(server_xml):
    indicators = []
    pats = [
        r'AprLifecycleListener',
        r'Http11AprProtocol',
        r'AjpAprProtocol',
        r'SSLEngine\s*=\s*"on"',
        r'certificateFile\s*=\s*"',
        r'certificateKeyFile\s*=\s*"',
    ]
    for p in pats:
        if re.search(p, server_xml, re.I):
            indicators.append(p)
    return indicators


def find_native_libs(tomcat_home):
    names = {'tcnative-1.dll', 'libtcnative-1.so', 'libtcnative-1.jnilib', 'libtcnative-1.dylib'}
    found = []
    for root, dirs, files in os.walk(tomcat_home):
        for f in files:
            if f.lower() in {n.lower() for n in names}:
                found.append(str(Path(root) / f))
    return found


def get_openssl_version():
    try:
        p = subprocess.run(['openssl', 'version'], capture_output=True, text=True, timeout=5)
        if p.returncode == 0:
            out = (p.stdout or p.stderr).strip()
            m = re.search(r'OpenSSL\s+([0-9a-zA-Z.]+)', out)
            return m.group(1) if m else out
    except Exception:
        pass
    return None


def openssl_is_vulnerable(v):
    if not v:
        return None
    if re.match(r'^0\.9\.8', v):
        return version_lt(v, '0.9.8zd')
    if re.match(r'^1\.0\.0', v):
        return version_lt(v, '1.0.0p')
    if re.match(r'^1\.0\.1', v):
        return version_lt(v, '1.0.1k')
    return False


def main():
    if len(sys.argv) != 2:
        print('UNKNOWN - usage: check_tomcat_83526.py <TOMCAT_HOME>')
        sys.exit(UNKNOWN)

    tomcat_home = sys.argv[1]
    if not Path(tomcat_home).exists():
        print('UNKNOWN - TOMCAT_HOME not found')
        sys.exit(UNKNOWN)

    tomcat_ver = get_tomcat_version(tomcat_home)
    server_xml = get_server_xml(tomcat_home)
    apr_hits = apr_indicators(server_xml)
    native_libs = find_native_libs(tomcat_home)
    openssl_ver = get_openssl_version()
    system_name = platform.system().lower()

    apr_in_use_likely = bool(apr_hits or native_libs)

    details = {
        'tomcat_version': tomcat_ver,
        'apr_indicators': apr_hits,
        'native_libs': native_libs,
        'openssl_version': openssl_ver,
        'platform': system_name,
    }

    # If APR/native is not present, this specific OpenSSL-driven finding is usually not real.
    if not apr_in_use_likely:
        print(f"PATCHED - no APR/native indicators found; likely JSSE-backed Tomcat. Details={details}")
        sys.exit(PATCHED)

    # If APR/native is present, inspect OpenSSL version when possible.
    if openssl_ver:
        vuln = openssl_is_vulnerable(openssl_ver)
        if vuln is True:
            print(f"VULNERABLE - APR/native present and OpenSSL appears vulnerable ({openssl_ver}). Details={details}")
            sys.exit(VULNERABLE)
        if vuln is False:
            print(f"PATCHED - APR/native present but OpenSSL appears fixed ({openssl_ver}). Details={details}")
            sys.exit(PATCHED)

    # Windows bundles before Tomcat 7.0.60 are especially suspicious because old tcnative binaries shipped with older OpenSSL.
    if system_name.startswith('win') and tomcat_ver:
        older = version_lt(tomcat_ver, '7.0.60')
        if older is True and native_libs:
            print(f"VULNERABLE - Windows Tomcat < 7.0.60 with bundled/native tcnative present; verify OpenSSL immediately. Details={details}")
            sys.exit(VULNERABLE)
        if older is False:
            print(f"PATCHED - Tomcat >= 7.0.60 and native present, but OpenSSL version could not be read. Details={details}")
            sys.exit(PATCHED)

    print(f"UNKNOWN - APR/native indicators found but OpenSSL version could not be confirmed. Details={details}")
    sys.exit(UNKNOWN)


if __name__ == '__main__':
    main()
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning, do not mass-escalate every 83526 hit. First, validate which Tomcat 7 nodes actually load tcnative / APR and expose TLS from Tomcat instead of a proxy; that is the real cut line. Because this is a LOW verdict, there is no noisgate mitigation SLA and no noisgate remediation SLA beyond normal backlog hygiene, so collapse false positives, fix or retire confirmed APR/native legacy nodes in routine change windows, and only fast-track any internet-facing host you confirm still allows export-grade TLS.

Sources

  1. Tenable Nessus Plugin 83526
  2. Tenable CVE-2015-0204
  3. Apache Tomcat 7 HTTP Connector Reference
  4. Apache Tomcat Native 1.1 Changelog
  5. Apache Tomcat 7 Changelog
  6. NVD CVE-2015-0204
  7. Red Hat FREAK Article
  8. Shadowserver SSL FREAK Report
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.