GHSA-VFP3-V2GW-7WFQ

Vulnerability from github – Published: 2026-08-25 16:13 – Updated: 2026-08-25 16:13
VLAI
Summary
Echo: Encoded slash (%2F) bypasses route-level protection and exposes static files
Details

Summary

Echo's router and static file handler disagree on URL path decoding. The router matches routes using the raw encoded path (preserving %2F as-is), while StaticDirectoryHandler unescapes %2F to / before resolving filesystem paths. This allows an attacker to bypass route-level access controls and read static files without authorization.

Details

Root cause 1 — router.go lines 798-802: The router uses req.URL.RawPath for route matching when useEscapedPathForRouting is false (the default). This means /admin%2Fsecret.txt is treated as a single path segment and does NOT match the /admin/* route pattern.

if !r.useEscapedPathForRouting && req.URL.RawPath != "" {
    path = req.URL.RawPath
}

Root cause 2 — echo.go lines 559-568: StaticDirectoryHandler calls url.PathUnescape() on the path parameter before opening files. This converts %2F back to /, resolving admin/secret.txt on disk.

if !disablePathUnescaping {
    tmpPath, err := url.PathUnescape(p)
    p = tmpPath
}
name := filepath.ToSlash(filepath.Clean(strings.TrimPrefix(p, "/")))

PoC (Screenshot)

Sample: image

403: image

Bypass with encoded slash: image

Impact

Unauthorized static file disclosure. Applications that protect route prefixes with authentication middleware while also serving static files from a broader root are vulnerable. An attacker only needs to encode the slash (/%2F) in the URL to bypass all route-level protection.

Common affected pattern:

adminGroup := e.Group("/admin", authMiddleware)
e.StaticFS("/", os.DirFS("public"))
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/labstack/echo/v5"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "5.2.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/labstack/echo/v4"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "4.15.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/labstack/echo"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "3.3.10"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-55677"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-08-25T16:13:29Z",
    "nvd_published_at": "2026-06-26T17:16:34Z",
    "severity": "HIGH"
  },
  "details": "### Summary\n\nEcho\u0027s router and static file handler disagree on URL path decoding. The router matches routes using the raw encoded path (preserving `%2F` as-is), while `StaticDirectoryHandler` unescapes `%2F` to `/` before resolving filesystem paths. This allows an attacker to bypass route-level access controls and read static files without authorization.\n\n### Details\n\n**Root cause 1 \u2014 `router.go` lines 798-802:**\nThe router uses `req.URL.RawPath` for route matching when `useEscapedPathForRouting` is false (the default). This means `/admin%2Fsecret.txt` is treated as a single path segment and does NOT match the `/admin/*` route pattern.\n\n```go\nif !r.useEscapedPathForRouting \u0026\u0026 req.URL.RawPath != \"\" {\n    path = req.URL.RawPath\n}\n```\n\n**Root cause 2 \u2014 `echo.go` lines 559-568:**\n`StaticDirectoryHandler` calls `url.PathUnescape()` on the path parameter before opening files. This converts `%2F` back to `/`, resolving `admin/secret.txt` on disk.\n\n```go\nif !disablePathUnescaping {\n    tmpPath, err := url.PathUnescape(p)\n    p = tmpPath\n}\nname := filepath.ToSlash(filepath.Clean(strings.TrimPrefix(p, \"/\")))\n```\n\n### PoC (Screenshot)\nSample:\n\u003cimg width=\"1291\" height=\"970\" alt=\"image\" src=\"https://github.com/user-attachments/assets/0bc58059-3e6d-4678-ab25-a5c79b006738\" /\u003e\n\n403:\n\u003cimg width=\"526\" height=\"194\" alt=\"image\" src=\"https://github.com/user-attachments/assets/2f55ffdd-87b2-4a1b-8a13-130ebad0f257\" /\u003e\n\nBypass with encoded slash:\n\u003cimg width=\"592\" height=\"203\" alt=\"image\" src=\"https://github.com/user-attachments/assets/1191cd39-ae8f-4d7e-8fb1-cb9cf31f484f\" /\u003e\n\n### Impact\n\nUnauthorized static file disclosure. Applications that protect route prefixes with authentication middleware while also serving static files from a broader root are vulnerable. An attacker only needs to encode the slash (`/` \u2192 `%2F`) in the URL to bypass all route-level protection.\n\nCommon affected pattern:\n```go\nadminGroup := e.Group(\"/admin\", authMiddleware)\ne.StaticFS(\"/\", os.DirFS(\"public\"))\n```",
  "id": "GHSA-vfp3-v2gw-7wfq",
  "modified": "2026-08-25T16:13:29Z",
  "published": "2026-08-25T16:13:29Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/labstack/echo/security/advisories/GHSA-vfp3-v2gw-7wfq"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-55677"
    },
    {
      "type": "WEB",
      "url": "https://github.com/labstack/echo/pull/3009"
    },
    {
      "type": "WEB",
      "url": "https://github.com/labstack/echo/pull/3011"
    },
    {
      "type": "WEB",
      "url": "https://github.com/labstack/echo/commit/8d1ae9d3360a71672418856d58753af25f2c3986"
    },
    {
      "type": "WEB",
      "url": "https://github.com/labstack/echo/commit/c3fa2a27ff92b2b8db360de614f999ef1da24725"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/labstack/echo"
    },
    {
      "type": "WEB",
      "url": "https://github.com/labstack/echo/releases/tag/v4.15.3"
    },
    {
      "type": "WEB",
      "url": "https://github.com/labstack/echo/releases/tag/v5.2.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Echo: Encoded slash (%2F) bypasses route-level protection and exposes static files"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…