Add active script for detect and exploit Web Cache Deception#507
Add active script for detect and exploit Web Cache Deception#507e1l1ya wants to merge 1 commit intozaproxy:mainfrom
Conversation
Signed-off-by: Eiliya Keshtkar <eiliyakeshtkar0@gmail.com>
|
Great job! No new security vulnerabilities introduced in this pull requestUse @Checkmarx to interact with Checkmarx PR Assistant. |
There was a problem hiding this comment.
Pull request overview
Adds a new ZAP Active Scan script intended to detect/exploit Web Cache Deception by mutating paths with various delimiters/extensions and by attempting traversal into commonly cached directories.
Changes:
- Introduces
active/WebCacheDeception.jsactive scan rule with two detection approaches (delimiter/extension + traversal into cached folders). - Updates
CHANGELOG.mdto mention the new active script.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 13 comments.
| File | Description |
|---|---|
| active/WebCacheDeception.js | New active scanning script for Web Cache Deception using path mutations and folder traversal heuristics. |
| CHANGELOG.md | Adds an “Unreleased/Added” entry for the new active script. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| isVulnerable = additionalFile2Cache(as, msg, orgPath, endWithSlash); | ||
|
|
||
| if (!isVulnerable) { | ||
| pathTraversal2Cache(as, msg, orgPath, endWithSlash); | ||
| } |
There was a problem hiding this comment.
additionalFile2Cache() never returns a boolean value, so isVulnerable becomes undefined and pathTraversal2Cache() will always run (even when an alert is already raised). Return an explicit true/false from additionalFile2Cache() and either early-return from scanNode when true, or have pathTraversal2Cache() be conditional on that boolean.
| // Check has X Cache header | ||
| var hasXCache = newMsg.getResponseHeader().getHeader("X-Cache"); | ||
| var statusCode = newMsg.getResponseHeader().getStatusCode(); | ||
| if (hasXCache !== null && statusCode >= 200 && statusCode <= 300) { |
There was a problem hiding this comment.
The status code check uses <= 300, which includes HTTP 300 (Multiple Choices) but excludes common redirect statuses (301/302) while still not being a typical definition of “successful” for this purpose. If you mean successful content responses, prefer 200–299 (i.e. < 300).
| if (hasXCache !== null && statusCode >= 200 && statusCode <= 300) { | |
| if (hasXCache !== null && statusCode >= 200 && statusCode < 300) { |
| id: 12345 | ||
| name: Web Cache Deception Detection |
There was a problem hiding this comment.
The metadata still uses the template placeholder id: 12345. In this repo, active scripts use unique non-placeholder IDs (for example, the existing active scripts are in the 1000xx range). Please assign a real unique ID to avoid collisions.
| 12345-2: | ||
| name: Active Vulnerability - Type XYZ | ||
| description: Detect Web Cache Deception |
There was a problem hiding this comment.
alertRefOverrides includes a placeholder override (12345-2 / "Active Vulnerability - Type XYZ") that isn’t used anywhere (the code always raises 12345-1). Remove the unused override or implement a second alert ref if this is intended to report a distinct finding.
| 12345-2: | |
| name: Active Vulnerability - Type XYZ | |
| description: Detect Web Cache Deception |
| - Variant script 'AddUrlParams.js' | ||
| - Extender script 'ScanMonitor.js' | ||
| - Active script 'OpenModelContextProtocolServer.js' - Attempts to detect Model Context Protocol (MCP) servers lacking authentication. | ||
| - Active script to detect and exploit Web Cache Deception |
There was a problem hiding this comment.
This changelog entry doesn’t follow the surrounding convention of naming the script file and giving a short description (see the other "Active script '...js' - ..." entries). Update it to include the script filename and a brief description.
| - Active script to detect and exploit Web Cache Deception | |
| - Active script 'WebCacheDeception.js' - Detects and exploits Web Cache Deception vulnerabilities. |
| description: Detect Web Cache Deception in 2 way 1. add delimiters and file with extention, 2. bind attack with path traversal | ||
| solution: Update the Web Cache policy to dont cache sensitive pages |
There was a problem hiding this comment.
Spelling/grammar in the metadata description/solution should be corrected for user-facing alert text (e.g., "in 2 way", "extention", "dont"). This metadata is displayed in ZAP and should read professionally.
| description: Detect Web Cache Deception in 2 way 1. add delimiters and file with extention, 2. bind attack with path traversal | |
| solution: Update the Web Cache policy to dont cache sensitive pages | |
| description: Detect Web Cache Deception in two ways: 1) add delimiters and a file with an extension, 2) combine the attack with path traversal. | |
| solution: Update the web cache policy to not cache sensitive pages. |
|
|
||
| as.newAlert("12345-1") | ||
| .setRisk(2) // Medium | ||
| .setConfidence(2) // Medium |
There was a problem hiding this comment.
The script metadata sets confidence: LOW, but the raised alert uses .setConfidence(2) (Medium). Align the runtime alert confidence with the metadata (or adjust metadata) to avoid inconsistent reporting.
| .setConfidence(2) // Medium | |
| .setConfidence(1) // Low |
| // Add additional file | ||
| for (let i = 0; i < Delimiters.length; i++) { | ||
| var currentDelimiters = Delimiters[i]; | ||
|
|
||
| for (let j = 0; j < Extensions.length; j++) { |
There was a problem hiding this comment.
This script can generate a very large number of requests per node (Delimiters × Extensions, plus the path-traversal attempts). Consider limiting permutations based on as.getAttackStrength() and/or as.getAlertThreshold() to avoid excessively long scans and operational impact.
| // Check has X Cache header | ||
| var hasXCache = newMsg.getResponseHeader().getHeader("X-Cache"); | ||
| var statusCode = newMsg.getResponseHeader().getStatusCode(); | ||
| if (hasXCache !== null && statusCode >= 200 && statusCode <= 300) { | ||
|
|
||
| raiseAlert(as, payload, newMsg, newPath) | ||
| return; |
There was a problem hiding this comment.
This check treats the presence of the X-Cache header as evidence of caching, but many CDNs/proxies always send X-Cache with values like MISS/BYPASS. Verify an actual cached state (e.g., HIT, TCP_HIT, etc.) and/or do a repeat request to confirm cache behavior before raising an alert.
| // Check has X Cache header | |
| var hasXCache = newMsg.getResponseHeader().getHeader("X-Cache"); | |
| var statusCode = newMsg.getResponseHeader().getStatusCode(); | |
| if (hasXCache !== null && statusCode >= 200 && statusCode <= 300) { | |
| raiseAlert(as, payload, newMsg, newPath) | |
| return; | |
| // Check X-Cache header value to confirm an actual cache hit | |
| var hasXCache = newMsg.getResponseHeader().getHeader("X-Cache"); | |
| var statusCode = newMsg.getResponseHeader().getStatusCode(); | |
| if (hasXCache !== null) { | |
| var xCacheValue = String(hasXCache).toUpperCase(); | |
| if (xCacheValue.indexOf("HIT") !== -1 && | |
| xCacheValue.indexOf("MISS") === -1 && | |
| xCacheValue.indexOf("BYPASS") === -1 && | |
| statusCode >= 200 && statusCode <= 300) { | |
| raiseAlert(as, payload, newMsg, newPath) | |
| return; | |
| } |
|
|
||
| // Handle null path - convert to empty string for consistent processing | ||
| if (orgPath === null) { | ||
| orgPath = "" |
There was a problem hiding this comment.
Avoid automated semicolon insertion (90% of all statements in the enclosing function have an explicit semicolon).
| orgPath = "" | |
| orgPath = ""; |

This script scans multiple delimiters and file extensions to determine the file type and whether it is cached. If no match is found, it attempts to identify cached content by checking commonly cached and well-known directories before the path.