Skip to content

Fix: remove hardcoded JWT signing key (challenge 9) - #68

Closed
beanbeah wants to merge 1 commit into
OWASP-CTF:dc34-ctffrom
beanbeah:ctf/challenge-9-weak-hardcoded-jwt-signing-key
Closed

beanbeah wants to merge 1 commit into
OWASP-CTF:dc34-ctffrom
beanbeah:ctf/challenge-9-weak-hardcoded-jwt-signing-key

Conversation

@beanbeah

@beanbeah beanbeah commented Aug 9, 2026

Copy link
Copy Markdown

Vulnerability

config.py hardcoded the Flask/JWT SECRET_KEY as the literal string 'random'. Since this key signs and verifies every auth token (models/user_model.py: encode_auth_token/decode_auth_token), anyone who read the source could forge a valid JWT for any username — including admin — completely offline, without ever authenticating.

Fix

SECRET_KEY is now read from the SECRET_KEY environment variable when the operator provides one, and otherwise falls back to a securely-generated random key (secrets.token_hex(32)) generated per process. There is no longer a fixed, guessable default shipped in source.

Verification (local run, vulnerable=1)

  1. Logged in as a seeded user (name1/pass1) and obtained a legitimate token from /users/v1/login.
  2. Forged a token for sub: admin signed with the old hardcoded key 'random'.
  3. Before the fix: the forged token was accepted. After the fix: calling PUT /users/v1/name1/password with the forged token now returns 401 {"message": "Invalid token. Please log in again."}.
  4. The legitimately-issued token from step 1 still authenticates successfully (204 on the same password-update endpoint), confirming normal login/auth flow is unaffected.

SECRET_KEY was a fixed literal ('random') committed to source, so anyone
could forge valid auth tokens offline for any username (including admin)
without ever logging in.

Now the key is sourced from the SECRET_KEY environment variable when the
operator provides one, and otherwise falls back to a securely-generated
random key per process (secrets.token_hex(32)) so there is never a
shared, guessable default baked into the repo.

Verified locally: a token forged with the old hardcoded key 'random' is
now rejected with 401 Invalid token, while tokens issued by the running
app's own /login endpoint continue to authenticate normally.
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

🏆 VAmPI — CTF Patch Score

████░░░░░░░░░░░░░░░░  3 / 16 pts  (19%)

1 / 9 challenges patched

Per-challenge detail is withheld — it would reveal the rubric.

Commit: f93ef3c · scoring run

🎉 Your result is on the leaderboard — see where you rank! 🏆

@beanbeah

beanbeah commented Aug 9, 2026

Copy link
Copy Markdown
Author

Superseded by consolidated PR #74 (#74), which merges all validated challenge fixes into one branch. Closing this individual PR.

@beanbeah beanbeah closed this Aug 9, 2026
@beanbeah
beanbeah deleted the ctf/challenge-9-weak-hardcoded-jwt-signing-key branch August 9, 2026 13:57
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