CVE-2026-63317 Overview
CVE-2026-63317 is an arbitrary class instantiation vulnerability in Apache OpenNLP affecting versions before 2.5.10 and before 3.0.0-M5. The flaw resides in three code paths that call Class.forName() on attacker-influenced strings and invoke the no-arg constructor without validating the class name or its type. The most reachable path is model loading: GeneratorFactory parses the class attribute of generator elements inside XML feature generator descriptors embedded in model archives such as TokenNameFinder and POSTagger models. Exploitation is not drop-in remote code execution because it depends on a class with useful side effects in its static initializer or constructor being present on the classpath [CWE-470].
Critical Impact
An attacker who supplies a crafted OpenNLP model archive or untrusted format name can trigger loading and instantiation of arbitrary classpath classes, enabling code execution paths through side-effecting initializers such as JNDI lookups, outbound network calls, or filesystem access.
Affected Products
- Apache OpenNLP versions before 2.5.10
- Apache OpenNLP versions before 3.0.0-M5
- Applications embedding OpenNLP that load untrusted models or accept untrusted -format values
Discovery Timeline
- 2026-07-24 - CVE-2026-63317 published to NVD
- 2026-07-24 - Last updated in NVD database
Technical Details for CVE-2026-63317
Vulnerability Analysis
Apache OpenNLP performs unsafe reflection in three distinct locations, each of which loads a class by its fully-qualified name and instantiates it without type checks. The first path, GeneratorFactory, reads the class attribute from generator elements in an XML feature generator descriptor. These descriptors ship as artifacts inside model archives, so a crafted TokenNameFinder or POSTagger model directly controls the class name parsed during model loading.
The second path is StreamFactoryRegistry.getFactory(Class, String). When a format name is not registered, the method falls back to treating the name as a fully-qualified ObjectStreamFactory class name. Applications that expose the command-line -format parameter to external input make this path reachable. The third path is StringInterners, which instantiates the class named by the opennlp.interner.class system property. This property is normally deployer-controlled and is hardened as defense in depth.
Root Cause
The root cause is unsafe use of Class.forName() followed by a no-arg constructor invocation on strings sourced from XML artifacts, user-supplied parameters, or system properties. No package allowlist, no interface type check, and no signature verification is applied before class loading and static initializer execution.
Attack Vector
The primary attack vector is a crafted OpenNLP model archive delivered to an application that loads third-party models. When the model is opened, the embedded feature generator descriptor forces instantiation of any class on the classpath. A secondary vector applies to applications that pass untrusted user input to the OpenNLP command-line -format parameter. Successful exploitation requires a gadget class on the classpath whose static initializer or constructor performs JNDI lookups, network I/O, or file system operations.
Detection Methods for CVE-2026-63317
Indicators of Compromise
- Unexpected loading of Java classes outside the opennlp.* package hierarchy during model deserialization
- Outbound JNDI, LDAP, or RMI connections initiated by the JVM process shortly after model load operations
- Presence of OpenNLP model archives from untrusted sources containing custom class attributes in embedded XML feature generator descriptors
- Command-line invocations of OpenNLP tooling with -format values that resolve to fully-qualified class names
Detection Strategies
- Inspect model archives with archive tools and grep XML descriptors for class=" attributes that reference non-opennlp.* packages
- Enable JVM class loading audit logs (-verbose:class) on services that ingest OpenNLP models and alert on unusual class loads following model parsing
- Monitor for OpenNLP process trees spawning unexpected child processes or opening outbound sockets to external hosts
Monitoring Recommendations
- Baseline the set of classes normally loaded by production OpenNLP services and alert on deviations
- Log every model file ingested by OpenNLP-consuming applications along with its source and hash
- Track EPSS movement and vendor advisories on the Apache mailing list thread for updated guidance
How to Mitigate CVE-2026-63317
Immediate Actions Required
- Upgrade Apache OpenNLP to 2.5.10 or 3.0.0-M5 or later, where all three code paths route through ExtensionLoader.instantiateExtension(...) and consult a package-prefix allowlist before Class.forName()
- Restrict model archive sources to trusted publishers and verify archive integrity with checksums or signatures before loading
- Audit the classpath of OpenNLP-consuming applications for classes with side-effecting static initializers or constructors
- Do not expose the OpenNLP command-line -format parameter to untrusted input
Patch Information
Upgrade to Apache OpenNLP 2.5.10 or 3.0.0-M5. The fix centralizes reflection in ExtensionLoader.instantiateExtension(...), which enforces a package-prefix allowlist. Classes under the opennlp. prefix remain permitted by default. Deployments that load models referencing feature generator factories, object stream factories, or string interners outside opennlp.* must opt those packages in via ExtensionLoader.registerAllowedPackage(String) before the first model load, or by setting the OPENNLP_EXT_ALLOWED_PACKAGES system property to a comma-separated list of allowed package prefixes. See the Apache Mailing List Thread and the Openwall OSS-Security Discussion for full details.
Workarounds
- Source all model files and format names exclusively from trusted origins and validate provenance before loading
- Remove or shade unused libraries from the classpath to eliminate gadget classes with dangerous static initializers
- Wrap OpenNLP model loading in a Java SecurityManager policy or module system boundary that restricts reflective class loading to opennlp.*
- After upgrading, set the OPENNLP_EXT_ALLOWED_PACKAGES system property to the minimum required package prefixes for your deployment
# Configuration example: restrict OpenNLP extension loading to specific package prefixes
export OPENNLP_EXT_ALLOWED_PACKAGES="opennlp.,com.example.myapp.opennlp."
java -Dopennlp.ext.allowed.packages="$OPENNLP_EXT_ALLOWED_PACKAGES" \
-jar my-nlp-service.jar
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

