From 5155aee2e552e5ab7ab7fa6f8ee3c3d0ca149043 Mon Sep 17 00:00:00 2001 From: kingthorin Date: Tue, 17 Feb 2026 11:18:13 -0500 Subject: [PATCH] Add Encode/Decode CyberChef example Signed-off-by: kingthorin --- CHANGELOG.md | 1 + encode-decode/CyberChefExample.js | 52 +++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 encode-decode/CyberChefExample.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 07c8634c..5e5152f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Variant script 'AddUrlParams.js' - Extender script 'ScanMonitor.js' - Active script 'OpenModelContextProtocolServer.js' - Attempts to detect Model Context Protocol (MCP) servers lacking authentication. +- Encode/Decode script 'CyberChefExample.js' - A script which communicates with CyberChef-server Docker image for processing. ### Changed - Update minimum ZAP version to 2.16.0 and compile with Java 17. diff --git a/encode-decode/CyberChefExample.js b/encode-decode/CyberChefExample.js new file mode 100644 index 00000000..17caa3b2 --- /dev/null +++ b/encode-decode/CyberChefExample.js @@ -0,0 +1,52 @@ +// CyberChef - Extract URLs (via /bake) +// https://www.zaproxy.org/blog/2026-02-17-encoder-cyberchef-via-scripts/ + +const EncodeDecodeResult = Java.type( + "org.zaproxy.addon.encoder.processors.EncodeDecodeResult" +); +const HttpRequestHeader = Java.type( + "org.parosproxy.paros.network.HttpRequestHeader" +); +const HttpMessage = Java.type("org.parosproxy.paros.network.HttpMessage"); +const HttpSender = Java.type("org.parosproxy.paros.network.HttpSender"); + +const cyberchefUrl = "http://localhost:3000/bake"; + +const header = new HttpRequestHeader("POST " + cyberchefUrl + " HTTP/1.1"); +header.setHeader("Content-Type", "application/json"); +header.setHeader("Accept", "application/json"); + +const msg = new HttpMessage(header); + +const sender = new HttpSender(HttpSender.MANUAL_REQUEST_INITIATOR); + +function process(helper, value) { + try { + // This is the recipe/operation(s) we're going to ask CyberChef to handle + // In this case if the input value is empty send a single space, otherwise CyberChef complains + var payload = JSON.stringify({ + input: !value || value === "" ? " " : value, + recipe: [{ op: "Extract URLs" }], + }); + + msg.setRequestBody(payload); + msg.getRequestHeader().setContentLength(msg.getRequestBody().length()); + + sender.sendAndReceive(msg); + + var responseStr = msg.getResponseBody().toString(); + + // CyberChef /bake returns { "value": "...", "type": "string" } + if (msg.getResponseHeader().isJson()) { + var json = JSON.parse(responseStr); + // If the return value is empty tell the user there's no URLs, otherwise provide them + // Falling back to the raw response if it isn't JSON + var output = json.value === "" ? "No URLs" : json.value || responseStr; + return helper.newResult(output); + } + + return helper.newResult(responseStr); + } catch (e) { + return helper.newError("Error contacting CyberChef: " + e.toString()); + } +}