Segredo HMAC fraco
Com HS256, quem sabe o segredo pode assinar qualquer token. Um segredo adivinhável entrega isso.
O algoritmo HS256 assina o token com HMAC-SHA256, usando um único segredo que o servidor guarda. Assinar e conferir usam o mesmo segredo: a assinatura é HMAC(segredo, header.payload). Quem descobre o segredo pode montar e assinar qualquer token, inclusive um com role: admin que passa em qualquer verificação.
A assinatura não tem volta, mas isso não protege um segredo fraco. Se o segredo é uma palavra comum, um ano, o nome do sistema (galpao2021), dá para testar candidatos um a um: para cada palavra de uma lista, recalcule a assinatura sobre o header.payload do token e veja qual reproduz a assinatura que veio. A que bater é o segredo.
Em Python, o laço é curto:
import hmac, hashlib, base64
signing_input = (header_b64 + "." + payload_b64).encode()
for w in open("wordlist.txt").read().split():
sig = base64.urlsafe_b64encode(
hmac.new(w.encode(), signing_input, hashlib.sha256).digest()
).rstrip(b"=").decode()
if sig == token_signature:
print("secret:", w)
O conserto é um segredo longo e aleatório (32 bytes ou mais, de um gerador seguro), guardado fora do código, em variável de ambiente ou cofre. Aí nenhuma lista de palavras chega perto.