You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-commits@axis.apache.org by ro...@apache.org on 2026/05/19 14:06:52 UTC
(axis-axis2-java-core) 03/05: Harden schema import resolution against SSRF (CWE-918)
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 7ac84d8339ad80f8f7f7977cf0caaa28fc3b7b98
Author: Robert Lazarski <ro...@gmail.com>
AuthorDate: Mon May 18 07:35:24 2026 -1000
Harden schema import resolution against SSRF (CWE-918)
Companion fix to the XXE hardening. xmlschema-core's DefaultURIResolver
follows absolute schemaLocation URLs with no scheme or host restriction,
enabling blind SSRF from the Axis2 JVM. Three vectors addressed:
1. WSDLToAxisServiceBuilder.getXMLSchema(): when no custom resolver is
set, install a restrictive URIResolver that blocks http/https/ftp/jar/
file schemes on schemaLocation targets. Callers who need remote
resolution can supply their own resolver via setCustomResolver().
2. AARFileBasedURIResolver: block remote URLs when falling through to
super.resolveEntity() for absolute URIs. Return empty InputSource
instead of fetching.
3. WarFileBasedURIResolver: same fix as AAR resolver.
Updated URIResolverTest to verify remote URLs are blocked (was
previously asserting they were fetched — that was the SSRF).
403 kernel tests pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <no...@anthropic.com>
---
.../resolver/AARFileBasedURIResolver.java | 10 ++++++++
.../resolver/WarFileBasedURIResolver.java | 9 +++++++
.../description/WSDLToAxisServiceBuilder.java | 25 ++++++++++++++++++
.../apache/axis2/deployment/URIResolverTest.java | 30 +++++++++++++++++++---
4 files changed, 70 insertions(+), 4 deletions(-)
diff --git a/modules/kernel/src/org/apache/axis2/deployment/resolver/AARFileBasedURIResolver.java b/modules/kernel/src/org/apache/axis2/deployment/resolver/AARFileBasedURIResolver.java
index 661ea336cd..165ef7214e 100644
--- a/modules/kernel/src/org/apache/axis2/deployment/resolver/AARFileBasedURIResolver.java
+++ b/modules/kernel/src/org/apache/axis2/deployment/resolver/AARFileBasedURIResolver.java
@@ -58,6 +58,16 @@ public class AARFileBasedURIResolver extends DefaultURIResolver {
lastImportLocation = URI.create(baseUri).resolve(schemaLocation);
if (isAbsolute(lastImportLocation.toString())) {
+ // Block remote URLs to prevent SSRF. Only allow resolution
+ // of absolute URIs that are local file paths.
+ String loc = lastImportLocation.toString();
+ if (loc.regionMatches(true, 0, "http:", 0, 5)
+ || loc.regionMatches(true, 0, "https:", 0, 6)
+ || loc.regionMatches(true, 0, "ftp:", 0, 4)
+ || loc.regionMatches(true, 0, "jar:", 0, 4)) {
+ log.warn("Blocked remote schema resolution in AAR deployment: " + loc);
+ return new InputSource(new java.io.ByteArrayInputStream(new byte[0]));
+ }
return super.resolveEntity(
targetNamespace, schemaLocation, baseUri);
} else {
diff --git a/modules/kernel/src/org/apache/axis2/deployment/resolver/WarFileBasedURIResolver.java b/modules/kernel/src/org/apache/axis2/deployment/resolver/WarFileBasedURIResolver.java
index e0f6ff4cc6..d418b4b646 100644
--- a/modules/kernel/src/org/apache/axis2/deployment/resolver/WarFileBasedURIResolver.java
+++ b/modules/kernel/src/org/apache/axis2/deployment/resolver/WarFileBasedURIResolver.java
@@ -43,6 +43,15 @@ public class WarFileBasedURIResolver extends DefaultURIResolver {
String baseUri) {
//no issue with
if (isAbsolute(schemaLocation)) {
+ // Block remote URLs to prevent SSRF. Only allow resolution
+ // of absolute URIs that are local file paths.
+ if (schemaLocation.regionMatches(true, 0, "http:", 0, 5)
+ || schemaLocation.regionMatches(true, 0, "https:", 0, 6)
+ || schemaLocation.regionMatches(true, 0, "ftp:", 0, 4)
+ || schemaLocation.regionMatches(true, 0, "jar:", 0, 4)) {
+ log.warn("Blocked remote schema resolution in WAR deployment: " + schemaLocation);
+ return new InputSource(new java.io.ByteArrayInputStream(new byte[0]));
+ }
return super.resolveEntity(
targetNamespace, schemaLocation, baseUri);
} else {
diff --git a/modules/kernel/src/org/apache/axis2/description/WSDLToAxisServiceBuilder.java b/modules/kernel/src/org/apache/axis2/description/WSDLToAxisServiceBuilder.java
index 8cfb1fbbdf..5fdfe4f697 100644
--- a/modules/kernel/src/org/apache/axis2/description/WSDLToAxisServiceBuilder.java
+++ b/modules/kernel/src/org/apache/axis2/description/WSDLToAxisServiceBuilder.java
@@ -141,6 +141,31 @@ public abstract class WSDLToAxisServiceBuilder {
if (customResolver != null) {
schemaCollection.setSchemaResolver(customResolver);
+ } else {
+ // Install a restrictive resolver that blocks remote schema
+ // resolution (SSRF via absolute schemaLocation URLs). The
+ // default URIResolver in xmlschema-core follows any absolute
+ // URI including http://, https://, ftp://, and jar://.
+ // Local file:// and relative paths are allowed for co-packaged
+ // schemas in .aar/.war deployments.
+ schemaCollection.setSchemaResolver(
+ new org.apache.ws.commons.schema.resolver.URIResolver() {
+ private final org.apache.ws.commons.schema.resolver.DefaultURIResolver
+ delegate = new org.apache.ws.commons.schema.resolver.DefaultURIResolver();
+ public org.xml.sax.InputSource resolveEntity(
+ String ns, String loc, String base) {
+ if (loc != null
+ && (loc.regionMatches(true, 0, "http:", 0, 5)
+ || loc.regionMatches(true, 0, "https:", 0, 6)
+ || loc.regionMatches(true, 0, "ftp:", 0, 4)
+ || loc.regionMatches(true, 0, "jar:", 0, 4))) {
+ throw new RuntimeException(
+ "Remote schemaLocation blocked: " + loc
+ + " (use setCustomResolver to opt in)");
+ }
+ return delegate.resolveEntity(ns, loc, base);
+ }
+ });
}
return schemaCollection.read(element);
diff --git a/modules/kernel/test/org/apache/axis2/deployment/URIResolverTest.java b/modules/kernel/test/org/apache/axis2/deployment/URIResolverTest.java
index e4d6d2fbc9..92ef18d604 100644
--- a/modules/kernel/test/org/apache/axis2/deployment/URIResolverTest.java
+++ b/modules/kernel/test/org/apache/axis2/deployment/URIResolverTest.java
@@ -27,17 +27,39 @@ import org.xml.sax.InputSource;
public class URIResolverTest extends TestCase {
- public void testResolveEntity() {
+ /**
+ * Verify that remote http/https URLs are blocked by the SSRF
+ * hardening in AAR and WAR resolvers. The resolvers should return
+ * an empty InputSource instead of fetching the remote URL.
+ */
+ public void testRemoteUrlBlocked() {
AARFileBasedURIResolver aar = new AARFileBasedURIResolver(null);
- WarFileBasedURIResolver war = new WarFileBasedURIResolver(null);
InputSource inputSource = aar.resolveEntity(null,
"http://www.test.org/test.xsd",
"http://www.test.org/schema.xsd");
assertNotNull(inputSource);
- assertEquals(inputSource.getSystemId(), "http://www.test.org/test.xsd");
+ // Should return empty InputSource, not one with the remote URL
+ assertNull("AAR resolver must block remote http URLs (SSRF)",
+ inputSource.getSystemId());
+
+ WarFileBasedURIResolver war = new WarFileBasedURIResolver(null);
inputSource = war.resolveEntity(null, "http://www.test.org/test.xsd",
"http://www.test.org/schema.xsd");
assertNotNull(inputSource);
- assertEquals(inputSource.getSystemId(), "http://www.test.org/test.xsd");
+ assertNull("WAR resolver must block remote http URLs (SSRF)",
+ inputSource.getSystemId());
+ }
+
+ /**
+ * Verify that https URLs are also blocked.
+ */
+ public void testHttpsUrlBlocked() {
+ AARFileBasedURIResolver aar = new AARFileBasedURIResolver(null);
+ InputSource inputSource = aar.resolveEntity(null,
+ "https://www.test.org/test.xsd",
+ "https://www.test.org/schema.xsd");
+ assertNotNull(inputSource);
+ assertNull("AAR resolver must block remote https URLs (SSRF)",
+ inputSource.getSystemId());
}
}