Hyland Alfresco Share's dispatchResource opens with one line of authorization: if (!isAllowedResourcePath(path)). The path it tests is whatever Spring's URL handler mapping extracted from the /share/page/resource/** route. The file it ultimately opens is whatever Tomcat resolves on the disk. CVE-2026-26336 lives between those two strings.
Hyland's deny-list catches /../WEB-INF/web.xml. It does not catch /..;/WEB-INF/web.xml, because to the regex ..; is not ... To Tomcat, it is.
The gate is Pattern.matches() against three regexes in an XML file
isAllowedResourcePath lives in org.springframework.extensions.surf.mvc.ResourceController, the Surf-overridden Spring resource controller wired into every Alfresco Share deployment by the bean definition in spring-surf-mvc-context.xml. Its body is fifteen lines:
public boolean isAllowedResourcePath(String pathToCheck)
{
if (!pathToCheck.startsWith(FORWARD_SLASH))
{
pathToCheck = FORWARD_SLASH + pathToCheck;
}
for (Pattern pattern : this.webframeworkConfigElement.getResourcesDeniedPaths())
{
Matcher matcher = pattern.matcher(pathToCheck);
if (matcher.matches())
{
// this path is configured as denied
return false;
}
}
return true;
}
The patterns are loaded out of share-config.xml, the deployment-time configuration that ships in the Share WAR:
<deny-access-resource-paths>
<resource-path-pattern>^/WEB-INF/.*</resource-path-pattern>
<resource-path-pattern>.*/\.\./WEB-INF/.*</resource-path-pattern>
<resource-path-pattern>.*/classes/.*\.properties</resource-path-pattern>
</deny-access-resource-paths>
Three regular expressions. The first refuses paths that begin with /WEB-INF/. The second refuses paths that contain a literal .. traversal segment immediately followed by /WEB-INF/. The third refuses paths that resolve to a .properties file under any classes/ directory. The matcher is Pattern.matches(), not find(), so each regex is anchored to the entire input; the leading and trailing .* are doing the work the matcher's anchoring takes away.
Against direct traversal, this gate is correct. A request for /share/page/resource/../WEB-INF/web.xml arrives at dispatchResource with path = /../WEB-INF/web.xml. The second regex matches: .* (empty) + / + .. + /WEB-INF/ + web.xml. The handler returns 403.
Against ..;/, the gate is silent.
..; is .. to Tomcat. It is not .. to a regex.
Tomcat's URI parser implements RFC 3986 path segments and parameters. Within a single segment, anything after a ; is a path parameter, the same construct that lets ;jsessionid=... ride along with any URL. The parser keeps the segment name and discards the parameter when it goes to look up the resource on disk. The segment ..; is, to the resource resolver, ...
To Pattern.matches() against .*/\.\./WEB-INF/.*, it isn't. The regex requires the literal byte sequence .. followed immediately by /. The bytes the regex sees are ..;/. There is a semicolon between .. and /. The regex returns false. The gate returns true. The handler proceeds to Spring's super.dispatchResource(path, request, response), which calls getResourceAsStream against a path the file system resolver will normalize one segment at a time, treating ..; as a parent-directory step. The resource opens.
The PoC's mechanism is two lines:
BYPASS = "..;/"
BASE_PATH = "/share/page/resource/"
def read_file(base_url, filepath):
url = f"{base_url.rstrip('/')}{BASE_PATH}{BYPASS}{filepath}"
r = requests.get(url, verify=False, timeout=15)
return r.status_code, r.content
https://target/share/page/resource/..;/WEB-INF/web.xml round-trips to the bytes of web.xml with HTTP 200. No authentication. No session.
..;/ is not a Hyland discovery and not an Alfresco discovery. Orange Tsai presented it at Black Hat USA in August 2018, in Breaking Parser Logic! Take Your Path Normalization Off and Pop 0days Out. The technique has been used to bypass servlet-container ACLs, reach management consoles, and cross WAR boundaries on the same Tomcat for the seven-and-a-half years between that talk and the CVE date on this advisory. Every Java application security cheat sheet published since names it. Every Tomcat hardening guide names it.
The deny-list in share-config.xml was committed to the public Alfresco repository on 2021-03-10. Three regular expressions. None of them mention ;.
The 25.3.0 patch is the same shape as the regex it patched
Hyland's advisory names 25.3.0, 23.6.1, and 7.4.2.6 as the fixed releases across the three supported branches. The PoC author tested 25.3.0 and reports ..;/ still works against the patched build. Both statements are independently verifiable: the CVE record lists those versions as the fixed ones, and the public PoC succeeds on a 25.3.0 install.
The patch closes one specific spelling of .. and leaves another open.
The 25.3.0 source is not in the public Alfresco GitHub repository; the master branch ends at Share 7.0.0 from 2021. The patch we cannot read is by inference one of two things: another regex pattern in share-config.xml that catches some additional traversal form, or an explicit String.contains("..") in the controller that runs before the regex loop. Either implementation operates on the same byte sequence the existing regex operates on. Either one is bypassed by the same path parameter that bypassed the existing regex. The ; separator slips between any defense built on substring inspection of the URL because that defense runs before Tomcat strips the parameter.
The pattern is general. A security check inspects an input for a forbidden form. A downstream subsystem canonicalizes the same input into that forbidden form. The check sees the wrapped representation; the action sees the unwrapped one. Call this gate-before-canonicalize: URL decoding, path-parameter stripping, Unicode normalization, escape resolution, every layer the input passes through after the gate is a layer that can put the forbidden form back into it. Path-traversal regexes, SSRF allowlists run against URLs that get re-parsed by the HTTP client, prompt-injection filters run against text the model later renders. Same shape. The fix is to canonicalize before checking, never after.
Hyland's next advisory will ship another regex. The class will return.
The shopping list the bypass actually opens
The CVE record's CVSS vector is AV:N/AC:L/PR:N/UI:N/C:H/I:N/A:N. Confidentiality only; the gate the bypass defeats is read-only. The PoC's DEFAULT_TARGETS dictionary names the files the read primitive matters for:
DEFAULT_TARGETS = {
"WEB-INF/web.xml": "Servlet configuration",
"WEB-INF/classes/alfresco-global.properties": "Global properties (may contain DB/LDAP/SMTP creds)",
"WEB-INF/classes/alfresco-encrypted.properties": "Encrypted properties",
"WEB-INF/classes/alfresco/web-extension/share-config-custom.xml": "Share custom config",
"WEB-INF/classes/alfresco/share-global.properties": "Share global properties",
"WEB-INF/classes/alfresco/keystore/ssl.keystore": "SSL keystore (binary)",
"WEB-INF/classes/alfresco/keystore/ssl.truststore": "SSL truststore (binary)",
"WEB-INF/classes/alfresco/keystore/ssl-keystore-passwords.properties": "Keystore passwords",
"WEB-INF/classes/alfresco/keystore/ssl-truststore-passwords.properties": "Truststore passwords",
"META-INF/MANIFEST.MF": "Build info and version",
}
Read these in order. alfresco-global.properties carries db.username, db.password, db.url, dir.root, the LDAP bind DN and password, and any SMTP credential the operator configured. With those credentials and direct network reach to the database (typically present from the same network position that reached the Share endpoint), the entire repository content layer is readable, including signed documents and the audit trail. The keystore and the matching ssl-keystore-passwords.properties are mTLS material for the Solr communication channel; once both are read, the attacker can present as the Share node to its Solr partner and read the search index, which already holds extracted text from every document in the repository. MANIFEST.MF pins the build to an exact version so the next stage of an exploit chain isn't guessing.
The PoC's README also notes that double traversal, ..;/..;/alfresco/..., reaches the Alfresco WAR if it is co-deployed in the same Tomcat instance, which is the standard Hyland reference architecture. That extension is the cross-context Tomcat behavior from the same 2018 talk; Tomcat resolves segment-by-segment from the request context root, and a ..; step exits one webapp's deployment directory while a second ..; step enters the sibling's. Two semicolons walk from Share to Alfresco.
Hyland's case file
Hyland shipped a regex-blacklist defense for the Share resource controller no later than 2021-03-10 in the public repository. The bypass for that blacklist was demonstrated at Black Hat in August 2018. The CVE record dates the defect to February 2026. The five-year gap between the defense being deployed and the bypass being assigned a CVE is not a story about a novel technique. It is a story about a vendor who held a defense whose bypass was already in every introductory training deck.
The Share resource controller is a design-debt driver. Five years of patches have addressed individual spellings of ..; the regex-blacklist design itself, the choice to inspect URL strings rather than canonicalize them, holds the primitive across every patch. The 25.3.0 release adds another pattern. The ..;/ bypass survives. The release that closes ..;/ will, by the same construction, leave the next encoding open.
The vendor's advisory will be paraphrased by the next blog as "improper authorization." That phrase is the CWE label. The mechanism is that Hyland's resource controller checks the URL string before Tomcat finishes parsing it.
The patch closes one spelling of ... It does not close the class.
PoC: CEAarab/CVE-2026-26336-PoC