fix(ShowBase64Offsets): escape staticSection on showVariable=false (#2344)
Closes #2344. `ShowBase64Offsets` writes the per-offset `staticSection` directly into HTML output. On the highlighted branches (`showVariable=true`) the static text was wrapped in an attribute-escaped tooltip and was fine, but on the `showVariable=false` branches at lines 98, 128, and 158 the raw Base64 string was assigned back to the offset variable and emitted unescaped. Combined with the explicit `<script>` eval in OutputWaiter.mjs (line 373), a crafted `alphabet` argument whose toBase64 image starts with `<script>...` produced a working XSS payload in the rendered output. The reporter's repro: https://gchq.github.io/CyberChef/#recipe=Show_Base64_offsets('%3Cscript%3Eale(1)/.ABCDEFGHIJKLMNOPQRSTUVWXYZbdfghjkmnoquvwxyz023456',false)&input=ABCDEFGHIJKDGLMNAOBCDEFGHPPP Fix: route all three `if (!showVariable)` branches through `Utils.escapeHtml`, mirroring what the highlighted branches already do for the surrounding tooltip values. The visible string is the same; the dangerous-character shape is sanitised. Tests - New `tests/operations/tests/ShowBase64Offsets.mjs` registered in `tests/operations/index.mjs`: - 'HTML escapes static output (#2344)' — alphabet whose toBase64 image starts with `<script>` must not appear verbatim in the output; the encoded form `<script>` should appear instead. - 'benign alphabet still renders Offset 0' — sanity that the fix is escape-only and the happy-path output still renders. I couldn't run the test suite locally because the CyberChef test runner crashes on Node 25 trying to fetch the argon2-browser WASM asset (unrelated infrastructure issue); the tests follow the same shape as the surrounding suite (BitwiseOp.mjs etc.) and CI on ubuntu-latest with the project's pinned Node will exercise them. Signed-off-by: SAY-5 <say.apm35@gmail.com>
This commit is contained in:
parent
864afa85aa
commit
109f5064cc
@ -95,7 +95,11 @@ class ShowBase64Offsets extends Operation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!showVariable) {
|
if (!showVariable) {
|
||||||
offset0 = staticSection;
|
// staticSection is derived from the input via toBase64 with a
|
||||||
|
// user-controlled alphabet; without escaping, a crafted alphabet
|
||||||
|
// (e.g. one beginning "<script>...") could land directly in the
|
||||||
|
// HTML output (#2344). Escape before reuse on this branch.
|
||||||
|
offset0 = Utils.escapeHtml(staticSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -125,7 +129,7 @@ class ShowBase64Offsets extends Operation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!showVariable) {
|
if (!showVariable) {
|
||||||
offset1 = staticSection;
|
offset1 = Utils.escapeHtml(staticSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Highlight offset 2
|
// Highlight offset 2
|
||||||
@ -154,7 +158,7 @@ class ShowBase64Offsets extends Operation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!showVariable) {
|
if (!showVariable) {
|
||||||
offset2 = staticSection;
|
offset2 = Utils.escapeHtml(staticSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (showVariable ? "Characters highlighted in <span class='hl5'>green</span> could change if the input is surrounded by more data." +
|
return (showVariable ? "Characters highlighted in <span class='hl5'>green</span> could change if the input is surrounded by more data." +
|
||||||
|
|||||||
@ -157,6 +157,7 @@ import "./tests/SeqUtils.mjs";
|
|||||||
import "./tests/SetDifference.mjs";
|
import "./tests/SetDifference.mjs";
|
||||||
import "./tests/SetIntersection.mjs";
|
import "./tests/SetIntersection.mjs";
|
||||||
import "./tests/SetUnion.mjs";
|
import "./tests/SetUnion.mjs";
|
||||||
|
import "./tests/ShowBase64Offsets.mjs";
|
||||||
import "./tests/Shuffle.mjs";
|
import "./tests/Shuffle.mjs";
|
||||||
import "./tests/SIGABA.mjs";
|
import "./tests/SIGABA.mjs";
|
||||||
import "./tests/SM2.mjs";
|
import "./tests/SM2.mjs";
|
||||||
|
|||||||
57
tests/operations/tests/ShowBase64Offsets.mjs
Normal file
57
tests/operations/tests/ShowBase64Offsets.mjs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* ShowBase64Offsets tests
|
||||||
|
*
|
||||||
|
* @author SAY-5
|
||||||
|
* @copyright Crown Copyright 2026
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
// Regression test for #2344. With showVariable=false the
|
||||||
|
// staticSection (toBase64 output, alphabet-derived from a
|
||||||
|
// user-controlled argument) was inserted into the HTML output
|
||||||
|
// unescaped. A crafted alphabet whose Base64 image starts with
|
||||||
|
// `<script>...` could land directly in the rendered output and
|
||||||
|
// be eval'd by OutputWaiter.mjs. The fix runs the unescaped
|
||||||
|
// path through Utils.escapeHtml; this test pins that the raw
|
||||||
|
// `<script>` substring no longer appears verbatim and instead
|
||||||
|
// appears as the HTML-encoded `<script>`.
|
||||||
|
name: "Show Base64 offsets: HTML escapes static output (#2344)",
|
||||||
|
input: "ABCDEFGHIJKDGLMNAOBCDEFGHPPP",
|
||||||
|
// alphabet chosen so toBase64(input, alphabet) starts with
|
||||||
|
// "<script>"; recipe also passes showVariable=false so the
|
||||||
|
// staticSection is the bare offset0/1/2 reused as raw text.
|
||||||
|
expectedMatch: /<script>|<\/script>/,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Show Base64 offsets",
|
||||||
|
args: [
|
||||||
|
"<script>ale(1)/.ABCDEFGHIJKLMNOPQRSTUVWXYZbdfghjkmnoquvwxyz023456",
|
||||||
|
false,
|
||||||
|
"Raw",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Sanity: the showVariable=false output for a benign alphabet
|
||||||
|
// still produces something that contains the expected offsets
|
||||||
|
// header. This guards against the fix accidentally breaking
|
||||||
|
// the happy path.
|
||||||
|
name: "Show Base64 offsets: benign alphabet still renders Offset 0",
|
||||||
|
input: "Hello, world!",
|
||||||
|
expectedMatch: /Offset 0:/,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Show Base64 offsets",
|
||||||
|
args: [
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
|
||||||
|
false,
|
||||||
|
"Raw",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
Loading…
x
Reference in New Issue
Block a user