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 0afbb74417b065412e11c99432b7d5a0fc02817c
Author: Robert Lazarski <[email protected]>
AuthorDate: Mon May 18 07:46:39 2026 -1000

    Fix SSRF bypass via relative path + remote base URI, harden WSDL locators
    
    Gemini review found that the SSRF check on raw schemaLocation/importLocation
    can be bypassed when a relative path resolves to a remote URL via the base
    URI (e.g., relative "evil.xsd" + base "http://attacker/wsdl/"; = remote 
fetch).
    
    Fixes:
    1. WSDLToAxisServiceBuilder restrictive resolver: resolve loc against base
       before checking scheme.
    2. WarFileBasedURIResolver: resolve schemaLocation against baseUri before
       the absolute/remote check (AARFileBasedURIResolver already resolves 
first).
    3. AARBasedWSDLLocator: block remote URLs in getImportInputSource() for
       <wsdl:import> targets (was only patched for <xsd:import>).
    4. WarBasedWSDLLocator: same fix, check resolved URI not raw importLocation.
    5. URIResolverTest: add relative-path-with-remote-base bypass test.
    
    404 kernel tests pass.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
---
 .../deployment/resolver/AARBasedWSDLLocator.java   | 13 +++++++--
 .../deployment/resolver/WarBasedWSDLLocator.java   | 14 +++++++--
 .../resolver/WarFileBasedURIResolver.java          | 33 +++++++++++++---------
 .../description/WSDLToAxisServiceBuilder.java      | 21 ++++++++++----
 .../apache/axis2/deployment/URIResolverTest.java   | 16 +++++++++++
 5 files changed, 73 insertions(+), 24 deletions(-)

diff --git 
a/modules/kernel/src/org/apache/axis2/deployment/resolver/AARBasedWSDLLocator.java
 
b/modules/kernel/src/org/apache/axis2/deployment/resolver/AARBasedWSDLLocator.java
index 7177075972..c3e4b367ad 100644
--- 
a/modules/kernel/src/org/apache/axis2/deployment/resolver/AARBasedWSDLLocator.java
+++ 
b/modules/kernel/src/org/apache/axis2/deployment/resolver/AARBasedWSDLLocator.java
@@ -70,8 +70,17 @@ public class AARBasedWSDLLocator extends DefaultURIResolver 
implements WSDLLocat
      */
     public InputSource getImportInputSource(String parentLocation, String 
importLocation) {
         lastImportLocation = 
URI.create(parentLocation).resolve(importLocation);
-
-        if (isAbsolute(lastImportLocation.toString())) {
+        String loc = lastImportLocation.toString();
+
+        if (isAbsolute(loc)) {
+            // Block remote URLs to prevent SSRF in WSDL imports
+            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)) {
+                throw new RuntimeException(
+                        "Remote WSDL import blocked: " + loc);
+            }
             return super.resolveEntity(
                     null, importLocation, parentLocation);
         } else {
diff --git 
a/modules/kernel/src/org/apache/axis2/deployment/resolver/WarBasedWSDLLocator.java
 
b/modules/kernel/src/org/apache/axis2/deployment/resolver/WarBasedWSDLLocator.java
index 4b8e5803bf..fcc860f6b4 100644
--- 
a/modules/kernel/src/org/apache/axis2/deployment/resolver/WarBasedWSDLLocator.java
+++ 
b/modules/kernel/src/org/apache/axis2/deployment/resolver/WarBasedWSDLLocator.java
@@ -57,13 +57,21 @@ public class WarBasedWSDLLocator extends DefaultURIResolver 
implements WSDLLocat
      */
     public InputSource getImportInputSource(String parentLocation, String 
importLocation) {
         lastImportLocation = 
URI.create(parentLocation).resolve(importLocation);
+        String loc = lastImportLocation.toString();
 
-        if (isAbsolute(importLocation)) {
+        if (isAbsolute(loc)) {
+            // Block remote URLs to prevent SSRF in WSDL imports
+            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)) {
+                throw new RuntimeException(
+                        "Remote WSDL import blocked: " + loc);
+            }
             return super.resolveEntity(
                     null, importLocation, parentLocation);
         } else {
-            String searchingStr = lastImportLocation.toString();
-            return new 
InputSource(classLoader.getResourceAsStream(searchingStr));
+            return new InputSource(classLoader.getResourceAsStream(loc));
         }
     }
 
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 d418b4b646..ec8fa2a79b 100644
--- 
a/modules/kernel/src/org/apache/axis2/deployment/resolver/WarFileBasedURIResolver.java
+++ 
b/modules/kernel/src/org/apache/axis2/deployment/resolver/WarFileBasedURIResolver.java
@@ -41,15 +41,25 @@ public class WarFileBasedURIResolver extends 
DefaultURIResolver {
             String targetNamespace,
             String schemaLocation,
             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);
