VYPR
Medium severity5.9GHSA Advisory· Published May 16, 2024· Updated Apr 15, 2026

CVE-2024-34273

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.

PackageAffected versionsPatched versions
njwtnpm
< 2.0.12.0.1

Affected products

2

Patches

1
ec9483b6eec1

CVE 2024 34273 (#107)

https://github.com/jwtk/njwtJared PerreaultJun 11, 2024via ghsa
7 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

5

News mentions

0

No linked articles in our index yet.