A single Go binary that makes outgoing HTTPS connections look exactly like OneDrive.exe (or other Windows apps) at the TLS layer. Every part of the Client Hello -- cipher suites, extensions, signature algorithms, extension order -- matches a real Windows 11 SChannel TLS 1.3 handshake.
Optionally chain through TREVORproxy for IPv6 source address rotation from a /64 subnet.
single Go binary
┌──────────────────────┐
Client ──HTTP──▶ │ ja4proxy │ ──uTLS──▶ Target
curl / Python │ profiles embedded │ (sees OneDrive JA4)
└──────────┬───────────┘
│ optional
▼
TREVORproxy SOCKS5
(IPv6 /64 rotation)
- ja4proxy is a ~12 MB static binary with 6 YAML TLS profiles compiled in. No Python, no runtime deps.
- TREVORproxy is only needed for IPv6 source rotation. Without it, the proxy connects directly.
# Build
go build -o ja4proxy
# See all profiles
./ja4proxy -list
# Run (default profile: onedrive)
./ja4proxy
# Test via X-Target-URL
curl -H "X-Target-URL: https://tls.browserleaks.com/json" http://127.0.0.1:8443/
# Test via CONNECT
curl -x http://127.0.0.1:8443 https://tls.browserleaks.com/json
# Verify fingerprint
./ja4proxy -profile onedrive -verifyAll profiles are embedded YAML files in profiles/. The -profile flag accepts any name or alias.
| Name | Alias | JA4 | Description |
|---|---|---|---|
schannel_tls13_win11 |
onedrive |
t13d2013h2_2b729b4bf6f3_e24568c0d440 |
OneDrive.exe Windows 11 SChannel TLS 1.3 |
schannel_tls12_telemetry |
onedrive-telemetry |
t12d180800_4b22cbed5bed_7af1ed941c26 |
Watson telemetry TLS 1.2 |
schannel_tls12_pss |
schannel_tls12 |
t12d180700_4b22cbed5bed_2dae41c691ec |
.NET Framework / SChannel TLS 1.2 with RSA-PSS |
edge_legacy_schannel |
edge_legacy |
t12d1810h2_4b22cbed5bed_27793441e138 |
Legacy Edge (EdgeHTML) SChannel TLS 1.2 |
edge_chromium |
t13d1516h2_8daaf6152771_e5627efa2ab1 |
Edge/Chrome (BoringSSL) | |
winhttp_tls12 |
winhttp |
t12d210800_76e208dd3e22_16bbda4055b2 |
WinHTTP native Win32 TLS 1.2 |
./ja4proxy [flags]
-addr string Listen address (default "127.0.0.1:8443")
-profile string Profile name or alias (default "onedrive")
-profiles-dir path Load profiles from directory instead of embedded
-socks string SOCKS5 upstream (e.g. "127.0.0.1:1080")
-list List profiles and exit
-verify Hit tls.peet.ws and compare actual vs expected JA4
For production use with IPv6 rotation on a Linux server.
- Linux server with a routed IPv6 /64 subnet
- Go 1.21+ on your build machine
- TREVORproxy on the server (or any SOCKS5 proxy on
:1080)
GOOS=linux GOARCH=amd64 go build -o ja4proxy_linux_amd64
scp ja4proxy_linux_amd64 root@your-server:/srv/ja4proxy/Terminal 1 -- start TREVORproxy:
trevorproxy subnet -s 2001:db8:abcd:1234::/64 -i eth0Terminal 2 -- start ja4proxy chained through SOCKS:
/srv/ja4proxy/ja4proxy_linux_amd64 \
-addr 0.0.0.0:8443 \
-socks 127.0.0.1:1080 \
-profile onedrive# Check JA4 fingerprint
curl -s -H "X-Target-URL: https://tls.browserleaks.com/json" http://127.0.0.1:8443/ \
| python3 -c "import sys,json; print('JA4:', json.load(sys.stdin)['ja4'])"
# Expected: t13d2013h2_2b729b4bf6f3_e24568c0d440
# Check IPv6 rotation
for i in 1 2 3; do
curl -s -H "X-Target-URL: https://api64.ipify.org" -H "Connection: close" http://127.0.0.1:8443/
echo
done
# Expected: different IPv6 addresses from your /64| Service | URL | Returns |
|---|---|---|
| tls.browserleaks.com | https://tls.browserleaks.com/json |
ja4, ja4_r, ja4_o, ja3 |
| tls.peet.ws | https://tls.peet.ws/api/all |
ja4, ja4_r, ja3 |
Create a YAML file in profiles/ and rebuild:
name: my_profile
aliases: [myalias]
description: "My custom TLS profile"
ja4: "t13d..."
tls_min_version: "1.2"
tls_max_version: "1.3"
cipher_suites:
- 0x1302 # TLS_AES_256_GCM_SHA384
- 0x1301 # TLS_AES_128_GCM_SHA256
supported_groups: [x25519, p256, p384]
ec_point_formats: [uncompressed]
signature_algorithms:
- 0x0804 # rsa_pss_rsae_sha256
alpn: [h2, http/1.1]
# Extension order matters for JA4
extensions:
- sni
- status_request
- supported_groups
- ec_point_formats
- signature_algorithms
- alpn
- extended_master_secret
- session_ticket
- supported_versions
- psk_key_exchange_modes
- key_share
- renegotiation_infoOr load at runtime without rebuilding: ./ja4proxy -profiles-dir /path/to/profiles/
JA4 doesn't match -- Make sure traffic goes through the Go proxy, not directly through SOCKS. Verify with ./ja4proxy -verify or curl through the proxy to a fingerprint echo service.
IPv6 same address every time -- HTTP keep-alive reuses connections. Add -H "Connection: close" to force new TCP per request.
SOCKS connection refused -- Check TREVORproxy is running: ss -tlnp | grep 1080
Permission denied on AnyIP route -- TREVORproxy needs root for ip route add local.
- uTLS by Refraction Networking
- TREVORproxy by blacklanternsecurity (GPL-3.0)
- JA4 fingerprint database: ja4db.com