{"record":{"id":"2bc7d81f061377e0","repo":"gchq/CyberChef","slug":"invalid-flask-token-format-expected-payload-times-2bc7d8","errorCode":null,"errorMessage":"Invalid Flask token format. Expected payload.timestamp.signature","messagePattern":"Invalid Flask token format\\. Expected payload\\.timestamp\\.signature","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/FlaskSessionVerify.mjs","lineNumber":73,"sourceCode":"     * @param {Object[]} args\n     * @returns {string}\n     */\n    run(input, args) {\n\n        if (!args[0].string) {\n            throw new OperationError(\"Secret key required\");\n        }\n\n        const key = Utils.convertToByteString(args[0].string, args[0].option);\n        const salt = Utils.convertToByteString(args[1].string || \"cookie-session\", args[1].option);\n        const algorithm = args[2] || \"sha1\";\n\n        input = input.trim();\n\n        const parts = input.split(\".\");\n\n        if (parts.length !== 3) {\n            throw new OperationError(\"Invalid Flask token format. Expected payload.timestamp.signature\");\n        }\n\n        const data = Utils.convertToByteString(parts[0] + \".\" + parts[1], \"utf8\");\n\n\n        const derivedKey = CryptoApi.getHmac(key, CryptoApi.getHasher(algorithm));\n        derivedKey.update(salt);\n\n        const sign = CryptoApi.getHmac(derivedKey.finalize(), CryptoApi.getHasher(algorithm));\n        sign.update(data);\n\n        const payloadB64 = parts[0];\n        const base64 = payloadB64.replace(/-/g, \"+\").replace(/_/g, \"/\");\n        const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, \"=\");\n\n        const time = parts[1];\n\n        const timeB64 = time.replace(/-/g, \"+\").replace(/_/g, \"/\");","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/FlaskSessionVerify.mjs#L55-L91","documentation":"Thrown by the Flask Session Verify operation when the input cookie string does not split into exactly three dot-separated parts. Flask session cookies use the itsdangerous format: payload.timestamp.signature. Verification requires all three segments to recompute and compare the HMAC.","triggerScenarios":"run(input, args) at line 72 where input.trim().split('.').length !== 3. The input has fewer or more than two dots after trimming.","commonSituations":"Pasting a non-Flask cookie, a truncated Flask cookie, or a JWT (which has 3 segments but a different signing scheme). Also when the 'session=' prefix is included or extra whitespace remains.","solutions":["Verify the input is a complete Flask session cookie with exactly three base64url segments separated by dots.","Strip any 'session=' cookie-name prefix, leaving only the token value.","Re-capture the cookie from browser DevTools to ensure completeness.","Confirm the token is from Flask and not another framework."],"exampleFix":"// before: input = 'session=eyJ1c2Vy...partial' (prefix + truncated)\n\n// after: input = 'eyJ1c2VyIjoiYWRtaW4ifQ.Zmxhc2s=.abc123sig'\n//         (clean payload.timestamp.signature)","handlingStrategy":"validation","validationCode":"// Validate Flask cookie has 3 dot-separated segments before verifying\nconst parts = input.trim().split('.');\nif (parts.length !== 3) {\n  throw new Error('Input must be payload.timestamp.signature');\n}","typeGuard":"function isFlaskCookieFormat(str) {\n  const parts = str.trim().split('.');\n  return parts.length === 3 && parts.every(p => p.length > 0);\n}","tryCatchPattern":null,"preventionTips":["Confirm the input has exactly three dot-separated segments.","Strip cookie name prefixes and whitespace.","Verify the source is a Flask session cookie."],"tags":["crypto","flask","session","format-validation","cookie"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}