GHSA-HM7R-C7QW-GHP6

Vulnerability from github – Published: 2026-04-03 22:01 – Updated: 2026-04-06 23:41
VLAI
Summary
fast-jwt accepts unknown `crit` header extensions (RFC 7515 violation)
Details

Summary

fast-jwt does not validate the crit (Critical) Header Parameter defined in RFC 7515 §4.1.11. When a JWS token contains a crit array listing extensions that fast-jwt does not understand, the library accepts the token instead of rejecting it. This violates the MUST requirement in the RFC.


RFC Requirement

RFC 7515 §4.1.11:

If any of the listed extension Header Parameters are not understood and supported by the recipient, then the JWS is invalid.


Proof of Concept

const { createSigner, createVerifier } = require("fast-jwt"); // v3.3.3

const signer = createSigner({ key: "secret", algorithm: "HS256" });
const token = signer({
  sub: "attacker",
  role: "admin",
  header: { crit: ["x-custom-policy"], "x-custom-policy": "require-mfa" },
});

// Should REJECT — x-custom-policy is not understood
const verifier = createVerifier({ key: "secret", algorithms: ["HS256"] });
try {
  const result = verifier(token);
  console.log("ACCEPTED:", result);
  // Output: ACCEPTED: { sub: 'attacker', role: 'admin' }
} catch (e) {
  console.log("REJECTED:", e.message);
}

Expected: Error — unsupported critical extension Actual: Token accepted.

Comparison

// jose (panva) v4+ — correctly rejects
const jose = require("jose");
await jose.jwtVerify(token, new TextEncoder().encode("secret"));
// throws: Extension Header Parameter "x-custom-policy" is not recognized

Impact

  • Split-brain verification in mixed-library environments
  • Security policy bypass when crit carries enforcement semantics
  • Token binding bypass (RFC 7800 cnf confirmation)
  • See CVE-2025-59420 for full impact analysis

Suggested Fix

In src/verifier.js, add crit validation after header decoding:

const SUPPORTED_CRIT = new Set(["b64"]);

function validateCrit(header) {
  if (!header.crit) return;
  if (!Array.isArray(header.crit) || header.crit.length === 0)
    throw new Error("crit must be a non-empty array");
  for (const ext of header.crit) {
    if (!SUPPORTED_CRIT.has(ext))
      throw new Error(`Unsupported critical extension: ${ext}`);
    if (!(ext in header))
      throw new Error(`Critical extension ${ext} not present in header`);
  }
}
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "fast-jwt"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "6.1.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-35042"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-345",
      "CWE-636"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-03T22:01:25Z",
    "nvd_published_at": "2026-04-06T17:17:13Z",
    "severity": "HIGH"
  },
  "details": "## Summary\n\n`fast-jwt` does not validate the `crit` (Critical) Header Parameter defined in RFC 7515 \u00a74.1.11. When a JWS token contains a `crit` array listing extensions that `fast-jwt` does not understand, the library accepts the token instead of rejecting it. This violates the **MUST** requirement in the RFC.\n\n---\n\n## RFC Requirement\n\nRFC 7515 \u00a74.1.11:\n\n\u003e If any of the listed extension Header Parameters are **not understood\n\u003e and supported** by the recipient, then the **JWS is invalid**.\n\n---\n\n## Proof of Concept\n\n```javascript\nconst { createSigner, createVerifier } = require(\"fast-jwt\"); // v3.3.3\n\nconst signer = createSigner({ key: \"secret\", algorithm: \"HS256\" });\nconst token = signer({\n  sub: \"attacker\",\n  role: \"admin\",\n  header: { crit: [\"x-custom-policy\"], \"x-custom-policy\": \"require-mfa\" },\n});\n\n// Should REJECT \u2014 x-custom-policy is not understood\nconst verifier = createVerifier({ key: \"secret\", algorithms: [\"HS256\"] });\ntry {\n  const result = verifier(token);\n  console.log(\"ACCEPTED:\", result);\n  // Output: ACCEPTED: { sub: \u0027attacker\u0027, role: \u0027admin\u0027 }\n} catch (e) {\n  console.log(\"REJECTED:\", e.message);\n}\n```\n\n**Expected:** Error \u2014 unsupported critical extension\n**Actual:** Token accepted.\n\n### Comparison\n\n```javascript\n// jose (panva) v4+ \u2014 correctly rejects\nconst jose = require(\"jose\");\nawait jose.jwtVerify(token, new TextEncoder().encode(\"secret\"));\n// throws: Extension Header Parameter \"x-custom-policy\" is not recognized\n```\n\n---\n\n## Impact\n\n- **Split-brain verification** in mixed-library environments\n- **Security policy bypass** when `crit` carries enforcement semantics\n- **Token binding bypass** (RFC 7800 `cnf` confirmation)\n- See CVE-2025-59420 for full impact analysis\n\n---\n\n## Suggested Fix\n\nIn `src/verifier.js`, add crit validation after header decoding:\n\n```javascript\nconst SUPPORTED_CRIT = new Set([\"b64\"]);\n\nfunction validateCrit(header) {\n  if (!header.crit) return;\n  if (!Array.isArray(header.crit) || header.crit.length === 0)\n    throw new Error(\"crit must be a non-empty array\");\n  for (const ext of header.crit) {\n    if (!SUPPORTED_CRIT.has(ext))\n      throw new Error(`Unsupported critical extension: ${ext}`);\n    if (!(ext in header))\n      throw new Error(`Critical extension ${ext} not present in header`);\n  }\n}\n```",
  "id": "GHSA-hm7r-c7qw-ghp6",
  "modified": "2026-04-06T23:41:50Z",
  "published": "2026-04-03T22:01:25Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/nearform/fast-jwt/security/advisories/GHSA-hm7r-c7qw-ghp6"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-35042"
    },
    {
      "type": "ADVISORY",
      "url": "https://github.com/advisories/GHSA-9ggr-2464-2j32"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/nearform/fast-jwt"
    },
    {
      "type": "WEB",
      "url": "https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.11"
    }
  ],
  "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-jwt accepts unknown `crit` header extensions (RFC 7515 violation)"
}



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…