blob: 6b94acc16a50b476aa0b30748b9d01ee11190caa [file] [view]
# Security Threat Model — Apache Axis2/Java
## Project Description
Apache Axis2/Java is a SOAP and REST web services engine. It provides a
message-processing pipeline with pluggable transports (HTTP/HTTPS, JMS, TCP,
local), a module system for cross-cutting concerns (WS-Security via Rampart,
WS-Addressing), hot-deployment of service archives (AAR/MAR), and
multi-protocol serving (JSON-RPC, REST/OpenAPI, MCP) from a single service
deployment. It runs inside a Jakarta Servlet container (Tomcat, Jetty,
WildFly) or embedded via Spring Boot.
## Roles and Trust Levels
| Role | Trust Level | Description |
|------|-------------|-------------|
| **Server Administrator** | Fully trusted | Configures `axis2.xml`, deploys/removes modules and services, controls the servlet container. Has filesystem and JVM-level access. |
| **Service Deployer** | Trusted | Drops AAR archives into `WEB-INF/services/`. May be the same person as the administrator, or a CI pipeline. |
| **Module Developer** | Trusted | Builds and deploys MAR module archives that add handlers to the processing pipeline. Code executes with full JVM privileges. |
| **Authenticated Client** | Partially trusted | A remote caller whose identity has been verified by the servlet container, a servlet filter, or a WS-Security module (Rampart). Authorized actions depend on the application. |
| **Anonymous Client** | Untrusted | A remote caller with no credentials. Can reach any endpoint exposed by the HTTP transport. All input is hostile. |
## Security Boundaries
### What IS a security issue
- **Remote Code Execution (RCE)** via the Axis2 framework itself — not
through user-written service logic.
- **XML External Entity (XXE) injection** — the framework's XML parsers
resolve external entities or allow DOCTYPE declarations from untrusted
input, enabling file read, SSRF, or denial of service.
- **Server-Side Request Forgery (SSRF)** — an attacker causes the server
to make requests to arbitrary internal or external hosts through framework
features such as WSDL/XSD import resolution, endpoint references, or
transport senders.
- **Deserialization of untrusted data** — framework-level Java object
deserialization that can be triggered by remote input without a class
whitelist. This was historically the most severe class of vulnerability
in Axis2 (see CVE history below).
- **Denial of Service via parser abuse** — billion-laughs XML bombs, deeply
nested JSON, or other input that causes unbounded memory or CPU
consumption inside framework-level parsers.
- **Authentication or authorization bypass** — a flaw in the handler/phase
pipeline that allows a message to skip an engaged security module.
- **Information disclosure of server internals** — stack traces, class
names, or configuration details leaked to unauthenticated callers through
fault messages or metadata endpoints when exposure has been disabled.
- **Path traversal** — a crafted service name, URI component, or WSDL
import location that allows reading or writing files outside expected
directories.
- **Multipart/file upload abuse** — unbounded file counts or sizes via
multipart form data that exhaust server resources.
### What is NOT a security issue
- **Vulnerabilities in user-written services.** SQL injection, broken
access control, or insecure business logic in a deployed service are the
service author's responsibility.
- **Missing authentication on endpoints.** Axis2 does not ship built-in
authentication. Securing endpoints is the responsibility of the servlet
container, servlet filters, or engaged security modules (Rampart).
- **Hot-deployment with weak filesystem permissions.** If an attacker has
write access to `WEB-INF/services/` or `WEB-INF/modules/`, they can
deploy arbitrary code. This is an OS/container configuration issue.
- **Service enumeration via `/services/` listing.** When
`exposeServiceMetadata` is `true` (the default), service names are
visible. This is documented behavior controllable via `axis2.xml`.
- **Denial of service at the network level.** SYN floods, slowloris, or
transport-layer attacks are mitigated by the servlet container, not Axis2.
- **Vulnerabilities *within* optional, external modules.** For example,
a flaw in Rampart's cryptographic implementation would be handled by
the Rampart project. However, a flaw in Axis2's handler pipeline that
allows the Rampart module to be bypassed *is* a vulnerability in Axis2.
## Architecture and Attack Surface
### Message Processing Pipeline
```
Remote Client (untrusted input)
|
v
Servlet Container (TLS termination, optional authentication)
|
v
AxisServlet / HTTPWorker <-- HTTP entry point
|
v
MessageContext created <-- request metadata captured
|
v
Transport-In Phase <-- transport-level handlers
|
v
Dispatchers <-- route to service/operation
(URI, SOAPAction, WS-Addressing, JSON method, HTTP location)
|
v
Handler Phases <-- global + per-service handlers
(security modules like Rampart execute here)
|
v
Message Builder <-- deserialize body
(SOAP, XML, JSON, MTOM, multipart/form-data)
|
v
MessageReceiver <-- invoke service method
|
v
Response Phases + Transport-Out <-- serialize response, send
```
### URL Patterns
Axis2 exposes the following URL patterns from the servlet mapping:
| Pattern | Purpose | Trust Requirement |
|---------|---------|-------------------|
| `/services/{ServiceName}` | JSON-RPC and SOAP service invocation | Application-defined |
| `/services/{ServiceName}/{Operation}` | REST-style per-operation invocation | Application-defined |
| `/services/{ServiceName}?wsdl` | WSDL metadata retrieval | Anonymous (if `exposeServiceMetadata=true`) |
| `/services/{ServiceName}?xsd` | XML Schema retrieval | Anonymous (if `exposeServiceMetadata=true`) |
| `/services/` | Service listing | Anonymous (if `exposeServiceMetadata=true`) |
| `/services/{ServiceName}/{name}.xsd` or `.wsdl` | Packaged metadata by file name | Anonymous (if `exposeServiceMetadata=true`) |
| `/openapi.json` | OpenAPI 3.0 schema (if OpenAPI module engaged) | Anonymous; per-service `exposeServiceMetadata` respected |
| `/swagger-ui` | Swagger UI (if OpenAPI module engaged) | Anonymous; per-service `exposeServiceMetadata` respected |
| `/openapi-mcp.json` | MCP tool catalog (if OpenAPI module engaged) | Anonymous; per-service `exposeServiceMetadata` respected |
### Attack Surface by Component
| Component | Threats | Mitigations |
|-----------|---------|-------------|
| **XML parsers** (AXIOM/StAX, DocumentBuilderFactory) | XXE, billion laughs, entity expansion DoS | DOCTYPE disallowed; external entities disabled; `DefaultEntityResolver` returns empty source |
| **WSDL/XSD import resolution** (wsdl4j, xmlschema-core) | XXE in imported documents; SSRF via `file://`/`gopher://` schemes | `SecureWSDLLocator` pre-validates with hardened SAX parser; protocol whitelist (HTTP/HTTPS only); size limit (10MB default); connect/read timeouts; relative-path SSRF bypass blocked |
| **JSON parser** (Gson) | Deep nesting stack exhaustion, large payload DoS | Fuzz-tested (1.7M+ iterations); Gson nesting limits |
| **JSON-RPC dispatch** | Method name injection; unexpected operation invocation | Method names validated against deployed operations; unknown methods return fault |
| **Multipart/file upload** (commons-fileupload2) | Unbounded file count DoS (CVE-2023-24998 pattern); unbounded body size; temp-file accumulation | commons-fileupload2 enforces the file count limit; `multipartMaxRequestSize` / `multipartMaxFileSize` bound the body; temp files are deleted immediately for form fields and tracked to collection for file parts |
| **Form-urlencoded builder** | Unbounded body read into an in-memory map | `formUrlEncodedMaxRequestSize` bounds the read; the stream fails rather than truncating |
| **Service dispatchers** | Routing to unintended service; header spoofing | Dispatchers validate service existence; unknown services return fault |
| **Hot-deployment** (DeploymentEngine) | Malicious AAR/MAR deploys arbitrary code | Trust boundary is filesystem access; no signature verification (admin operation) |
| **Context externalization** (SafeObjectInputStream) | Java deserialization gadget chains | Whitelist-based `SafeObjectInputStream`; restricted to known Axis2 context classes |
| **Metadata endpoints** (`?wsdl`, `?xsd`, `/services/`, `.xsd`/`.wsdl` by name, OpenAPI/MCP) | Service enumeration, schema disclosure | `exposeServiceMetadata` enforced uniformly across the servlet and standalone HTTP paths and the OpenAPI/MCP generators |
| **WS-Addressing response endpoints** (`wsa:ReplyTo`, `wsa:FaultTo`) | SSRF: an inbound header names the destination of a server-initiated send | Non-anonymous response endpoints refused by default (`allowNonAnonymousResponseEndpoints`); when enabled, scheme restricted to HTTPS, destination screened at both the header-parsing and transport-selection layers, and redirects not followed |
| **OpenAPI / Swagger UI surface** | Reflected XSS from request-controlled values; Host reflected into published URLs | Host validated, values encoded for their output context, CSP with a per-response script nonce; the published `servers[].url` is relative unless `openapi.serverBaseUrl` pins it |
| **MTOM/attachment handling** | Large attachment DoS, temp file exhaustion | Streaming processing; `TempFileManager` cleanup |
| **`?fields=` query parameter** (field selection, if enabled) | Reflection-based field filtering on response objects | Field names validated against declared response type; no dynamic class loading |
### Transports
| Transport | Security Notes |
|-----------|----------------|
| HTTP/HTTPS | TLS handled by servlet container. No framework-level auth. Primary production transport. |
| Local (in-JVM) | No network exposure. JVM-level isolation only. |
| JMS | Authentication delegated to JMS broker. |
| TCP | Raw sockets. No encryption or authentication. Trusted networks only. |
| UDP | No encryption, no authentication, no reliability. Trusted networks only. |
| Mail | Depends on mail server authentication. |
## CVE History and Lessons Learned
Axis2's CVE history concentrates in three categories. The scan should
weight these areas accordingly.
### 1. Deserialization of Untrusted Data (most severe)
**Clustering module (removed):**
A previous version of Axis2 included a clustering module for multi-node
coordination using Apache Tribes. This module exposed a network listener
that deserialized Java objects from untrusted network streams without
validation, enabling Remote Code Execution (RCE) via standard
deserialization gadget chains. This affected all releases through 2.0.0
on Apache Tomcat, but only when the Tribes-based clustering feature was
manually enabled (it was off by default). Assigned
[CVE-2026-66713](https://www.cve.org/CVERecord?id=CVE-2026-66713) and
resolved by complete removal of the clustering module in 40+ files
([AXIS2-6097](https://issues.apache.org/jira/browse/AXIS2-6097)) in
release 2.0.1.
**Lesson:** Any `ObjectInputStream.readObject()` on network input is a
critical-severity finding. The remaining use of Java serialization in
Axis2 is `SafeObjectInputStream` for context externalization, which uses
a class whitelist.
### 2. XML Parsing (XXE/SSRF)
**CVE-2010-1632:** DTD/XXE in MTOMBuilder flow. Fixed by strictly
forbidding DOCTYPE declarations in SOAP and XML requests.
**WSDL import parsing:** wsdl4j 1.6.3 creates its own
`DocumentBuilderFactory` without XXE hardening. Axis2 mitigates this
with `SecureWSDLLocator` (pre-validates imported documents with a
hardened SAX parser, rejects DOCTYPE, protocol-whitelists to HTTP/HTTPS,
enforces size limits and timeouts) and hardened URI resolvers for
xmlschema-core imports.
**Lesson:** Third-party XML libraries (wsdl4j, xmlschema-core) create
their own parser factories that bypass framework-level hardening. Every
XML parsing path — including transitive ones through dependency
libraries — must be audited.
### 3. Dependency Vulnerabilities
| CVE | Dependency | Issue | Resolution |
|-----|-----------|-------|------------|
| CVE-2010-3981 | Admin console | CSRF/XSS | Fixed in 1.7.3 |
| CVE-2012-6153, CVE-2014-3577 | Apache HttpClient | Various | Updated dependency in 1.7.4 |
| CVE-2016-1000031 | commons-fileupload | RCE via DiskFileItem | Updated dependency in 1.7.6 |
| CVE-2023-24998 | commons-fileupload 1.x | Unbounded file count DoS | Migrated to commons-fileupload2 in 2.0.0 |
**Lesson:** Dependency-level CVEs are the most frequent class. The
migration from `commons-fileupload` 1.x to `commons-fileupload2` in
2.0.0 was specifically driven by CVE-2023-24998.
## Existing Security Hardening
1. **XML parsing:** All `DocumentBuilderFactory` and `SAXParserFactory`
instances created by the framework disable DTDs and external entities
(`XMLUtils.java`, `SecureWSDLLocator.java`, `DefaultEntityResolver.java`).
2. **WSDL import security:** `SecureWSDLLocator` pre-parses imported
documents before passing them to wsdl4j. Protocol-restricted to
HTTP/HTTPS. Size-limited. Timeout-protected. Relative-path SSRF
bypass patched.
3. **Schema import security:** URI resolvers for AAR and WAR deployments
block HTTP/HTTPS/FTP/JAR/file scheme resolution to prevent SSRF via
xmlschema-core's `DefaultURIResolver`.
4. **Deserialization whitelist:** `SafeObjectInputStream` restricts Java
object deserialization to known Axis2 context classes.
5. **Clustering removed:** The entire clustering module (Tribes-based
inter-node communication with unvalidated deserialization) has been
removed from the codebase.
6. **File upload limits:** Migration to commons-fileupload2 enforces
file count limits, preventing CVE-2023-24998-style DoS.
7. **Fault detail suppression:** `sendStacktraceDetailsWithFaults`
defaults to `false`.
8. **Fuzz testing:** Jazzer-based fuzzers cover XML, JSON, HTTP header,
and URL parsers. 45M+ iterations with zero crashes or security
findings. See `src/site/xdoc/docs/OSS-FUZZ.md`. Axis2/C has an
active OSS-Fuzz integration.
9. **WS-Addressing response endpoints (2.0.2):** A non-anonymous
`wsa:ReplyTo` or `wsa:FaultTo` makes the server open a connection to an
address the caller chose. Unless WS-Security is engaged to bind that
endpoint reference to a trusted issuer, the WS-Addressing specification
leaves it to the receiver to decide whether to honour it, so Axis2 now
declines by default. `allowNonAnonymousResponseEndpoints` is `false`;
replies and faults travel back down the inbound connection only. Apache
CXF made the same choice in
`org.apache.cxf.ws.addressing.decoupled.enabled`.
Deployments that genuinely use decoupled responses — the separate-listener
"Dual" clients, or a third-party callback endpoint — set it to `true`, and
should also set `httpFrontendHostUrl` so the generated reply address is the
real external URL rather than the local one. With the feature enabled:
- `allowedResponseEndpointSchemes` permits HTTPS only. Widen it to name a
transport actually used for replies.
- The destination is screened both where the inbound header is parsed and
where a server-side response acquires its transport, so the check cannot
be reached around by setting the endpoint reference another way.
- Link-local, wildcard and multicast destinations are always refused.
`blockPrivateNetworkResponseEndpoints` additionally refuses loopback and
private ranges; it is off by default because a callback inside the same
private network is how most decoupled deployments are wired.
- The address checks are address-family agnostic: a bracketed IPv6 literal
is classified, not treated as an unrecognised host, and the IPv4-mapped
form (`[::ffff:169.254.169.254]`) is refused as the address it reaches
rather than as a separate spelling. IPv6 unique-local (`fc00::/7`) is
covered explicitly, since `InetAddress.isSiteLocalAddress` answers only
for the deprecated `fec0::/10`.
- Redirects are not followed, so a reply endpoint cannot hand the sender a
destination the policy already refused.
- Name resolution is bounded (`responseEndpointResolveTimeoutMillis`) and
runs on a capped pool, so a slow resolver cannot tie up request threads.
Known limitation: the destination is resolved once to check it and again to
connect, so a hostile DNS server could answer differently the second time.
Closing that requires connecting to a pinned address, which the transport
does not currently support. Operators in cloud environments should pair
these settings with network egress controls.
10. **Request body ceilings (2.0.2):** The `multipart/form-data` and
`application/x-www-form-urlencoded` builders read the transport stream
directly, so a servlet container's post-size limit never sees the body.
`multipartMaxRequestSize` and `multipartMaxFileSize` (100 MB) and
`formUrlEncodedMaxRequestSize` (2 MB) bound them; `-1` restores the
previous unbounded behaviour, and either may be set per service.
Multipart temp files are now deleted rather than accumulating: form-field
parts as soon as their text is read, file parts once the item backing the
`DataHandler` is unreachable.
Both ceilings are enforced against bytes actually read, not against a
declared `Content-Length`, so a chunked request body is bounded on the same
terms as a declared one. This is worth stating because the reverse is the
easy mistake: a limit that screens the header before the read is no limit
at all for `Transfer-Encoding: chunked`, which declares no length. The
form-urlencoded builder wraps the stream in `BoundedInputStream`; the
multipart path relies on commons-fileupload2, which pairs its
`Content-Length` fast path with a streaming guard.
11. **OpenAPI and Swagger UI output (2.0.2):** Request-controlled values are
validated and encoded for the context they are written into, the served
page carries a Content-Security-Policy with a per-response script nonce,
and the published `servers[].url` is relative — resolved by the client
against wherever it fetched the document — rather than derived from the
request Host. `openapi.serverBaseUrl` pins an absolute URL where a
deployment needs one.
12. **Uniform metadata exposure (2.0.2):** `exposeServiceMetadata` is now
honoured by every anonymous metadata route: the `?wsdl`, `?wsdl2` and
`?xsd` queries as before, plus the `.xsd`/`.wsdl` file routes on both the
servlet and standalone HTTP paths, the named-WSDL route, and the
OpenAPI/Swagger/MCP generators. A service with exposure disabled is
skipped rather than refused, so it stays indistinguishable from one that
is not deployed.
## Reporting Security Issues
Report vulnerabilities to: **security@apache.org**
Follow the [Apache Security Policy](https://www.apache.org/security/).
All confirmed issues go through coordinated disclosure with CVE assignment.