AI LOAD INSTRUCTION: This is the "module-level MITM" topic in the Yaklang three-tier hot patch system. MITM hot patching allows security testers to dynamically take over each processing stage of HTTP traffic with Yaklang code without interrupting the proxy service. First read the Hook trigger timing table and the forward/drop semantics on this page, then look at
examples/the examples named by Hook below; each example can be self-tested directly withyak <file>.
0. Related Routes
- Main entry and the three-tier system:yak
- Web Fuzzer hot patch (single-Tab request encryption/decryption/retry):webfuzzer-hotpatch
- Global hot patch (system-wide hook that executes before modules):global-hotpatch
1. The Three Basic Roles
Before understanding Hooks, first understand the three parties of MITM:
flowchart LR
Browser["MITM 客户端 (浏览器/App/脚本)"] --> Proxy["MITM 代理 (Yakit)"]
Proxy --> Server["目标服务器"]
Server --> Proxy
Proxy --> Browser
- Browser: the side that directs traffic to Yakit (browser, mobile app, automation script).
- MITM proxy (Yakit): receives requests, can modify or drop them, then forwards to the target; after getting the response it can also modify it again and write it back to the client. All Hooks are attached inside the proxy.
- Target server: the actual backend.
2. The Three Major Hook Categories and Trigger Timing
Yakit MITM divides Hooks into three categories: request-response hijack category (synchronous and serial, can modify or drop), mirror category (observe and analyze only), and packet storage processing category.
| Hook | Trigger Timing | Can Rewrite | Submission Method |
|---|---|---|---|
hijackHTTPRequest(isHttps, url, req, forward, drop) |
After the browser initiates the request, before it is sent to the target (the main request interception point) | Yes | forward(req) / drop() |
hijackHTTPResponse(isHttps, url, rsp, forward, drop) |
After receiving the target response, before writing it back to the client | Yes | forward(rsp) / drop() |
hijackHTTPResponseEx(isHttps, url, req, rsp, forward, drop) |
Same as above, but simultaneously gets req (recommended) | Yes | forward(rsp) / drop() |
beforeRequest(isHttps, oreq, req) |
The last moment before the request goes out (after hijackHTTPRequest) | Yes (return-value submission) | return req |
afterRequest(isHttps, oreq, req, orsp, rsp) |
The last moment before the response is written back (after hijack response) | Yes (return-value submission) | return rsp |
mirrorHTTPFlow(isHttps, url, req, rsp, body) |
After each request-response completes (including all traffic) | No, observe only | None |
mirrorFilteredHTTPFlow(isHttps, url, req, rsp, body) |
Only traffic that passes the filter rules | No, observe only | None |
mirrorNewWebsite(isHttps, url, req, rsp, body) |
New domain discovered (once per domain) | No, observe only | None |
mirrorNewWebsitePath(isHttps, url, req, rsp, body) |
New path discovered (once per same domain and same path) | No, observe only | None |
mirrorNewWebsitePathParams(isHttps, url, req, rsp, body) |
New parameter combination discovered (structural deduplication) | No, observe only | None |
hijackSaveHTTPFlow(flow, modify, drop) |
The last step before storing into History | Yes (modify flow) | modify(flow) / drop() |
mockHTTPRequest(isHttps, url, req, mockResponse) |
Before the request goes out, a local response can be used as a substitute | Yes (substitute response) | mockResponse(rspStr) |
forward / drop semantics (the core of the hijack category)
forward(req|rsp): release the (possibly rewritten) packet. Hijack-category hooks mustcall forward or drop for each packet, otherwise the request is suspended.drop(): Drop the packet.- Even when the target is not hit,
forward(原始包), ensuring the remaining traffic and subsequent plugins continue processing.
Special characteristics of beforeRequest / afterRequest
Here "Request" follows the Burp/Zap convention, referring to the entire round trip of "browser sends request → proxy forwards → proxy receives response".
beforeRequest: the last chance to modify the request before it goes outbound, submitted via the return value ; modifications are invisible to the user hijacking interface.afterRequest: the last chance to modify the response before it is written back, also submitted via the return value.
3. mirror deduplication semantics (important)
When accessing the following sequence:
http://a:8080/abc/ http://a:8080/abc/12 http://a:8080/abc/13
http://a:8080/abc/14 http://a:8080/abc/14?x=1 http://b:8080/abc/14
mirrorNewWebsite: triggered 2 times (domaina:8080、b:8080once each).mirrorNewWebsitePath: triggered 5 times (a:80804 different paths under it +b:8080/abc/14;/abc/14?x=1with query is still/abc/14not duplicated).mirrorNewWebsitePathParams: deduplicated by query parameter structure (same parameter name with different values does not trigger repeatedly).
4. Index of all Hook examples (examples/, one example per function)
In the tableeach Hook has an independent example + YAK_MAIN self-test,yak <file> to self-verify; see the evidence in scripts/validate-skills.yak。
| Hook | Example scenario | File |
|---|---|---|
hijackHTTPRequest |
Modify JSON business field (amount) before outbound | examples/hijack-request.yak |
hijackHTTPResponse |
Add security headers and erase version numbers based only on the response | examples/hijack-response.yak |
hijackHTTPResponseEx |
Delete blocking JS (alert/redirect) while keeping the debug page | examples/hijack-response-ex.yak |
beforeRequest |
Inject the Trace header last before outbound (submitted via return value) | examples/before-request.yak |
afterRequest |
Add a debug marker before write-back (submitted via return value) | examples/after-request.yak |
mirrorHTTPFlow |
Passive scanning of all traffic for sensitive information leakage | examples/mirror-http-flow.yak |
mirrorFilteredHTTPFlow |
Statistics by content type only for filtered traffic | examples/mirror-filtered-http-flow.yak |
mirrorNewWebsite |
New domain discovery → asset inventory | examples/mirror-new-website.yak |
mirrorNewWebsitePath |
New path discovery and deduplicated collection | examples/mirror-new-website-path.yak |
mirrorNewWebsitePathParams |
New parameter combination discovery → Fuzz target selection | examples/mirror-new-website-path-params.yak |
hijackSaveHTTPFlow |
Tag and color sensitive words before storage | examples/hijack-save-http-flow.yak |
mockHTTPRequest |
Mock guardrail for dangerous operations (DELETE/PUT) | examples/mock-http-request.yak |
5. Standard pattern: hook function + YAK_MAIN self-test
All MITM hot-load scripts share a unified structure—register the hook as a function variable, then use if YAK_MAIN { runSelfTest() } to guard the local self-test:
hijackHTTPRequest = func(isHttps, url, req, forward, drop) {
// ... 命中目标则改写, 未命中也要 forward 原包
forward(req)
}
func runSelfTest() {
// 用自定义 forward/drop callback 捕获结果并 assert
}
if YAK_MAIN {
runSelfTest()
}
YAK_MAIN is a global boolean injected by the engine:
yak xxx.yakRun from the command line:YAK_MAIN = true, runrunSelfTest()for mock self-test.- Loading in the yakit MITM hot-load window:
YAK_MAIN = false, the self-test block does not execute, only the hook is registered.
Therefore, pasting the complete script including the self-test block back into yakit is absolutely safe.
Concurrency and global variables (important, avoid crashes): MITM will concurrently call the same hook. Treat top-level global variables as read-only constants(keys/IV/rule tables assigned once at load time, never modified inside the hook).Do not write shared mutable globals inside the hook(bare
appendglobal slice, assigning to a global map will trigger a data race and directly panic). When cross-request aggregation is needed, usesync.Map/sync.NewMutex()ordb.*/risk.*to persist to the database; in this library, the global accumulation in themirror-*examples is only a single-threaded command-line self-test demonstration pattern. See details in webfuzzer-hotpatch Section 6。
Self-test mock methods for each Hook
| Hook | Self-test verification methods |
|---|---|
hijackHTTPRequest / hijackHTTPResponseEx |
Custom forward/drop callback, assert on captured packet contents |
mirror* |
Directly call the hook and assert changes to outer state (set/slice/coloring fields) |
hijackSaveHTTPFlow |
Use map to simulate *HTTPFlow,stub AddTag/color methods, verify that modify(flow) is called |
mockHTTPRequest |
Custom mockResponse callback, verify target triggers and non-target does not |
6. Common API quick reference
| Purpose | API |
|---|---|
| Get request/response body | poc.GetHTTPPacketBody(packet) |
| Replace body | poc.ReplaceHTTPPacketBody(packet, newBody) |
| Get/replace header | poc.GetHTTPPacketHeader(packet, key) / poc.ReplaceHTTPPacketHeader(packet, key, val) |
| Get request method | poc.GetHTTPRequestMethod(req) |
| Get response status code | poc.GetStatusCodeFromResponse(rsp) |
| flow original text | codec.StrconvUnquote(flow.Request)~ / codec.StrconvQuote(str) |
| Actively send packet | poc.HTTP(raw, poc.https(b), poc.timeout(5), poc.save(false))~ |
7. Verification
cd /Users/v1ll4n/Projects/yaklang
go run common/yak/cmd/yak.go skills/mitm-hotpatch/examples/hijack-request.yak
# 或已安装引擎: yak skills/mitm-hotpatch/examples/hijack-request.yak
# 用与 Yakit gRPC 同款执行路径在真实请求上验证:
go build -o /tmp/yak ./common/yak/cmd/yak.go
printf 'POST /api/order/create HTTP/1.1\r\nHost: shop.example.com\r\nContent-Type: application/json\r\n\r\n{"amount":100}' > /tmp/req.txt
/tmp/yak hotpatch-mitm --script skills/mitm-hotpatch/examples/hijack-request.yak --request /tmp/req.txt
Each example should: complete within 10 seconds, pass all asserts, log entirely in English, and finally show ... self test passed。
References
- yak-project-public 031 (2025-10-17) Full analysis of MITM hot-loading workflow: a breakdown of four practical Hook function scenarios
- yak-project-public 030 (2025-10-24) Yakit hot-loading practical tips
- yak-project-public 024 (2025-12-05) Mock reshaping pollution-free client testing
- Engine implementation:
common/yak/hook_mixed_plugin_caller.go