Skip to content

Reject unexpected JWT algorithms, and refuse a guessable signing key - #850

Open
yuzi-co wants to merge 1 commit into
sipeed:mainfrom
yuzi-co:security/jwt-hardening
Open

Reject unexpected JWT algorithms, and refuse a guessable signing key#850
yuzi-co wants to merge 1 commit into
sipeed:mainfrom
yuzi-co:security/jwt-hardening

Conversation

@yuzi-co

@yuzi-co yuzi-co commented Aug 1, 2026

Copy link
Copy Markdown

Two faults in the session token, either of which lets an attacker forge a session.

1. The parser accepts whatever algorithm the token names

Nothing pins the expected signing method, so a token is parsed on the terms it declares rather than the terms the server issues. The parser now accepts only the algorithm the server signs with and rejects everything else before verification.

middleware/jwt_alg_test.go presents tokens with a different algorithm and asserts they are refused.

2. The signing secret falls back to a compiled-in default

When the configured key is missing or unreadable, the server used a built-in value and carried on. Every device that took that path shared one signing key, so a token minted on any one of them was valid on all of them — and the key is in the source.

Loading the key now fails loudly. A server that cannot load a secret does not start, instead of starting with one an attacker already has.

config/jwt_test.go covers the missing, unreadable and valid cases.

Note on the second half

This changes a failure into a hard stop at startup, which is a behaviour change. It seemed like the right trade — a device that silently accepts forged sessions is worse than one that refuses to start — but if you would rather it generate and persist a fresh random key instead of exiting, that is a small change and I am happy to make it.

Verified with go build, go vet, go test, and GOOS=linux GOARCH=riscv64 go build. Tests need -tags novision (#846) to run off-device.

Touches middleware/jwt.go, as does #847, but in a different function — they merge cleanly in either order.

@yuzi-co
yuzi-co force-pushed the security/jwt-hardening branch from 5cdf5d4 to 33a7a3c Compare August 2, 2026 21:28
Two faults in the session token, either of which forges a session.

The parser accepted whatever algorithm the token named. A token presented with
alg "none", or signed with HMAC where the server expects its own HMAC secret,
was therefore parsed on the attacker's terms. The parser now accepts only the
algorithm the server issues and rejects everything else before verification.

The signing secret fell back to a compiled-in default when the configured key
was missing or unreadable. Every device that hit that path shared one key, so
a token minted on any of them was valid on all of them. Reading the key now
fails loudly instead: a server that cannot load a secret does not start,
rather than starting with one an attacker already knows.
@yuzi-co
yuzi-co force-pushed the security/jwt-hardening branch from 33a7a3c to dec75ad Compare August 13, 2026 17:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant