Skip to content

Library (embed) ​

For .NET library users — operators who want a reverse proxy or desktop debugger should start with the CLI or Inspector instead.

NuGet package Titanium.Web.Proxy (MIT). Target framework: .NET 10.

shell
dotnet add package Titanium.Web.Proxy
# Prerelease when newer than the stable NuGet feed:
dotnet add package Titanium.Web.Proxy --prerelease

Related MIT packages (also on NuGet): Titanium.Web.Proxy.Abstractions (shared contracts) and Titanium.Web.Proxy.Configuration (twp.yaml / dialect loaders — optional for library users). See migration 6→7.

Explicit man-in-the-middle (MITM) proxy ​

csharp
using System.Net;
using Titanium.Web.Proxy;
using Titanium.Web.Proxy.Models;

using var proxyServer = new ProxyServer();
proxyServer.BeforeRequest += async (sender, e) =>
{
    // Inspect or rewrite e.HttpClient.Request
};

var endPoint = new ExplicitProxyEndPoint(IPAddress.Loopback, 8000, decryptSsl: true);
proxyServer.AddEndPoint(endPoint);
proxyServer.CertificateManager.EnsureRootCertificate(
    userTrustRootCertificate: true,
    machineTrustRootCertificate: false);
proxyServer.Start();

Capabilities ​

  • Intercept, modify, redirect, or block HTTP and HTTPS
  • Explicit, transparent, and SOCKS4/5 endpoints
  • HTTP/2 on by default (ProxyServer.EnableHttp2); HTTP/3 opt-in (EnableHttp3, experimental TWP001)
  • Upstream HTTP/HTTPS/SOCKS + system proxy detection
  • Proxy auth, mTLS, Kerberos, NTLM
  • Connection, certificate, and buffer pooling
  • Built-in async logging and opt-in request timing. Logging.AdditionalLoggerProviders adds host sinks after the built-in ones; an empty list changes nothing, the proxy does not dispose those providers, and the default level stays Error.

Reverse proxy ​

Use ForwardHost on a transparent endpoint for a zero-cost terminate-lite path, or declarative routes/clusters (also used by the CLI). See Configuration and Protocol support.

API reference ​

Examples in the repo ​

  • examples/Titanium.Web.Proxy.Examples.Basic
  • examples/Titanium.Web.Proxy.Examples.Wpf
  • examples/Titanium.Web.Proxy.Examples.WindowsService

System proxy and root CA (Windows / macOS / Linux) ​

ProxyServer.SetAsSystemProxy / RestoreOriginalProxySettings work on Windows (WinINET), macOS (networksetup), and Linux (GNOME + KDE + process environment). Unsupported platforms throw NotSupportedException.

CertificateManager.TrustRootCertificate installs into the current-user store on all platforms and additionally trusts for SSL on macOS (login keychain) and Linux (user NSS db). Check LastOsTrustResult for structured outcomes (e.g. missing certutil, Keychain Always Trust needed). InstallNssCertutilAndRetryUserTrust installs NSS tools via package manager / Homebrew after user consent. FirefoxCertificateTrust enables Windows ImportEnterpriseRoots or profile user.js (security.enterprise_roots.enabled) so Firefox trusts OS roots, and can import into the default Firefox NSS profile. TrustRootCertificateAsAdmin shows an OS admin prompt (UAC / macOS authentication / polkit) for machine-wide trust.

MITM hostname exclusions ​

Two layers (both work with system proxy on Windows, macOS, and Linux):

  1. OS bypass — SystemProxySettings.BypassRules + SetAsSystemProxy(..., settings). Traffic never hits the proxy when System proxy is on. Factory seed: MitmExclusionDefaults.SystemProxyBypassRules (Microsoft identity / SSO / RDP).
  2. Tunnel only — BeforeTunnelConnectRequest → e.DecryptSsl = false, or MitmExclusionDefaults.ApplyDecryptExclusions(...). CONNECT stays visible; no decrypt. Factory seed: MitmExclusionDefaults.TunnelOnlyPinningDomains (dropbox.com, webex.com).

