KEVWire

Security intelligence, with context.

Response snapshot Oct 29, 2026, 02:31 UTC

Back to the wire
Permalink
VulnerabilityCVE-2026-118654

Echo static file middleware route protection bypass via encoded dot-dot traversal

Echo v5.2.0 contains a bypass of the fix for GHSA-vfp3-v2gw-7wfq. The fix rejects encoded path separators such as %2F and %5C before static file path unescaping, but two traversal forms still bypass route-level middleware protections for static files.

At a glance

Exploited
Not known
Severity
5.9 Medium (CVSS 3.1)
Chance of exploitation
Not estimated
Sources
1 source

What to do

GitHub lists first patched versions: github.com/labstack/echo/v5: 5.4.0; github.com/labstack/echo/v4: 4.16.0. Confirm the affected range and upgrade guidance in the exact advisory.

Read GitHub-reviewed advisory GHSA-3pmx-cf9f-34xr (opens a new tab)

What happened

Summary

Echo v5.2.0 contains a bypass of the fix for GHSA-vfp3-v2gw-7wfq. The fix rejects encoded path separators such as %2F and %5C before static file path unescaping, but two traversal forms still bypass route-level middleware protections for static files.

The primary bypass uses encoded dot-dot segments. A request such as /public/%2E%2E/admin/secret.txt passes the encoded-separator guard, is unescaped to public/../admin/secret.txt, then path.Clean resolves it to admin/secret.txt. If /admin/* is protected by middleware but the static filesystem is mounted at /, the protected file is returned through the public static route.

A second bypass exists when UseEscapedPathForMatching=true. In that mode, the router normalizes encoded separators before the static handler checks the wildcard. The handler receives a decoded wildcard with no % characters, so the encoded-separator guard does not run on the original encoded path.

Continue reading

Impact

An unauthenticated attacker can read files that an application intended to protect with route-level middleware, when those files are also reachable through a static filesystem mount after path normalization.

The high-severity variant works with the default router configuration and requires only encoded dot-dot path segments. The direct protected route returns 403, while the public static route returns the protected file content.

The UseEscapedPathForMatching=true variant is lower severity because it requires a non-default router configuration.

Affected versions

Tested vulnerable:

- github.com/labstack/echo/v5 v5.2.0 - Current master at 5786024ea4d85c01784796e8aa7aac53e007b39b

No patched version is currently known.

Policy and version checks

GitHub Private Vulnerability Reporting is enabled for labstack/echo. The repository has a root SECURITY.md and accepts security reports through GitHub Security Advisories.

The vulnerable code was revalidated on both current master and the latest release tag:

- Current master: 5786024ea4d85c01784796e8aa7aac53e007b39b - Latest release: v5.2.0, published June 14 2026 - Package: github.com/labstack/echo/v5

The same focused Go tests pass on the checked out v5.2.0 / master commit, proving the bypass remains present in the latest released version and latest main branch at the time of reporting.

Reproduction

The following application shape reproduces the high-severity bypass:

e := echo.New()

g := e.Group("/admin", func(next echo.HandlerFunc) echo.HandlerFunc {
 return func(c echo.Context) error {
 return echo.NewHTTPError(http.StatusForbidden)
 }
})
g.GET("/*", handler)

e.StaticFS("/", fsysWithAdminSecret)

Control request:

GET /admin/secret.txt

Observed result:

403 Forbidden

Bypass request:

GET /public/%2E%2E/admin/secret.txt

Observed result:

200 OK
TOP-SECRET

For the non-default router variant:

e := echo.New()
e.router = echo.NewRouter(echo.RouterConfig{
 UseEscapedPathForMatching: true,
})

g := e.Group("/admin", authMiddlewareReturning403)
g.GET("/*", handler)

e.StaticFS("/", fsysWithAdminSecret)

Bypass request:

GET /public%2F..%2Fadmin%2Fsecret.txt

Observed result:

200 OK
TOP-SECRET

Proof of concept evidence

I added focused tests against the current Echo codebase. The tests exercise both StaticDirectoryHandler and the static middleware path.

Command:

go test -run TestHostile -v ./...

Observed result:

=== RUN TestHostile_StaticDirectoryHandler_EncodedSeparatorsBlocked
--- PASS: TestHostile_StaticDirectoryHandler_EncodedSeparatorsBlocked (0.00s)
=== RUN TestHostile_StaticDirectoryHandler_EncodedDotDotBypass
--- PASS: TestHostile_StaticDirectoryHandler_EncodedDotDotBypass (0.00s)
=== RUN TestHostile_UseEscapedPathForMatching_Bypass
--- PASS: TestHostile_UseEscapedPathForMatching_Bypass (0.00s)
PASS
ok github.com/labstack/echo/v5 0.013s
=== RUN TestHostile_StaticMiddleware_EncodedSeparatorsBlocked
--- PASS: TestHostile_StaticMiddleware_EncodedSeparatorsBlocked (0.01s)
=== RUN TestHostile_StaticMiddleware_EncodedDotDotBypass
--- PASS: TestHostile_StaticMiddleware_EncodedDotDotBypass (0.00s)
=== RUN TestHostile_StaticMiddleware_DisablePathUnescaping
--- PASS: TestHostile_StaticMiddleware_DisablePathUnescaping (0.00s)
PASS
ok github.com/labstack/echo/v5/middleware 0.012s

The control tests also confirm that the new fix blocks encoded separators such as %2F, %5C, double-encoded slash values, null bytes, and overlong slash encodings.

Root cause

The fix for GHSA-vfp3 uses a denylist-style guard that checks for encoded path separators before unescaping the static wildcard. This blocks %2F and %5C, but does not block encoded traversal segments such as %2E%2E.

The vulnerable flow is:

1. The static route wildcard accepts public/%2E%2E/admin/secret.txt. 2. The encoded-separator guard sees no %2F or %5C and allows the request. 3. The handler unescapes the wildcard to public/../admin/secret.txt. 4. path.Clean resolves it to admin/secret.txt. 5. The file is served through the public static route instead of the protected /admin/* route.

For UseEscapedPathForMatching=true, the router decodes the path before the static handler sees the wildcard, so the handler cannot detect that encoded separators were used in the original request.

Remediation

Do not rely only on detecting encoded separators. Reject encoded traversal sequences before unescaping, and reject normalized wildcard values that cross route or static mount boundaries.

Possible fixes:

1. Extend the pre-unescape guard to reject encoded dot segments such as %2E and %2E%2E in path components. 2. After unescaping, reject any wildcard where cleaning changes the path in a way that removes . or .. components. 3. For UseEscapedPathForMatching=true, run the static-file guard against the original escaped request path before router normal

Affected package ranges reported by GitHub: github.com/labstack/echo/v5: < 5.4.0 github.com/labstack/echo/v4: < 4.16.0

Scores and how they were measured

CVSS base severity

5.9

Version 3.1As of

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N

Measurement source (opens a new tab)

How bad it is if exploited. Not a prediction of exploitation or proof you are exposed.

EPSS probability

Not available

A model's estimate of exploitation in the next 30 days, not certainty or your own risk.

Related technology

Sources

  1. Primary source

    GitHub-reviewed advisory GHSA-3pmx-cf9f-34xr (opens a new tab)

    The public advisory supplies the description, affected package/version ranges, and any listed CVSS metric. GitHub review is not local review.

    Published Checked

  2. Primary source

    GitHub public advisory API page (opens a new tab)

    The API page supplied GHSA-3pmx-cf9f-34xr, its actual identifiers, source dates, and structured metrics.

    Published Date not suppliedChecked

Cite this record

For factual claims, cite the primary sources above; cite KEVWire for its compilation, dates, and classifications.

APA

KEVWire. (2026, October 28). Echo static file middleware route protection bypass via encoded dot-dot traversal (CVE-2026-118654). https://kevwire.com/record/CVE-2026-118654

MLA

"Echo static file middleware route protection bypass via encoded dot-dot traversal (CVE-2026-118654)." KEVWire, 28 Oct. 2026, kevwire.com/record/CVE-2026-118654.

Chicago

KEVWire. "Echo static file middleware route protection bypass via encoded dot-dot traversal (CVE-2026-118654)." Last modified October 28, 2026. https://kevwire.com/record/CVE-2026-118654.

Evidence summary (plain text)

Echo static file middleware route protection bypass via encoded dot-dot traversal (Oct 28, 2026).
Echo v5.2.0 contains a bypass of the fix for GHSA-vfp3-v2gw-7wfq. The fix rejects encoded path separators such as %2F and %5C before static file path unescaping, but two traversal forms still bypass route-level middleware protections for static files.

The primary bypass uses encoded dot-dot segments. A request such as /public/%2E%2E/admin/secret.txt passes the encoded-separator guard, is unescaped to public/../admin/secret.txt, then path.Clean resolves it to admin/secret.txt.
CVSS 5.9 (version 3.1; evidence as of Oct 28, 2026; https://github.com/advisories/GHSA-3pmx-cf9f-34xr).
Sources:
GitHub-reviewed advisory GHSA-3pmx-cf9f-34xr: https://github.com/advisories/GHSA-3pmx-cf9f-34xr
GitHub public advisory API page: https://api.github.com/advisories?type=reviewed&per_page=100&sort=updated&direction=desc
Record ID: CVE-2026-118654.
Record origin: Ingested record.
AI evidence: Not assessed.
Known exploitation: Not assessed.
Zero-day status: Not assessed. KEV membership alone does not establish zero-day status.
About this data

This record was ingested from a data source. Retrieved: Oct 29, 2026, 02:00 UTC. Ingestion is not an independent editorial investigation.

A CISA KEV listing documents known exploitation, not necessarily a zero-day; absence from the catalog does not prove a vulnerability has never been exploited.

Technology tags indicate possible relevance, not verified exposure. Confirm the affected product, version, and configuration against your own inventory; KEVWire does not scan your systems.

A personal reading checklist on this device, not verified remediation.

Record JSON

Your account

Email alerts

Email alerts are coming as part of KEVWire Premium: join the waitlist. To follow your stack today, use its RSS feed, which honors your filters, or connect an AI agent through the API.

Suggest an improvement

Ideas, missing sources, corrections, and bugs are all welcome. No account needed. Suggestions are reviewed by a person before anything changes.

Record details

Record detail