Skip to content

Releases

impersonate-mcp 0.1.0

Choose a tag to compare

@github-actions github-actions released this 08 Nov 07:40

Full Changelog: v1.5.0...mcp-v0.1.0

v1.5.0 — Optional MCP server

Choose a tag to compare

@ytkoka ytkoka released this 07 Nov 15:46

Highlights

Optional MCP server (impersonate-mcp/)

A new stdio MCP server, built on the official Go SDK, lets an AI agent configure the proxy and verify the result. It is a plain client of the existing management API, so the proxy itself is unchanged.

Tool What it does
get_config Show the active runtime settings
set_tls_preset Switch the TLS preset (chrome, firefox, safari, …)
set_custom_hello Set an arbitrary ClientHello and switch to the custom preset
set_user_agent Set the User-Agent ("auto" derives it from the preset)
set_client_ip Set the spoofed client IP
set_upstream Enable/disable the upstream proxy and select one by name
verify_fingerprint Fetch tls.peet.ws/api/all through the proxy and summarise ja3_hash, ja4, akamai_fingerprint, user_agent and ip
  • --read-only exposes only get_config and verify_fingerprint.
  • The management API URL, proxy URL, CA certificate and echo endpoint can be set by flag or environment variable (IMPERSONATE_MGMT_URL, …).
  • verify_fingerprint warns when the host filter excludes the echo host, since the result would not be impersonated.

Opt-in, no impact on existing setups

The MCP server is a separate Go module. make build and the Docker image are unchanged and do not include it. To use it:

make build-mcp   # → impersonate-mcp/impersonate-mcp
make test-mcp

Setup instructions, the full option list and notes are in the README (English / 日本語 / 简体中文): MCP server (optional).

Notes

  • The management API has no authentication, and the MCP server lets an agent change the proxy's settings. Keep mgmt_listen on loopback and use --read-only when the agent should only observe.
  • verify_fingerprint makes one request to an external service (tls.peet.ws by default).
  • The HTTP/2 fingerprint is controlled by http2 in config.yaml, not by the TLS preset.

Full changelog: v1.4.0...v1.5.0

v1.4.0

Choose a tag to compare

@ytkoka ytkoka released this 07 Nov 00:16

v1.4.0

Highlights

Host filter. The proxy can now impersonate only the targets you choose, instead of every host it sees.

filter:
  mode: "include"          # off (default) | include | exclude
  hosts:
    - "www.example.com"    # exact host
    - "*.example.com"      # any subdomain, but not example.com itself
  • include impersonates only the listed hosts, exclude impersonates everything except them, and off (the default) keeps the previous behavior.
  • Hosts that are not impersonated are passed through untouched. An HTTPS CONNECT is relayed as raw bytes without terminating TLS, so the client keeps seeing the origin's real certificate (no CA trust is needed for these hosts) and its own TLS fingerprint. Plain-HTTP requests are forwarded without header rewriting. Both still go through the upstream proxy when one is enabled.
  • The decision is made before a certificate is minted or a ClientHello is built, so a pass-through costs neither. It also means CONNECT to non-TLS ports works for hosts outside the filter.
  • Passed-through tunnels are logged as PASSTHROUGH host:port, which helps you find the CDN and challenge hosts a page loads and add them to the list.

Runtime control. filter_mode and filter_hosts are available through the management API (POST /api/config), and GET /api/config reports them. filter_hosts replaces the whole list, and changes apply to new connections only.

curl -s -X POST http://127.0.0.1:8081/api/config \
  -H "Content-Type: application/json" \
  -d '{"filter_mode":"include","filter_hosts":["www.example.com","*.example.com"]}'

Behavior notes

  • Matching: case-insensitive, port ignored. example.com matches exactly that host. *.example.com matches subdomains at any depth but not example.com, so list both to cover the apex. IP literals match exactly.
  • Validation: ports, paths, CIDR ranges and any other use of * are rejected, at startup and from the management API.
  • Atomic updates: POST /api/config now validates every part of a patch before applying any of it, with upstream_select applied last. A rejected patch changes nothing; previously an invalid value could leave an earlier field applied.
  • Upgrading: with the default mode: off, nothing changes. Existing configurations keep working without edits.