Use MitmExclusionMode.Merge (default, back-compat) to always re-inject factory hosts, or Replace so the caller lists are authoritative (you can remove identity hosts — risk breaking SSO while System proxy is on).

csharp
// Merge: factory identity hosts + extras
var settings = MitmExclusionDefaults.CreateSystemProxySettings(
    proxyLoopback: true,
    additionalBypassRules: ["*.corp.example.com"]);
proxyServer.SetAsSystemProxy(endPoint, ProxyProtocolType.AllHttp, settings);

// Replace: full list you provide (factory not re-added)
var custom = MitmExclusionDefaults.CreateSystemProxySettings(
    proxyLoopback: true,
    MitmExclusionDefaults.SystemProxyBypassRules.Append("*.corp.example.com"),
    MitmExclusionMode.Replace);

MitmExclusionDefaults.ApplyDecryptExclusions(endPoint, () => true,
    decryptSkipHosts: ["*.bank.example.com"],
    decryptOnlyHosts: null,
    MitmExclusionMode.Replace);

CLI: when server.decryptSkipHosts and/or server.decryptOnlyHosts are present in twp.yaml, exclusions apply with Replace. Omit both to leave Merge defaults. Optional server.systemProxyBypassHosts / server.proxyLoopback build OS-bypass settings the same way (present ⇒ Replace; omit ⇒ Merge). Removing identity hosts from OS bypass can break Microsoft SSO while System proxy is enabled.

Decrypt failure bypass (learned tunnel) ​

Optional heuristic for hosts that reject the proxy’s TLS fingerprint under MITM (bot / WAF style). Default off on ProxyServer (library and RPS baselines unchanged). Titanium Inspector enables it by default.

csharp
proxyServer.EnableDecryptFailureBypass = true;
proxyServer.DecryptFailureBypassThreshold = 2;      // strikes before later CONNECTs skip decrypt
proxyServer.DecryptFailureBypassTtl = TimeSpan.FromMinutes(30);
proxyServer.DecryptFailureBypassMaxEntries = 256;   // approximate LRU

// Snapshot / manage
foreach (var e in proxyServer.GetDecryptFailureBypassEntries())
    Console.WriteLine($"{e.Host} active={e.BypassActive}");
proxyServer.RemoveDecryptFailureBypass("www.example.com");
proxyServer.ClearDecryptFailureBypass();

Behavior:

  • Learns from origin TLS AuthenticationException failures (not ALPN-only “no h2”, not TCP/DNS).
  • Also learns from MITM HTTPS responses with status 403 or 429 (bot/WAF after TLS succeeds), excluding synthetic Respond/Ok/GenericResponse.
    • Document navigations (Sec-Fetch-Dest: document or Accept prefers text/html): activate bypass immediately and answer with a one-shot meta-refresh (200) plus connection close so the browser opens a new CONNECT over an opaque tunnel—seamless recovery without a manual reload.
    • Non-document (XHR/fetch): shared strike threshold (default 2); no body rewrite.
  • Prefetch (MITM origin sockets) is not started for learned hosts. The current MITM CONNECT is never converted in place.
  • If a cold awaited HTTP/2 capability probe fails with a learnable error, the same CONNECT can fall back to opaque relay before browser MITM (ClientHello was only peeked); session prefetch is not started on that failure path.
  • Does not replace MitmExclusionDefaults pinning/SSO lists. Does not auto-learn browser-leg pinning aborts.
  • Not a twp.yaml key in v1 — set on ProxyServer (or use Inspector). Use ShouldBypassDecryptForLearnedHost for O(1) consults (avoid snapshotting the full list on hot paths).
  • Automation/CDP browsers may still see Akamai-style captchas after a successful tunnel (site bot score), which is outside MITM recovery.

Core, CLI, and website: MIT