_SPECS in challenges/expert_vault.py is module-level global state. Once any player submits the correct key, _SPECS is not None for the entire process, and is_loaded() returns True for every subsequent visitor until restart.
Since the app runs under gunicorn with a single worker, one successful unlock likely opens the expert tier to everyone hitting that instance.
Needs checking: which routes in app.py gate on is_loaded() rather than on the individual player's session. If any serve expert content based on the global, the tier is effectively unlocked for all users after the first successful unlock.
Related, lower priority:
_verify uses == for key comparison; should use hmac.compare_digest
_VALID_KEY holds the key in cleartext in module globals; consider storing a hash
- No rate limiting on unlock attempts
_SPECSinchallenges/expert_vault.pyis module-level global state. Once any player submits the correct key,_SPECS is not Nonefor the entire process, andis_loaded()returns True for every subsequent visitor until restart.Since the app runs under gunicorn with a single worker, one successful unlock likely opens the expert tier to everyone hitting that instance.
Needs checking: which routes in
app.pygate onis_loaded()rather than on the individual player's session. If any serve expert content based on the global, the tier is effectively unlocked for all users after the first successful unlock.Related, lower priority:
_verifyuses==for key comparison; should usehmac.compare_digest_VALID_KEYholds the key in cleartext in module globals; consider storing a hash