GHSA-W74X-V6F9-J3XG

Vulnerability from github – Published: 2026-10-23 21:41 – Updated: 2026-10-23 21:41
VLAI
Summary
fast-uri vulnerable to URI scheme spoofing via percent-encoded scheme decoding
Details

Impact

fast-uri percent-decodes the scheme component with the legacy global unescape() before validating it, so an input whose decoded scheme is a valid but dangerous token is emitted as a live scheme. RFC 3986 section 3.1 does not allow percent-encoding in a scheme, so no RFC or WHATWG parser treats such input as having that scheme, but fast-uri does.

For example, normalize('%6Aavascript:alert(1)') returns javascript:alert(1), resolve('https://a.example/', '%6Aavascript:alert(1)') returns javascript:alert(1), and parse('%6Aavascript:alert(1)').scheme returns javascript. The %uXXXX form (%u006Aavascript:) produces the same result, and equal('%68ttp://a/', 'http://a/') returns true.

An application that screens dangerous schemes on the raw input and then stores or renders normalize(input) or resolve(base, input) turns an inert string into an executable javascript:, data:, or vbscript: URL, a stored or reflected cross-site scripting vector in the consuming application. equal() also treats an encoded and a plain scheme as the same, which can bypass equality-based allowlists.

Patches

Upgrade to fast-uri 2.4.8, 3.1.9, or 4.2.3.

Workarounds

Reject input whose scheme part (before the first :, and before any /, ?, or #) contains %. Alternatively, check parse(x).scheme against an allowlist after normalization and use that same parsed result rather than the raw string.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "fast-uri"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.4.8"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "npm",
        "name": "fast-uri"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.0.0"
            },
            {
              "fixed": "3.1.9"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "npm",
        "name": "fast-uri"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "4.0.0"
            },
            {
              "fixed": "4.2.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-110306"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-172",
      "CWE-180"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-10-23T21:41:36Z",
    "nvd_published_at": "2026-10-20T07:17:08Z",
    "severity": "MODERATE"
  },
  "details": "### Impact\n\n`fast-uri` percent-decodes the scheme component with the legacy global `unescape()` before validating it, so an input whose decoded scheme is a valid but dangerous token is emitted as a live scheme. RFC 3986 section 3.1 does not allow percent-encoding in a scheme, so no RFC or WHATWG parser treats such input as having that scheme, but `fast-uri` does.\n\nFor example, `normalize(\u0027%6Aavascript:alert(1)\u0027)` returns `javascript:alert(1)`, `resolve(\u0027https://a.example/\u0027, \u0027%6Aavascript:alert(1)\u0027)` returns `javascript:alert(1)`, and `parse(\u0027%6Aavascript:alert(1)\u0027).scheme` returns `javascript`. The `%uXXXX` form (`%u006Aavascript:`) produces the same result, and `equal(\u0027%68ttp://a/\u0027, \u0027http://a/\u0027)` returns `true`.\n\nAn application that screens dangerous schemes on the raw input and then stores or renders `normalize(input)` or `resolve(base, input)` turns an inert string into an executable `javascript:`, `data:`, or `vbscript:` URL, a stored or reflected cross-site scripting vector in the consuming application. `equal()` also treats an encoded and a plain scheme as the same, which can bypass equality-based allowlists.\n\n### Patches\n\nUpgrade to `fast-uri` `2.4.8`, `3.1.9`, or `4.2.3`.\n\n### Workarounds\n\nReject input whose scheme part (before the first `:`, and before any `/`, `?`, or `#`) contains `%`. Alternatively, check `parse(x).scheme` against an allowlist after normalization and use that same parsed result rather than the raw string.",
  "id": "GHSA-w74x-v6f9-j3xg",
  "modified": "2026-10-23T21:41:36Z",
  "published": "2026-10-23T21:41:36Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/fastify/fast-uri/security/advisories/GHSA-w74x-v6f9-j3xg"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-110306"
    },
    {
      "type": "WEB",
      "url": "https://github.com/fastify/fast-uri/commit/39933a1f1422986f14e2d844f552238feb40f5d4"
    },
    {
      "type": "WEB",
      "url": "https://github.com/fastify/fast-uri/commit/597f254c86d151568511eeb9a1df761fd12520b3"
    },
    {
      "type": "WEB",
      "url": "https://github.com/fastify/fast-uri/commit/e60e716f41d1d73717e2d803d20b68d2c6d20a0f"
    },
    {
      "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.8"
    },
    {
      "type": "WEB",
      "url": "https://github.com/fastify/fast-uri/releases/tag/v3.1.9"
    },
    {
      "type": "WEB",
      "url": "https://github.com/fastify/fast-uri/releases/tag/v4.2.3"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "fast-uri vulnerable to URI scheme spoofing via percent-encoded scheme decoding"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.

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.
Vulnerability timeline

Sightings and recorded dates, grouped by day · UTC

JSON
Events included in the timeline

Loading timeline…


    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.