{"record":{"id":"41361df14f9ec6da","repo":"zaproxy/zaproxy","slug":"api-nonce-not-found-in-request-from","errorCode":null,"errorMessage":"API nonce {} not found in request from {}","messagePattern":"API nonce (.+?) not found in request from (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"zap/src/main/java/org/zaproxy/zap/extension/api/API.java","lineNumber":1081,"sourceCode":"     */\n    public boolean hasValidKey(HttpRequestHeader reqHeader, JSONObject params) {\n        try {\n            String apiPath;\n            try {\n                apiPath = reqHeader.getURI().getPath();\n            } catch (URIException e) {\n                LOGGER.error(e.getMessage(), e);\n                return false;\n            }\n            String nonceParam = reqHeader.getHeader(HttpHeader.X_ZAP_API_NONCE);\n            if (nonceParam == null && params.has(API_NONCE_PARAM)) {\n                nonceParam = params.getString(API_NONCE_PARAM);\n            }\n\n            if (nonceParam != null) {\n                Nonce nonce = nonces.get(nonceParam);\n                if (nonce == null) {\n                    LOGGER.warn(\n                            \"API nonce {} not found in request from {}\",\n                            nonceParam,\n                            reqHeader.getSenderAddress().getHostAddress());\n                    return false;\n                } else if (nonce.isOneTime()) {\n                    nonces.remove(nonceParam);\n                }\n                if (!nonce.isValid()) {\n                    LOGGER.warn(\n                            \"API nonce {} expired at {} in request from {}\",\n                            nonce.getNonceKey(),\n                            nonce.getExpires(),\n                            reqHeader.getSenderAddress().getHostAddress());\n                    return false;\n                }\n\n                if (!apiPath.equals(nonce.getApiPath())) {\n                    LOGGER.warn(","sourceCodeStart":1063,"sourceCodeEnd":1099,"githubUrl":"https://github.com/zaproxy/zaproxy/blob/9d1970a436b1b189bfb588fc88864c80d9baf6a5/zap/src/main/java/org/zaproxy/zap/extension/api/API.java#L1063-L1099","documentation":"ZAP validates API nonces sent with requests via API_NONCE_PARAM; this warning fires when the supplied nonce value is not present in ZAP's in-memory nonces map, so validation returns false and the request is rejected. Nonces are not persisted, so any restart invalidates previously issued ones.","triggerScenarios":"A request includes apiNonce=... whose value is unknown to ZAP: reused nonce from a previous ZAP run, an already-consumed one-time nonce, typo'd nonce, or fabricated nonce in an attack.","commonSituations":"Bookmarked links with embedded nonces used after ZAP restart; proxies replaying API requests whose one-time nonce was already consumed; clients caching API URLs containing nonces.","solutions":["Re-request the API URL/page to obtain a fresh nonce before calling the API","Remove any cached/bookmarked URLs containing apiNonce values and fetch them dynamically","Do not reuse one-time nonces; obtain a new nonce for each request"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Only send a nonce obtained in the same ZAP session\nconst nonce = await getFreshNonceFromZapPage(); // parse apiNonce from ZAP-served page\nif (!nonce) throw new Error('No valid nonce available from this ZAP session');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Fetch a fresh nonce for each request instead of caching","Do not reuse one-time nonces; they are consumed on first valid use","Re-obtain nonces after ZAP restarts since they are in-memory only"],"tags":["api","zap","nonce","csrf","stale-state"],"backgroundTag":"api-nonce-not-found","analyzedSha":"9d1970a436b1b189bfb588fc88864c80d9baf6a5","analyzedAt":"2026-09-05T19:26:59.356Z","contentChangedAt":"2026-09-05T19:26:59.356Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}