+        // Resolve against base URI first to catch relative + remote base 
bypass
+        URI resolvedURI;
+        try {
+            resolvedURI = (baseUri != null)
+                    ? URI.create(baseUri).resolve(schemaLocation)
+                    : URI.create(schemaLocation);
+        } catch (IllegalArgumentException e) {
+            log.warn("Invalid URI syntax for schema location: " + 
schemaLocation);
+            return new InputSource(new java.io.ByteArrayInputStream(new 
byte[0]));
+        }
+        String resolved = resolvedURI.toString();
+
+        if (isAbsolute(resolved)) {
+            // Block remote URLs to prevent SSRF
+            if (resolved.regionMatches(true, 0, "http:", 0, 5)
+                    || resolved.regionMatches(true, 0, "https:", 0, 6)
+                    || resolved.regionMatches(true, 0, "ftp:", 0, 4)
+                    || resolved.regionMatches(true, 0, "jar:", 0, 4)) {
+                log.warn("Blocked remote schema resolution in WAR deployment: 
" + resolved);
                 return new InputSource(new java.io.ByteArrayInputStream(new 
byte[0]));
             }
             return super.resolveEntity(
@@ -60,10 +70,7 @@ public class WarFileBasedURIResolver extends 
DefaultURIResolver {
                 throw new RuntimeException(
                         "Unsupported schema location " + schemaLocation);
             }
-
-            URI lastImportLocation = 
URI.create(baseUri).resolve(schemaLocation);
-            String searchingStr = lastImportLocation.toString();
-            return new 
InputSource(classLoader.getResourceAsStream(searchingStr));
+            return new InputSource(classLoader.getResourceAsStream(resolved));
         }
     }
 }
diff --git 
a/modules/kernel/src/org/apache/axis2/description/WSDLToAxisServiceBuilder.java 
b/modules/kernel/src/org/apache/axis2/description/WSDLToAxisServiceBuilder.java
index 5fdfe4f697..b271b069ce 100644
--- 
a/modules/kernel/src/org/apache/axis2/description/WSDLToAxisServiceBuilder.java
+++ 
b/modules/kernel/src/org/apache/axis2/description/WSDLToAxisServiceBuilder.java
@@ -154,13 +154,22 @@ public abstract class WSDLToAxisServiceBuilder {
                             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))) 
{
+                        // Resolve against base URI before checking —
+                        // a relative loc with a remote base must be caught
+                        String resolved = loc;
+                        if (base != null && loc != null) {
+                            try {
+                                resolved = 
java.net.URI.create(base).resolve(loc).toString();
+                            } catch (IllegalArgumentException ignored) {
+                            }
+                        }
+                        if (resolved != null
+                                && (resolved.regionMatches(true, 0, "http:", 
0, 5)
+                                 || resolved.regionMatches(true, 0, "https:", 
0, 6)
+                                 || resolved.regionMatches(true, 0, "ftp:", 0, 
4)
+                                 || resolved.regionMatches(true, 0, "jar:", 0, 
4))) {
                             throw new RuntimeException(
-                                    "Remote schemaLocation blocked: " + loc
+                                    "Remote schemaLocation blocked: " + 
resolved
                                     + " (use setCustomResolver to opt in)");
                         }
                         return delegate.resolveEntity(ns, loc, base);
diff --git 
a/modules/kernel/test/org/apache/axis2/deployment/URIResolverTest.java 
b/modules/kernel/test/org/apache/axis2/deployment/URIResolverTest.java
index 92ef18d604..e74693dc2c 100644
--- a/modules/kernel/test/org/apache/axis2/deployment/URIResolverTest.java
+++ b/modules/kernel/test/org/apache/axis2/deployment/URIResolverTest.java
@@ -62,4 +62,20 @@ public class URIResolverTest extends TestCase {
         assertNull("AAR resolver must block remote https URLs (SSRF)",
                 inputSource.getSystemId());
     }
+
+    /**
+     * Verify that a relative schemaLocation with a remote baseUri is
+     * blocked — prevents the bypass where a relative path resolves to
+     * a remote URL via the base URI.
+     */
+    public void testRelativePathWithRemoteBaseBlocked() {
+        WarFileBasedURIResolver war = new WarFileBasedURIResolver(null);
+        InputSource inputSource = war.resolveEntity(null,
+                "evil.xsd",
+                "http://attacker.example.com/wsdl/";);
+        assertNotNull(inputSource);
+        // Resolved URI is http://attacker.example.com/wsdl/evil.xsd — must be 
blocked
+        assertNull("WAR resolver must block relative path resolving to remote 
URL",
+                inputSource.getSystemId());
+    }
 }

Reply via email to