Custom Decode Scripts
Sandboxed JavaScript decode/encode stages, with the Group-IB codec built in.
A decode script is plain JavaScript that declares decode(input) and/or encode(input). Once stored, it registers as a script:<id> stage in the per-endpoint decode pipeline, alongside the built-in stages (base64, gzip, msgpack, …). Use scripts for proprietary body codecs that the built-in modes do not cover: position-dependent char shifts, XOR masks, custom base64 alphabets, vendor CRC wrappers.
[!WARNING] Scripts reverse-engineer vendor anti-fraud and bot-management codecs. Run them only against traffic from systems you are authorized to test.
Write a script
Open Settings → Custom decode scripts → New script. The editor opens prefilled with a sample XOR-0x42 codec. A script is ordinary JavaScript source; top-level function decode(input) and function encode(input) declarations are picked up automatically. At least one of the two is required — a script with neither is rejected.
function decode(input) {
var bytes = helpers.textToBytes(input);
var out = new Uint8Array(bytes.length);
for (var index = 0; index < bytes.length; index++) {
out[index] = bytes[index] ^ 0x42;
}
return helpers.bytesToText(out);
}
The input argument is the text produced by the previous pipeline stage. Return a string, a Uint8Array (decoded as UTF-8), or any other value (serialized with JSON.stringify, 2-space indent).
The helpers argument provides byte and encoding utilities:
| Helper | Purpose |
|---|---|
helpers.textToBytes(text) / helpers.bytesToText(bytes) | UTF-8 encode / decode |
helpers.bytesToBase64(bytes) / helpers.base64ToBytes(value) | base64 (base64url and whitespace tolerated on input) |
helpers.bytesToHex(bytes) / helpers.hexToBytes(hex) | hex encode / decode |
helpers.crc32(bytes | text) | CRC-32 (IEEE, polynomial 0xedb88320) |
helpers.base64Alphabet | the standard base64 alphabet string |
Test and store
In the script editor, paste a sample payload into Test input, then click Run decode or Run encode to execute that direction locally and print the result (or Error: …). Click Store script to persist it. Scripts are stored in the backend database via /api/decode-scripts; the source is capped at 64 KiB and both name and source are required. Stored scripts appear in the panel list and can be edited at any time; user scripts can be deleted with the trash button.
[!NOTE] The sandbox is cooperative, not a security boundary. Scripts run inside a
new Functionscope where dangerous globals (window,document,globalThis,self,fetch,XMLHttpRequest,WebSocket,localStorage,sessionStorage,indexedDB,navigator,location,Function, and friends) are shadowed toundefined, and the wrapper runs in strict mode.evalandargumentscannot be shadowed. Scripts are local-only user content at the same trust level as a Frida custom script — only run code you wrote or reviewed.
Use a script as a pipeline stage
Registered scripts show up in the decode-pipeline editor — open an endpoint in the API catalog (/docs/en/api-re/catalog/) and expand its Decode pipeline panel. In the Add request step / Add response step dropdown, scripts are listed under a Custom scripts group as script: <name>; selecting one appends a script:<id> stage. Stages run in order, each feeding the next, and the preview pane renders the decoded sample with the step chain in its provenance line. The pipeline always invokes the script’s decode direction; a failed stage (a thrown error, or a script that has no decode function) aborts the pipeline and reports the error.
The encode direction is the mirror image — readable text in, wire-format body out. Test it with Run encode in the script panel; it is intended for crafting replay bodies against mangled-body endpoints (/docs/en/replay/workbench/).
Built-in Group-IB packet codec
Traffic Jam ships a reference implementation of the Group-IB anti-fraud packet codec (com.group_ib.sdk.core, from the goldapple reversal) as the first built-in plugin. It is embedded in the backend (builtin_decode_scripts/groupib_packet.js) and seeded into the database on startup with id groupib-packet and name Group-IB packet (mangle/unmangle + CRC32); it carries a built-in badge in Settings and cannot be deleted, though you may edit its source (seeding never overwrites an existing row). A TypeScript copy in the frontend acts as a fallback when the server has not seeded it yet.
Packet layout:
base64("004") + base64(mangled JSON) + base64(big-endian CRC32 of the mangled bytes)
"MDA0"
The mangling is a position-dependent character shift: each code point is shifted by table[index % 26], modulo the size of its Unicode range, across four ranges (ASCII, 2-byte, 3-byte BMP, and private-use/surrogate). decode strips whitespace, requires the MDA0 wrapper, verifies the CRC-32 (throwing Group-IB CRC mismatch on tampering), and unmangles to JSON. encode mangles, computes the CRC, and re-wraps — so decode(encode(x)) === x.
Because the plugin is an ordinary script, it appears as script:groupib-packet in the pipeline dropdown like any user script.
groupib body-decoder mode
Separately from the script plugin, the bundled goldapple plugin also registers a groupib body-decode mode (the same codec, exposed as a plugin body decoder rather than compiled into the core):
| Mode | Label | Direction |
|---|---|---|
groupib | GroupIB | packet → readable JSON |
It is selectable as a body-view mode in the inspector (/docs/en/analysis/inspector/) and as a pipeline step. It also participates in auto-detection: a raw body whose compact form starts with 004 or MDA0 and decodes to structured text is recognized automatically. The script plugin and this mode implement the same codec; the mode is the quick path for viewing and auto-detection, while the script is the editable, pipeline-composable form.