This is an automated email from the ASF dual-hosted git repository. robertlazarski pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-core.git
commit b5071b4fb55896b135f9d74df01a8308a04d55db Author: Robert Lazarski <[email protected]> AuthorDate: Wed Sep 2 18:26:59 2026 -1000 Write up the 2.0.2 hardening for upgraders Collect the changed defaults in the release notes with what to set to restore the previous behaviour, and record content-based dispatch in the threat model. The existing service-dispatcher row claimed dispatchers only validate service existence, which understated what late binding allowed. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> --- SECURITY.md | 13 ++++++- src/site/markdown/release-notes/2.0.2.md | 67 ++++++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 6b94acc16a..7100641f27 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -136,7 +136,7 @@ Axis2 exposes the following URL patterns from the servlet mapping: | **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 | +| **Service dispatchers** | Routing to unintended service; header spoofing; a service chosen from message content after the Security phase has already run | Dispatchers validate service existence and unknown services return fault; selecting the service from the SOAP body namespace is off unless `allowContentBasedServiceDispatch` is set, so binding happens before the Security phase runs | | **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 | @@ -320,6 +320,17 @@ migration from `commons-fileupload` 1.x to `commons-fileupload2` in skipped rather than refused, so it stays indistinguishable from one that is not deployed. +13. **Content-based service dispatch (2.0.2):** The inflow phase order is + Transport, Addressing, Security, PreDispatch, Dispatch, and `DispatchPhase` + installs only the phases that follow it, so a service bound during Dispatch + is bound after the Security phase has run against no service and Security is + never revisited. Selecting a service from the namespace of the SOAP body's + first element therefore let a caller whose request URI named no service reach + a service whose engaged security modules had not run for it. + `allowContentBasedServiceDispatch` defaults to `false`. Dispatch by request + URI, SOAPAction and WS-Addressing binds the service before the Security phase + and is unaffected. + ## Reporting Security Issues Report vulnerabilities to: **[email protected]** diff --git a/src/site/markdown/release-notes/2.0.2.md b/src/site/markdown/release-notes/2.0.2.md index 9175c9ff8c..4e5a317b9c 100644 --- a/src/site/markdown/release-notes/2.0.2.md +++ b/src/site/markdown/release-notes/2.0.2.md @@ -1,4 +1,63 @@ -Apache Axis2 2.0.2 Release Notes --------------------------------- - -(Unreleased) +Apache Axis2 2.0.2 Release Notes +-------------------------------- + +(Unreleased) + +## Security Hardening + +Several defaults changed in this release. Each one closes a surface an +unauthenticated caller could reach, and each is listed here with what to set if a +deployment genuinely needs the previous behaviour. The full reasoning for each is +in `SECURITY.md`. + +- **No default admin console credentials.** The published `axis2-webapp` WAR and + the `axis2_default.xml` inside `axis2-kernel.jar` shipped `admin`/`axis2` as the + `/axis2-admin` login. That console can upload services, and so execute code. Both + now ship empty, which leaves the console disabled: the login rejects empty + credentials before comparing, so no request can authenticate until an operator + sets both `userName` and `password` in their own `axis2.xml`. Deployments that + relied on the default login must now set one explicitly. + +- **Service dispatch from the message body is opt-in.** The inflow order is + Transport, Addressing, **Security**, PreDispatch, **Dispatch**, so a service + selected during Dispatch is selected after the Security phase has already run — + against no service, because none was bound yet — and Security is not revisited. + A request whose URI names no service could therefore pick the service from the + namespace of the SOAP body's first element, reaching a service whose engaged + security modules never ran. `allowContentBasedServiceDispatch` now defaults to + `false`. Dispatch by request URI, SOAPAction and WS-Addressing is unaffected. + Set it to `true` only if services are genuinely addressed by body namespace, and + not alongside per-service security modules. + +- **Decoupled WS-Addressing responses are refused by default.** A non-anonymous + `wsa:ReplyTo` or `wsa:FaultTo` makes the server open a connection to an address + the caller chose. `allowNonAnonymousResponseEndpoints` now defaults to `false`; + replies and faults travel back down the inbound connection. Deployments that use + decoupled responses — 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. With the feature enabled, + `allowedResponseEndpointSchemes` permits HTTPS only, the destination is screened + at both the header-parsing and transport-selection layers, and redirects are not + followed. + +- **Request bodies are bounded.** 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 saw the body. + `multipartMaxRequestSize` and `multipartMaxFileSize` (100 MB) and + `formUrlEncodedMaxRequestSize` (2 MB) now bound them; `-1` restores the previous + unbounded behaviour, and either may be set per service. The ceilings are enforced + against bytes actually read, so a chunked body is bounded on the same terms as a + declared one. Multipart temporary files are deleted rather than accumulating. + +- **`exposeServiceMetadata` is honoured uniformly.** Every anonymous metadata route + now respects it: 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. + +- **OpenAPI and Swagger UI output.** 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 rather than derived from the request Host. + `openapi.serverBaseUrl` pins an absolute URL where a deployment needs one.
