A section MITM proxy that lets you power TLS fingerprints (JA3/JA4), HTTP/2 fingerprints, HTTP header order, User-Agent, and root IP headers — each from a azygous YAML config file.
A Chrome extension is included for toggling the proxy and switching fingerprint profiles straight from the browser toolbar without restarting the proxy.
Intended for authorized information testing of WAF bot-detection systems. Route curl, browsers, aliases Playwright done the proxy to observe really different fingerprint combinations are classified.
| TLS | Cipher suites, extensions, their bid (JA3 / JA4) via uTLS presets aliases a afloat civilization custom_hello spec |
| HTTP/1.1 | Header order, User-Agent, add/remove immoderate header, IP spoofing (X-Forwarded-For / True-Client-IP) |
| HTTP/2 | SETTINGS values & order, WINDOW_UPDATE, pseudo-header bid (HTTP/2 fingerprint) |
- macOS aliases Linux (amd64 / arm64)
- Go 1.22+
The distro-packaged Go is often outdated. Install the charismatic binary directly:
Verify:
ARM64 (Raspberry Pi, AWS Graviton, etc.): switch linux-amd64 pinch linux-arm64 successful the download URL.
2. Generate the MITM CA certificate
The CA is generated automatically connected first run. Start the proxy erstwhile to create ca.crt and ca.key:
Stop it pinch Ctrl-C.
3. Trust the CA certificate
Clients request to spot your MITM CA truthful they don't cull the proxy-generated leafage certificates.
macOS strategy keychain (affects each apps):
Linux strategy trust (affects each apps; requires ca-certificates package):
curl only (no system-wide change):
Playwright / Node.js:
Firefox: Preferences → Privacy & Security → View Certificates → Authorities → Import ca.crt
Edit config.yaml earlier starting the proxy. All fields person defaults — you only request to specify what you want to override.
When the proxy starts it besides exposes a lightweight HTTP API connected mgmt_listen (default 127.0.0.1:8081). The Chrome hold uses this to publication and update settings astatine runtime without restarting the proxy. You tin besides telephone it straight pinch curl:
| /api/config | GET | Return progressive settings arsenic JSON, including the existent custom_hello |
| /api/config | POST | Update TLS preset (including a afloat civilization custom_hello), customer IP, and User-Agent |
Changes return effect instantly for caller connections. Set mgmt_listen: "" to disable the API entirely.
Browser fingerprint reference
| Chrome | chrome | 1:65536,2:0,4:6291456,6:262144 | 15663105 |
| Firefox | firefox | 1:65536,4:131072,5:16384 | 12517377 |
| Safari | safari | 1:4096,3:100,4:2097152,6:16384 | 10485760 |
Custom TLS fingerprint (preset: "custom")
The built-in presets (chrome, firefox, safari, …) screen the astir communal cases. When you request to lucifer a circumstantial browser type aliases a fingerprint that differs from those presets, group preset: "custom" and supply a custom_hello block.
How JA3 / JA4 representation to config fields
| TLS type range | versions | Min/max are derived automatically |
| Cipher suite database + order | cipher_suites | Use 0x0a0a arsenic a GREASE placeholder; uTLS randomises it per connection |
| Extension type IDs + order | extensions | Order straight controls the JA3 extensions component; values matching the GREASE shape (0xXAXA) are randomised per connection |
| Supported groups (curves) | curves | Also controls which cardinal shares are sent |
JA3 and JA4 are one-way hashes — you cannot reverse a hash backmost to a spec. Find the underlying parameters for the target browser pinch tls.peet.ws aliases Wireshark, past paste them into custom_hello.
Chrome 131 example
Supported hold type IDs
| 0xXAXA (any GREASE pattern) | GREASE | Randomised per connection |
| 0 | server_name (SNI) | |
| 5 | status_request | OCSP stapling |
| 10 | supported_groups | Uses the curves list |
| 11 | ec_point_formats | Fixed: uncompressed (0) |
| 13 | signature_algorithms | Chrome-like defaults |
| 16 | ALPN | Advertises h2, http/1.1 |
| 18 | signed_certificate_timestamp | |
| 21 | padding | BoringSSL-style padding |
| 23 | extended_master_secret | |
| 27 | compress_certificate | |
| 28 | record_size_limit | Fixed: 0x4001 |
| 35 | session_ticket | |
| 43 | supported_versions | Uses the versions list |
| 45 | psk_key_exchange_modes | PSK pinch DHE |
| 50 | signature_algorithms_cert | Chrome-like defaults |
| 51 | key_share | Key shares for X25519 and P256 (from curves) |
| 17513 | application_settings (ALPS) | Advertises h2 |
| 65281 | renegotiation_info | |
| other | GenericExtension | Sent pinch quiet payload |
Runtime updates: preset: "custom" is not constricted to config.yaml — it tin besides beryllium switched to astatine runtime via the guidance API (POST /api/config pinch a custom_hello object, spot Management API) aliases from the Chrome extension's TLS Preset dropdown, without restarting the proxy.
To move fingerprint profiles, edit config.yaml and re-run make run.
The chrome-extension/ directory contains a Manifest V3 hold that controls the proxy from the browser toolbar.

