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 <[email protected]>
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) <[email protected]>
---
 .../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());
     }
 }

Reply via email to