Known limitations

  • Plain-HTTP requests to hosts that are not impersonated are re-serialized by the proxy, so their header order is not preserved. HTTPS pass-through is relayed byte for byte.
  • A page usually loads other hosts too (CDNs, challenge scripts). Add them to the list, or the WAF will see a mix of impersonated and real fingerprints.
  • The Chrome extension has no UI for the filter yet; use config.yaml or the management API.
  • The limitations from earlier releases still apply (see the README's Limitations section), including ws:// through CONNECT for impersonated hosts.

Docker

docker pull ghcr.io/ytkoka/impersonate-proxy:1.4.0

The Chrome extension is unchanged in this release (still 1.2.0).

Full changelog: v1.3.0...v1.4.0

v1.3.0

Choose a tag to compare

@ytkoka ytkoka released this 06 Nov 09:49

v1.3.0

Highlights

WebSocket support. The proxy now carries WebSocket upgrades instead of breaking them.

  • wss:// works through the CONNECT tunnel, and plain ws:// works when the client sends it as an ordinary proxy request.
  • When the origin speaks HTTP/2, the upgrade goes over a separate HTTP/1.1 connection whose TLS ClientHello offers only http/1.1 in ALPN and omits the ALPS extension, the way a browser opens a WebSocket socket. Every other request on the tunnel stays on HTTP/2, so the JA4 and HTTP/2 fingerprints of ordinary traffic are unchanged (verified against tls.peet.ws: identical to v1.2.0).
  • After the 101 Switching Protocols, the stream is relayed byte for byte, so extensions such as permessage-deflate pass through untouched.

Before this release, an upgrade over an h2 origin lost its Upgrade and Connection headers and got an ordinary response, and over an HTTP/1.1 origin the connection stalled right after the 101.

Fixes

  • Chunked request bodies (Transfer-Encoding: chunked) are now forwarded with their framing intact on HTTP/1.1 upstreams. Previously the body was sent unframed.
  • Expect: 100-continue is answered by the proxy and the header is stripped; 1xx responses from the origin are relayed instead of being mistaken for the final response.

Tests

  • Table-driven tests for isPublicIPv4, thanks to @Macawls (#9).
  • New tests for the WebSocket relay on all three paths, declined upgrades, upgrade dial failures, and the ClientHello ALPN/ALPS handling for every TLS preset.

Known limitations

  • ws:// through CONNECT (for example from browsers) is not supported yet; the tunnel assumes TLS.
  • WebSocket over HTTP/2 (RFC 8441) is not supported.
  • The ClientHello used for WebSocket connections has not been compared against a real browser capture, and the handshake keeps the configured header_order rather than a browser's WebSocket-specific order.
  • Request trailers on chunked bodies are dropped, and large HTTP/2 request bodies are still sent as a single DATA frame.

See the README's Limitations section for the full list.

Docker

docker pull ghcr.io/ytkoka/impersonate-proxy:1.3.0

The Chrome extension is unchanged in this release (still 1.2.0).

Full changelog: v1.2.0...v1.3.0

v1.2.0

Choose a tag to compare

@ytkoka ytkoka released this 19 Sep 07:57

v1.2.0 — User-Agent auto mode

user_agent: "auto" now picks the User-Agent that matches the current tls.preset, so the TLS fingerprint and the UA no longer contradict each other. Switching the preset switches the UA too.

  • chrome / firefox / safari / edge / ios map to Chrome 131, Firefox 132, Safari 17.2, Edge 131, and iPhone iOS 17.1
  • random / golang / custom presets leave the client's User-Agent untouched
  • "random" remains a separate mode that picks a random UA from a built-in list per request

Behavior change

  • The edge preset now sends the same TLS ClientHello as chrome, and ios the same as safari. The previous uTLS Edge 85 / iOS 14 hellos contradicted the Edg/131 and iOS 17 User-Agents. Their JA3/JA4 values now match Chrome and Safari respectively

Chrome extension

  • Added an "Auto" checkbox next to "Random" for the User-Agent field (mutually exclusive)

v1.1.0

Choose a tag to compare

@ytkoka ytkoka released this 04 Sep 16:13

v1.1.0 — Upstream proxy support

Support for routing target connections through an upstream proxy (SOCKS5 / HTTP CONNECT).

Until now, source-IP spoofing only rewrote the X-Forwarded-For / True-Client-IP headers — the TCP connection's real source IP never changed. With this release, the connection to the target can be routed through a SOCKS5 or HTTP CONNECT proxy first, so the real egress IP changes too. This lets you separate "fingerprint looks fine but the IP is bad" from "IP is clean but the fingerprint is wrong" when testing WAF/bot-detection rules.

  • Supported schemes: socks5 / socks5h (remote DNS resolution) / http (CONNECT)
  • https:// (TLS-terminating) upstreams are intentionally not supported — they would strip the uTLS ClientHello this tool exists to control
  • Multiple proxies can be registered; select by name, or use rotate / random
  • suppress_ip_headers_when_active: while an upstream is active, XFF/True-Client-IP are automatically skipped (on by default) so a clean real IP doesn't also claim a spoofed one
  • Can be enabled and switched at runtime via the management API or Chrome extension — no restart required

API changes

  • New GET /api/upstream — returns upstream state (enabled, select, proxy names only). URLs and credentials are never exposed
  • POST /api/config is now a genuine partial update — fields you omit are left unchanged (previously, omitted fields were silently overwritten with empty values)

Chrome extension

  • Added an "Upstream proxy" toggle and proxy-selection dropdown
  • ⚠️ Developer Mode (unpacked) builds only, for now. The Chrome Web Store release hasn't been updated for this yet. If you're using the Web Store version, control upstream settings via the management API directly (curl, etc.) in the meantime

Docker

  • Added an upstream: section to config.docker.yaml
  • Fixed a build-breaking bug where the Dockerfile didn't copy the new upstream/ package into the build stage

v1.0.0

Choose a tag to compare

@ytkoka ytkoka released this 21 Aug 23:31

Highlights

First tagged release. This establishes a versioning baseline going forward — it
bundles everything shipped so far, not just changes since some prior release.

  • TLS fingerprinting (JA3 / JA4) via uTLS presets (chrome / firefox /
    safari / edge / ios / random / golang) or a fully custom
    custom_hello ClientHello spec
  • HTTP/2 fingerprinting: SETTINGS values/order, WINDOW_UPDATE, pseudo-header
    order
  • HTTP header control: header order, User-Agent override, arbitrary
    add/remove, source IP spoofing (X-Forwarded-For / True-Client-IP)
  • Runtime reconfiguration via a local management API — switch fingerprint
    profiles without restarting the proxy
  • Chrome extension (Manifest V3) to toggle the proxy and fingerprint
    profile from the toolbar
  • Docker support: docker compose up -d — no local Go/Make install
    required. Multi-arch images (amd64/arm64) published to
    ghcr.io/ytkoka/impersonate-proxy

Installation

Notes

Intended for authorized security testing only (WAF / bot-detection testing on
systems you own or have explicit permission to test).