Installation:
- Open chrome://extensions successful Chrome
- Enable Developer mode (toggle successful the top-right corner)
- Click Load unpacked and prime the chrome-extension/ folder
Controls:
| Proxy toggle | Enables / disables Chrome's proxy mounting (routes postulation done :8080) |
| TLS Preset | Switches the uTLS fingerprint preset (chrome / firefox / safari / separator / ios / random / golang / custom) |
| Cipher Suites / Curves / TLS Versions / Extensions | Shown erstwhile Custom (JA3/JA4) is selected — the aforesaid fields arsenic custom_hello successful config.yaml, letting you dial successful an arbitrary JA3/JA4 fingerprint without editing YAML aliases restarting the proxy |
| Client IP | Sets X-Forwarded-For and True-Client-IP connected each request |
| User-Agent | Overrides the HTTP User-Agent header |
| Apply button | POSTs the caller settings to the guidance API; takes effect immediately |
| API field | Address of the guidance API (default http://127.0.0.1:8081) |
User-Agent scope: The hold changes the HTTP User-Agent header only. JavaScript's navigator.userAgent is controlled by Chrome itself and is not affected. To spoof some simultaneously, motorboat Chrome pinch --user-agent="..." alongside the proxy settings.
Set NODE_EXTRA_CA_CERTS (Node) aliases REQUESTS_CA_BUNDLE (Python) if the CA is not trusted system-wide.
tls.peet.ws returns the afloat fingerprint breakdown for immoderate petition it receives. Pipe the output done jq aliases Python for a readable view:
Key fields to check:
| tls.ja3_hash | JA3 fingerprint hash |
| tls.ja4 | JA4 fingerprint string |
| http2.akamai_fingerprint | HTTP/2 fingerprint drawstring (SETTINGS + WINDOW_UPDATE + pseudo-header order) — section sanction is defined by the tls.peet.ws API |
| http1.headers | Header names successful the bid received by the server |
| user_agent | User-Agent arsenic seen by the server |
| ip | Source IP arsenic seen by the server — verify X-Forwarded-For / True-Client-IP spoofing here |
| make build | Compile the binary |
| make run | Build, termination immoderate existing instance, and start |
| make trust-ca | Add ca.crt to the macOS strategy keychain (requires sudo) |
| make clean | Remove the binary, ca.crt, and ca.key |
Remove the binary and generated CA files:
If you added the CA to the macOS strategy keychain, region it done Keychain Access (search for "impersonate-proxy CA") or:
- MITM only: The proxy decrypts and re-encrypts traffic. Clients must spot the generated CA.
- No HTTP/2 from client: The client→proxy limb uses HTTP/1.1 (via CONNECT). Only the proxy→server limb uses HTTP/2 pinch civilization fingerprints.
- Chunked petition bodies: Requests pinch Transfer-Encoding: chunked bodies are not presently supported.
- No QUIC / HTTP/3: Out of scope.
- User-Agent (HTTP header only): The proxy rewrites the User-Agent HTTP header, but JavaScript's navigator.userAgent is group by the browser independently and is unaffected. Use Chrome's --user-agent motorboat emblem to override some simultaneously.
This instrumentality is intended for authorized information testing only — for example, testing WAF and bot-detection configurations connected systems you ain aliases person definitive written support to test.
Using this instrumentality against systems without authorization whitethorn break applicable laws (such arsenic the Computer Fraud and Abuse Act, Japan's Unauthorized Computer Access Law, aliases balanced authorities successful your jurisdiction) and the position of work of the target.
The authors judge nary liability for misuse.
- uTLS — TLS fingerprint customization
- tls.peet.ws — Fingerprint inspection API utilized successful examples
- JA4+ — Fingerprinting modular reference
English (US) ·
Indonesian (ID) ·