The Token That Never Dies — JavaScript Bug Hunt
Security review flagged that Meridian API access tokens keep working long after they expire — and freshly issued tokens are sometimes rejected at 9 AM sharp.
- Language: JavaScript
- Layer: Backend
- Difficulty: Medium
- Modelled on: JWT deployments
- Visible tests: a fresh token is accepted; a token expired an hour ago is rejected; clock skew works in the client's favour
- Reward: 50 XP for a complete fix
Briefing
Security review flagged that Meridian API access tokens keep working long after they expire — and freshly issued tokens are sometimes rejected at 9 AM sharp.
Token decoding and the route guard are locked. verifyToken.js owns the expiry math.
Remember: JWT exp is in seconds since epoch (RFC 7519), and the service allows 60 seconds of clock skew in the client's favour.
Bug report
BUG-5521 · Priority: Critical (security) · Reported by: pentest
- A token with exp = one hour AGO is still accepted.
- Tokens minted by a server whose clock is 30s ahead get rejected, even though the spec grants 60s of skew tolerance.
Contract for verifyToken(token, nowMs): returns { valid: true, userId } or { valid: false, reason }.
Logs
[guard] ALLOW userId=u_812 exp=1767261600 now=1767265200000 <- expired 1h ago!
[guard] DENY reason=expired exp=1767268830 now=1767268800000 <- only 30s aheadThe code as shipped
src/auth/verifyToken.js (editable)
var store = require("./tokenStore");
var CLOCK_SKEW_SECONDS = 60;
// exp is SECONDS since epoch (JWT spec). nowMs is milliseconds.
exports.verifyToken = function (token, nowMs) {
var payload = store.decode(token);
var deadline = payload.exp - CLOCK_SKEW_SECONDS;
if (deadline < nowMs) {
return { valid: false, reason: "expired" };
}
return { valid: true, userId: payload.userId };
};
Read-only context: src/auth/guard.js, src/auth/tokenStore.js.
Open the hunt to edit the files, run the visible tests and submit against the hidden ones. More JavaScript bug hunts.