VYPR
Low severity3.1NVD Advisory· Published Nov 4, 2024· Updated Apr 15, 2026

CVE-2024-51744

CVE-2024-51744

Description

golang-jwt is a Go implementation of JSON Web Tokens. Unclear documentation of the error behavior in ParseWithClaims can lead to situation where users are potentially not checking errors in the way they should be. Especially, if a token is both expired and invalid, the errors returned by ParseWithClaims return both error codes. If users only check for the jwt.ErrTokenExpired using error.Is, they will ignore the embedded jwt.ErrTokenSignatureInvalid and thus potentially accept invalid tokens. A fix has been back-ported with the error handling logic from the v5 branch to the v4 branch. In this logic, the ParseWithClaims function will immediately return in "dangerous" situations (e.g., an invalid signature), limiting the combined errors only to situations where the signature is valid, but further validation failed (e.g., if the signature is valid, but is expired AND has the wrong audience). This fix is part of the 4.5.1 release. We are aware that this changes the behaviour of an established function and is not 100 % backwards compatible, so updating to 4.5.1 might break your code. In case you cannot update to 4.5.0, please make sure that you are properly checking for all errors ("dangerous" ones first), so that you are not running in the case detailed above.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/golang-jwt/jwt/v4Go
< 4.5.14.5.1

Patches

1
7b1c1c00a171

Merge commit from fork

https://github.com/golang-jwt/jwtChristian BanseNov 3, 2024via ghsa
3 files changed · +36 22
  • example_test.go+5 1 modified
    @@ -93,7 +93,7 @@ func ExampleParseWithClaims_customClaimsType() {
     	// Output: bar test
     }
     
    -// An example of parsing the error types using bitfield checks
    +// An example of parsing the error types using [errors.Is].
     func ExampleParse_errorChecking() {
     	// Token from another example.  This token is expired
     	var tokenString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c"
    @@ -106,6 +106,10 @@ func ExampleParse_errorChecking() {
     		fmt.Println("You look nice today")
     	} else if errors.Is(err, jwt.ErrTokenMalformed) {
     		fmt.Println("That's not even a token")
    +	} else if errors.Is(err, jwt.ErrTokenUnverifiable) {
    +		fmt.Println("We could not verify this token")
    +	} else if errors.Is(err, jwt.ErrTokenSignatureInvalid) {
    +		fmt.Println("This token has an invalid signature")
     	} else if errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet) {
     		// Token is either expired or not active yet
     		fmt.Println("Timing is everything")
    
  • parser.go+20 21 modified
    @@ -36,19 +36,21 @@ func NewParser(options ...ParserOption) *Parser {
     	return p
     }
     
    -// Parse parses, validates, verifies the signature and returns the parsed token.
    -// keyFunc will receive the parsed token and should return the key for validating.
    +// Parse parses, validates, verifies the signature and returns the parsed token. keyFunc will
    +// receive the parsed token and should return the key for validating.
     func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
     	return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc)
     }
     
    -// ParseWithClaims parses, validates, and verifies like Parse, but supplies a default object implementing the Claims
    -// interface. This provides default values which can be overridden and allows a caller to use their own type, rather
    -// than the default MapClaims implementation of Claims.
    +// ParseWithClaims parses, validates, and verifies like Parse, but supplies a default object
    +// implementing the Claims interface. This provides default values which can be overridden and
    +// allows a caller to use their own type, rather than the default MapClaims implementation of
    +// Claims.
     //
    -// Note: If you provide a custom claim implementation that embeds one of the standard claims (such as RegisteredClaims),
    -// make sure that a) you either embed a non-pointer version of the claims or b) if you are using a pointer, allocate the
    -// proper memory for it before passing in the overall claims, otherwise you might run into a panic.
    +// Note: If you provide a custom claim implementation that embeds one of the standard claims (such
    +// as RegisteredClaims), make sure that a) you either embed a non-pointer version of the claims or
    +// b) if you are using a pointer, allocate the proper memory for it before passing in the overall
    +// claims, otherwise you might run into a panic.
     func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
     	token, parts, err := p.ParseUnverified(tokenString, claims)
     	if err != nil {
    @@ -85,35 +87,32 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf
     		return token, &ValidationError{Inner: err, Errors: ValidationErrorUnverifiable}
     	}
     
    +	// Perform validation
    +	token.Signature = parts[2]
    +	if err := token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil {
    +		return token, &ValidationError{Inner: err, Errors: ValidationErrorSignatureInvalid}
    +	}
    +
     	vErr := &ValidationError{}
     
     	// Validate Claims
     	if !p.SkipClaimsValidation {
     		if err := token.Claims.Valid(); err != nil {
    -
     			// If the Claims Valid returned an error, check if it is a validation error,
     			// If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set
     			if e, ok := err.(*ValidationError); !ok {
     				vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid}
     			} else {
     				vErr = e
     			}
    +			return token, vErr
     		}
     	}
     
    -	// Perform validation
    -	token.Signature = parts[2]
    -	if err = token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil {
    -		vErr.Inner = err
    -		vErr.Errors |= ValidationErrorSignatureInvalid
    -	}
    -
    -	if vErr.valid() {
    -		token.Valid = true
    -		return token, nil
    -	}
    +	// No errors so far, token is valid.
    +	token.Valid = true
     
    -	return token, vErr
    +	return token, nil
     }
     
     // ParseUnverified parses the token but doesn't validate the signature.
    
  • parser_test.go+11 0 modified
    @@ -111,6 +111,17 @@ var jwtTestData = []struct {
     		nil,
     		jwt.SigningMethodRS256,
     	},
    +	{
    +		"basic invalid and expired",
    +		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIiLCJleHAiOjEyMzR9.IbFvatLIJ2Z7B_MAaeIaRZsRSQF1CDzmAE0osHII3WfRTbPavonrDXz-p2Ap_oh9LT2lyohL_jCLoVcpTyu7K3Rt-hdgxZ1_r1StwM1we0SqW2BFFeXCzyS9SLf2YTaVR35lVvfwwlCpPBgOw1SBbczm9m6yPgA9Afsvw_lG_GU2civvG0UzHXxbzWWvJoflGokJDuoHQiku2bfxReyNsoUGcLjx5tfkY7cPihM3CffPpRFYCVjv_abHYelZWpVjdGULQyJDInGYqO8oANqNTtjui7aqxBpcFCUBwVVgktM4Q6Dvj-o5LrdPyJSEl0b_R2JstFE5CbEZGN5anN1yHa",
    +		defaultKeyFunc,
    +		jwt.MapClaims{"foo": "bar", "exp": 1234.0},
    +		false,
    +		jwt.ValidationErrorSignatureInvalid,
    +		[]error{jwt.ErrTokenSignatureInvalid, rsa.ErrVerification},
    +		nil,
    +		jwt.SigningMethodRS256,
    +	},
     	{
     		"basic nokeyfunc",
     		"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.