CVE-2024-34273
Description
njwt <=0.4.0 has a prototype pollution vulnerability in Parser.prototype.parse, allowing attackers to pollute Object.prototype via crafted JWT tokens.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
njwt <=0.4.0 has a prototype pollution vulnerability in Parser.prototype.parse, allowing attackers to pollute Object.prototype via crafted JWT tokens.
Vulnerability
Description
The nJwt library up to version 0.4.0 is vulnerable to prototype pollution in the Parser.prototype.parse method. When verifying a JWT token, the parser does not validate that attributes assigned to JwtHeader and JwtBody objects do not resolve to the object prototype. An attacker can craft a JWT token containing __proto__ properties in the header or body, which, upon parsing, can pollute Object.prototype with arbitrary properties [1][2].
Attack
Vector and Prerequisites
Exploitation requires the ability to supply a crafted JWT token to an application using nJwt's verify() function. No additional authentication is needed if the application accepts tokens from untrusted sources. The attacker creates a token with __proto__ keys in the JSON payload. For example, setting "__proto__": { "compact": null, "reservedKeys": ["typ", "random_gibberish"] } in the header can override the reservedKeys array used during property assignment, enabling injection of arbitrary keys [2][3].
Impact
Successful prototype pollution can lead to property injection on all objects in the Node.js process. This may be leveraged to bypass security checks, alter application behavior, or trigger denial of service. For instance, overriding the hasOwnProperty or toJSON methods could break logic that depends on these functions, potentially leading to privilege escalation or information disclosure [2][3].
Mitigation
Status
The vulnerability has been patched in the nJwt repository. The fix involves freezing the prototype of JwtBody, moving reservedKeys from the prototype to a local variable, and preventing toString from being overloaded. Users should upgrade to the latest version beyond 0.4.0 [4].
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
njwtnpm | < 2.0.1 | 2.0.1 |
Affected products
2Patches
17 files changed · +78 −2970
CHANGELOG.md+4 −0 modified@@ -1,5 +1,9 @@ # nJwt Change Log +### 2.0.1 + +* [#107](https://github.com/jwtk/njwt/pull/107) Freeze `prototype` of all classes to prevent prototype pollution vuln ([CVE-2024-34273](https://cve.mitre.org/cgi-bin/cvename.cgi?name=2024-34273)) + ### 2.0.0 * [#98](https://github.com/jwtk/njwt/pull/98) Bumps jsonwebtoken version, drop Node < 12 from engines
index.d.ts+2 −3 modified@@ -61,12 +61,11 @@ export declare class JwtBody { toJSON(): JSONMap; compact(): string; } -export declare function JwtHeader(header: JwtHeaderOptions): JwtHeader; +export declare function JwtHeader(header: JwtHeaderOptions, enforceDefaultFields?: boolean): JwtHeader; export declare class JwtHeader { - constructor(header: JwtHeaderOptions); + constructor(header: JwtHeaderOptions, enforceDefaultFields?: boolean); typ: string; alg: string; - reservedKeys: string[]; compact(): string; }
index.js+31 −11 modified@@ -113,17 +113,21 @@ JwtBody.prototype.compact = function compact(){ return base64urlEncode(JSON.stringify(this)); }; -function JwtHeader(header){ +var reservedHeaderKeys = ['typ','alg']; +function JwtHeader(header, enforceDefaultFields){ if(!(this instanceof JwtHeader)){ return new JwtHeader(header); } - var self = this; - this.typ = header && header.typ || 'JWT'; - this.alg = header && header.alg || 'HS256'; + this.typ = header && header.typ; + this.alg = header && header.alg; + if (enforceDefaultFields !== false) { + this.typ = this.typ || 'JWT'; + this.alg = this.alg || 'HS256'; + } if(header){ return Object.keys(header).reduce(function(acc,key){ - if(self.reservedKeys.indexOf(key)===-1 && header.hasOwnProperty(key)){ + if(reservedHeaderKeys.indexOf(key)===-1 && header.hasOwnProperty(key)){ acc[key] = header[key]; } return acc; @@ -132,7 +136,6 @@ function JwtHeader(header){ return this; } } -JwtHeader.prototype.reservedKeys = ['typ','alg']; JwtHeader.prototype.compact = function compact(){ return base64urlEncode(JSON.stringify(this)); }; @@ -312,7 +315,7 @@ Parser.prototype.parse = function parse(jwtString,cb){ jwt.setSigningAlgorithm(header.alg); jwt.signature = signature; jwt.verificationInput = segments[0] +'.' + segments[1]; - jwt.header = new JwtHeader(header); + jwt.header = new JwtHeader(header, false); return done(null,jwt); }; @@ -409,11 +412,12 @@ Verifier.prototype.verify = function verify(jwtString,cb){ var newJwt = new Jwt(body, false); - newJwt.toString = function () { - return jwtString; - }; + // since prototype is now frozen, .toString can no longer be overloaded + // newJwt.toString = function () { + // return jwtString; + // }; - newJwt.header = new JwtHeader(header); + newJwt.header = new JwtHeader(header, false); if (!verified) { return done(new JwtParseError(properties.errors.SIGNATURE_MISMTACH,jwtString,header,body)); @@ -428,6 +432,22 @@ Verifier.prototype.withKeyResolver = function withKeyResolver(keyResolver) { return this; }; +// vuln: https://security.snyk.io/vuln/SNYK-JS-NJWT-6861582 +Object.freeze(Jwt); +Object.freeze(Jwt.prototype); +Object.freeze(JwtBody); +Object.freeze(JwtBody.prototype); +Object.freeze(JwtHeader); +Object.freeze(JwtHeader.prototype); +Object.freeze(Verifier); +Object.freeze(Verifier.prototype); +Object.freeze(Parser); +Object.freeze(Parser.prototype); +Object.freeze(JwtParseError); +Object.freeze(JwtParseError.prototype); +Object.freeze(JwtError); +Object.freeze(JwtError.prototype); + var jwtLib = { Jwt: Jwt, JwtBody: JwtBody,
package.json+1 −1 modified@@ -1,6 +1,6 @@ { "name": "njwt", - "version": "2.0.0", + "version": "2.0.1", "description": "JWT Library for Node.js", "engines": { "node": ">=12.0"
test/exports.js+39 −0 added@@ -0,0 +1,39 @@ +var assert = require('chai').assert; +var nJwt = require('..'); + +describe('njwt module exports',function () { + // https://github.com/chrisandoryan/vuln-advisory/blob/main/nJwt/CVE-2024-34273.md + describe('CVE-2024-34273', function () { + it('should export classes with frozen prototypes', function(){ + assert.frozen(nJwt.Jwt); + assert.frozen(nJwt.Jwt.prototype); + assert.frozen(nJwt.JwtBody); + assert.frozen(nJwt.JwtBody.prototype); + assert.frozen(nJwt.JwtHeader); + assert.frozen(nJwt.JwtHeader.prototype); + assert.frozen(nJwt.Verifier); + assert.frozen(nJwt.Verifier.prototype); + }); + + it('should not allow prototype pollution', function () { + + // based on: https://github.com/chrisandoryan/vuln-advisory/blob/main/nJwt/CVE-2024-34273.md#proof-of-concept-poc + var token = `ewogICJ0eXAiOiAiSldUIiwKICAiYWxnIjogIm5vbmUiLAogICJfX3Byb3RvX18iOiB7CiAgICAidHlwIjogIkpXVCIsCiAgICAiYWxnIjogIkhTMjU + 2IiwKICAgICJfX3Byb3RvX18iOiB7CiAgICAgICJjb21wYWN0IjogbnVsbCwKICAgICAgInJlc2VydmVkS2V5cyI6IFsKICAgICAgICAidHlwIiwKICAgICAgICAicmF + uZG9tX2dpYmJlcmlzaCIKICAgICAgXQogICAgfQogIH0KfQ.ewogICJzdWIiOiAxLAogICJzY29wZSI6ICJ1c2VyIiwKICAianRpIjogImJhZmIxNmNlLTIwZDYtNGNk + Ny05NDgzLTY1YTA5NThhOGU2NCIsCiAgImlhdCI6IDI1Mzc0Nzg1MDYsCiAgImV4cCI6IDI1Mzc0Nzg1MDYsCiAgIl9fcHJvdG9fXyI6IHsKICAgICJjb21wYWN0Ijog + bnVsbCwKICAgICJ0b0pTT04iOiBudWxsLAogICAgInBvbGx1dGVkIjogdHJ1ZQogIH0KfQ`.replace(/\s/g, ''); + + assert.isOk(nJwt.JwtBody.prototype.hasOwnProperty('toJSON')) + assert.isOk(nJwt.JwtBody.prototype.hasOwnProperty('compact')) + assert.isOk(nJwt.JwtHeader.prototype.hasOwnProperty('compact')) + + nJwt.verify(token); + + assert.isOk(nJwt.JwtBody.prototype.hasOwnProperty('toJSON')) + assert.isOk(nJwt.JwtBody.prototype.hasOwnProperty('compact')) + assert.isOk(nJwt.JwtHeader.prototype.hasOwnProperty('compact')) + }); + }); + +});
test/verifier.js+1 −1 modified@@ -36,7 +36,7 @@ describe('Verifier().setSigningAlgorithm() ',function(){ describe('.verify()',function(){ it('should persist the original token to the toString() invocation',function(){ - var token = 'eyJhbGciOiJub25lIn0.eyJzdWIiOiIxMjMifQ.p6bizskaJLAheVyRhQEMR-60PkH_jtLVYgMy1qTjCoc'; + var token = 'eyJhbGciOiJub25lIn0.eyJzdWIiOiIxMjMifQ'; assert.equal(token,nJwt.verify(token).toString()); });
yarn.lock+0 −2954 removed
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5News mentions
0No linked articles in our index yet.