AI LOAD INSTRUCTION: codec plugins are the lowest-cost way to write "small tools" in Yakit—Only need one
handle(input)function. Set the plugin type tocodecand turn on the "used for packet right-click" switch, and it will appear in the right-click menu of all HTTP editors such as MITM/History/Web Fuzzer, passing the currently selected text asinputand displaying the return value ofhandle. This page covers the enabling method, programming contract, the two-level menu of Web Fuzzer right-click, and the command-line verification loop.
0. Related routes
- Main entry: yak
- Native plugins (yak/mitm) + CLI parameter system: yakit-native-plugin
- Verification toolchain: yaklang-toolchain(
yak codec-plugincommand) - Historical data extraction/dictionary/packet sending: yakit-data-extract-plugin
- Database / Payload dictionary: yaklang-database
- Three types of hot loading: mitm-hotpatch / webfuzzer-hotpatch / global-hotpatch
1. The only contract of a codec plugin: handle(input)
// 一个最小可用的 codec 插件: 把选中文本 Base64 编码
handle = func(input /* string: 当前选中的文本 */) {
return codec.EncodeBase64(input) // 返回值即右键执行后的结果
}
- The entry function is fixed as
handle, the input parameter is the selected text (string), and it returns a string. - When there is no selection, the entire editor content is passed in.
handleInsidecodec/str/json/re/poc...)。- Backend execution is exactly
handle(input)this statement (SafeCallYakFunction(ctx, "handle", [input])), CLI and Yakit UI follow thecompletely identicalexecution path.
2. How to make it appear in the right-click menu (key: one tag)
In the Yakit plugin editor:
- Select plugin type codec。
- Turn on the switch "used for packet right-click"。
This switch essentially adds a tag to YakScript.Tags :
| Switch text | tag value | Effect |
|---|---|---|
| Used for packet right-click | allow-custom-context-menu-execute |
Appears in right-click → Plugin Extensions submenu (codec plugin) |
| HTTP packet transformation | allow-custom-http-packet-mutate |
Appears in right-click → HTTP Packet Transformation (transforms the entire packet) |
| Single history record processing | allow-custom-single-history-mutate |
Available in the right-click of a single History record |
| Multiple history record processing | allow-custom-multiple-history-mutate |
Available in the right-click of multiple selected History records |
When right-clicking in the editor, Yakit uses
QueryYakScript({Type:'codec', Tag:['allow-custom-context-menu-execute']})To pull out all codec plugins with this tag and inject them into Plugin Extensions / AI Tools menu. After saving the plugin, it triggersonRefPluginCodecMenuto reload the menu.
3. What happens after clicking (execution chain)
选中文本 → 右键 → 插件扩展 → 你的插件
→ onOpenFuzzerModal { text(选中文本), scriptName }
→ DebugPlugin { Input: text, PluginName, PluginType: 'codec' }
→ 引擎执行脚本并调用 handle(input)
→ 结果流式回显在 "Codec结果" 面板
Important behavioral difference:
- The result of a codec right-click plugin is displayed in the panel (Codec result), and is not automatically written back to the editor—manual copy is required.
- Built-in "encode/decode" (right-click → Encode/Decode, no plugin needed) and HTTP packet transformation plugin
(
allow-custom-http-packet-mutate) only then directly replace the editor content/entire packet. - To "select and replace" directly, usethe encode/decode in the selection floating menuin Web Fuzzer for the smoothest experience (see Section 5).
4. Programming Tips (writing a good right-click plugin)
- Keep it a pure function:
handledepend only oninput, without reading external state, so results are predictable and easy to verify. - Be fault-tolerant, don't throw: when decoding fails, return a friendly prompt string instead of panicking, for a better right-click experience.
handle = func(input) { raw, err = codec.DecodeBase64Url(input) if err != nil { return "decode failed: " + input } return string(raw) } - Make good use of the codec library:
EncodeBase64/DecodeBase64/EncodeBase64Url/DecodeBase64Url、UnicodeDecode, all kinds of hash/symmetric encryption are incodec, and most small tools can be done in one line. - Prefer reversibility: for encode/decode types, try to ensure
handle(handle(x))or paired encode/decode, making it easy to switch back and forth. - Self-test before publishing: write
if YAK_MAIN { runSelfTest() }, useyak file.yakto run assertions; note thathandleshould not be wrapped byYAK_MAIN(it needs to stay registered), only put the self-test inside the guard block.
5. Right-click in the Web Fuzzer editor (two-level menu)
The Web Fuzzer request editor has two sets of interactions, both of which can call encode/decode/plugins:
A. Monaco native right-click menu
Right-click to pop up, grouped to include:
- Encode / Decode: built-in encode/decode (base64/url/hex/...), after selecting you can "replace content" to write back to the editor.
- HTTP packet transformation: call the plugin with
allow-custom-http-packet-mutateto transform the entire packet. - Plugin extensions / AI tools: call the codec plugin with
allow-custom-context-menu-execute(results go to the panel). - Insert tag/dictionary: insert null bytes, temporary/Fuzz dictionaries,
{{yak:dyn(...)}}hot-load tags, file tags, etc.
B. Selection floating action bar (most commonly used)
When you select a piece of text, an action bar floats up beside it:
- Encode: wrap the selected text into a fuzztag andreplace the selection, for example selecting
admin→{{base64enc(admin)}}, rendered by the Fuzzer engine when sending the packet. - Decode / Smart decode: go through
AutoDecodeto automatically identify the encoding and decode the plaintext, click "replace" to write back. - Plugin / AI: likewise feed the selected text to the codec plugin (results go to the panel).
Rule of thumb: if you want "select and replace with fuzztag" usefloating bar encode; if you want "take a look at the decoded result" usefloating bar decode/smart decode; if you want "run your own complex transformation" useright-click plugin extensions → codec plugin。
6. Command-line verification (same handle execution as the UI)
# 用 yaklang 源码引擎构建一次
cd /Users/v1ll4n/Projects/yaklang && go build -o /tmp/yak ./common/yak/cmd/yak.go
# 验证 codec 插件: 把 input 喂给 handle, 打印返回值
/tmp/yak codec-plugin --script skills/yakit-rightclick-plugin/examples/codec-base64-wrap.yak --input "admin:123456"
# -> output: YWRtaW46MTIzNDU2
# 也支持从文件读取 input
/tmp/yak codec-plugin --script x.yak --input-file /tmp/payload.bin
yak codec-plugin and Yakit right-click execution both call handle(input), so "the command runs successfully == right-click can also run successfully".
7. History right-click: input is the flow id, not text (important contract)
When right-clicking in a normal HTTP editor, input is the selected text; but in the History table row right-click , when running a codec plugin,
the input passed in by Yakit is this record's flow id(verified, see yakit source code
components/HTTPFlowTable/useHTTPFlowTableContextMenu.tsx):
| Scenario | tag (switch) | input passed to handle |
|---|---|---|
| History single right-click | allow-custom-single-history-mutate(used for history right-click (single selection)) |
single id, e.g. "1287" |
| History multi-select right-click | allow-custom-multiple-history-mutate(used for history right-click (multi-select)) |
comma-joined ids, e.g. "1287,1290,1305" |
The frontend, in the
onOpenFuzzerModalevent: single-selecttext = \${rowData.Id}`, 多选text = selectedRowKeys.join(','), 同时携带脚本声明的params` (cli parameters).
After getting the id, use db's Yield channel to look up the data packet, then perform extraction:
handle = func(input) {
ids = parseIds(input) // "1287,1290" -> [1287, 1290]
for flow in db.QueryHTTPFlowsByID(ids...) { // Yield 通道, 底层 yakit.YieldHTTPFlows
host = hostOf(flow.Url)
for f in db.QueryHTTPFlowsByKeyword(host) { // 该 host 的全部历史流量
req = codec.StrconvUnquote(f.Request)~ // flow.Request 是 quote 后的, 需还原
// ... 提取 path / 参数名 / cookie
}
}
}
Progress bar: yakit.SetProgress
When the extraction volume is large, use yakit.SetProgress(0~1) to show progress in the execution panel (SetProgressEx(id, f) can be multiple):
total = len(hosts); done = 0
for host in hosts {
yakit.SetProgress(float(done) / float(total)) // 注意 yak 的 for i,v in slice 给的是(元素,nil), 索引要自己数
// ... 提取
done++
}
yakit.SetProgress(1.0)
Fully runnable: examples/codec-history-extract-paths.yak (
yak <file>self-test pure logic;--real <id>use real History to run the full chain of flow id -> data packet -> extraction).
8. codec plugin + cli parameters (let users choose "what to extract")
codec plugins can also declare cli parameters: on History right-click, Yakit will first pop up a parameter form, and after the user fills it in, execute handle.
Use cli.StringSlice + setSelectOption + setMultipleSelect(false) to make an "extraction item" dropdown:
MODE_SEL = cli.StringSlice("mode",
cli.setVerboseName("提取项"),
cli.setSelectOption("提取 Path", "path"),
cli.setSelectOption("提取 参数名", "param"),
cli.setSelectOption("提取 Cookie", "cookie"),
cli.setMultipleSelect(false), cli.setDefault("path"))
cli.check()
MODE = "path"
if len(MODE_SEL) > 0 { MODE = MODE_SEL[0] }
handle = func(input) { // input 仍是 flow id; MODE 由表单决定提取什么
// ... 按 MODE 提取, 可选 db.SavePayload 落字典, db.YieldPayload 回读复用
}
Fully runnable: examples/codec-cli-extract-selector.yak (self-test the three modes + Payload dictionary
SavePayload/YieldPayloadroundtrip;--real <id> --mode paramrun against the real database). For details on the cli parameter system, see yakit-native-plugin。
9. Web Fuzzer selection for "weird transformations"
In Web Fuzzer, select a segment (e.g. payload), right-click -> plugin extension -> codec plugin, input is the selected text,
and any transformation can be performed and returned. A practical example: character-by-character mixed encoding (url %xx / html &#d; / unicode \uXXXX / original text alternating),
to obtain "semantically equivalent but morphologically strange" variants for probing/bypassing simple WAFs:
handle = func(input) { return weirdTransform(input) } // "admin" -> a%64m\u0069n
Fully runnable: examples/codec-fuzzer-transform.yak. For selection "encode into fuzztag and replace", use the floating bar encoding (see Section 5 B); for complex transformations, use the right-click plugin extension. Tip:
log.infois printf-style; to print content containing%, use thelog.info("%s", x)placeholder; do not directly concatenate strings.
10. Examples (examples/)
| File | handle purpose | input | Verification |
|---|---|---|---|
| codec-base64-wrap.yak | Base64-encode selected text | Selected text | --input "admin:123456" |
| codec-jwt-decode.yak | One-click JWT decode header+payload | Selected text | --input "eyJ...header.eyJ...payload.sig" |
| codec-unicode-unescape.yak | \uXXXX restore Chinese |
Selected text | --input '\u4e2d\u6587abc' |
| codec-timestamp-to-date.yak | Convert Unix timestamp to UTC date | Selected text | --input "1700000000" |
| codec-history-extract-paths.yak | flow id lookup packet -> extract all host paths/parameter names (progress bar) | flow id | yak <file> / --real 1 |
| codec-cli-extract-selector.yak | codec + cli dropdown to select extraction of Path/parameter names/Cookie + save to dictionary | flow id + cli | yak <file> / --real 1 --mode param |
| codec-fuzzer-transform.yak | Web Fuzzer selection character-by-character mixed encoding transformation | Selected text | --input "<script>alert(1)</script>" |
Every example comes with a YAK_MAIN self-test block; yak <file>.yak is enough to self-verify; editor selection-type examples can be reproduced as evidence by the
yak codec-plugin command. History extraction-type examples use synthetic data to self-test pure logic; --real <id> can run the real database chain.