Skip to content

Commit

Permalink
CVE 2024 34273 (#107)
Browse files Browse the repository at this point in the history
* tests

* fixes tests

* version bump

* CVE-2024-34273
  • Loading branch information
jaredperreault-okta authored Jun 11, 2024
1 parent 84fa6e6 commit ec9483b
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 2,970 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
5 changes: 2 additions & 3 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
42 changes: 31 additions & 11 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -132,7 +136,6 @@ function JwtHeader(header){
return this;
}
}
JwtHeader.prototype.reservedKeys = ['typ','alg'];
JwtHeader.prototype.compact = function compact(){
return base64urlEncode(JSON.stringify(this));
};
Expand Down Expand Up @@ -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);
};

Expand Down Expand Up @@ -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));
Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "njwt",
"version": "2.0.0",
"version": "2.0.1",
"description": "JWT Library for Node.js",
"engines": {
"node": ">=12.0"
Expand Down
39 changes: 39 additions & 0 deletions test/exports.js
Original file line number Diff line number Diff line change
@@ -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'))
});
});

});
2 changes: 1 addition & 1 deletion test/verifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -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());
});

Expand Down
Loading

0 comments on commit ec9483b

Please sign in to comment.