Skip to main content

In-Memory MITM TLS Proxy

The network channel inspects all outbound HTTP and HTTPS egress traffic by running an ephemeral, in-memory loopback proxy on 127.0.0.1:<random-port>. It is completely air-gapped: no external telemetry or third-party validation servers are contacted. All decryption and scanning happen locally in RAM.

1. Ephemeral Root Certificate Authority (CA)

Before spawning your application process, envtrap creates a dedicated 2048-bit RSA Root Certificate Authority in memory:
  • RAM-Only Key Material: The Root CA private key is generated with Node’s native crypto.generateKeyPairSync and retained exclusively in RAM. It is never written to disk.
  • Child Process Trust: The public certificate (ca.crt) is written to a temporary folder with restrictive file permissions (0o600) in os.tmpdir(). envtrap points NODE_EXTRA_CA_CERTS to this file so Node.js trusts it automatically without modifying system settings.
  • Optional System CA Trust: If run with sufficient permissions (e.g. root/admin or on macOS/Windows), SystemCaTrust can register the certificate into OS trust stores (security, certutil, update-ca-certificates) to protect non-Node subprocesses like curl or Python scripts.
  • Automated Cleanup: When the application shuts down or receives SIGINT/SIGTERM, the temporary CA files and OS trust certificates are purged immediately.

2. HTTPS Decryption Flow: The Two-Wire Model

When your application initiates an HTTPS request (e.g. fetch("https://api.stripe.com/v1/charges")), traffic is routed through the proxy via HTTP_PROXY and HTTPS_PROXY:

Step-by-Step Breakdown:

  1. CONNECT Tunneling: The client asks the proxy to open a raw TCP tunnel to target-host:443.
  2. On-The-Fly Certificate Minting: envtrap dynamically generates an X.509 server certificate for target-host, signed by the in-memory Root CA. Domain certificates are cached in memory for sub-millisecond reuse.
  3. Local Handshake (Wire #1): The client performs a TLS handshake with envtrap. Because Node was configured with NODE_EXTRA_CA_CERTS, the client accepts the forged certificate.
  4. Decryption & Inspection: envtrap decrypts the incoming TLS packets into plain text to scan headers, URLs, and bodies.
  5. Upstream Forwarding (Wire #2): If clean, envtrap opens a genuine, external TLS socket to the real remote host, verifies the real server certificate, and relays the payload.

3. Streaming Inspection & Security Gating

TlsInterceptor protects against packet fragmentation, split-secret bypasses, and protocol deadlocks:

A. HTTP Header Pre-Buffering & Early Chunk Gating

HTTP requests often arrive in fragmented TCP packets. If an authorization header containing a secret arrives in Packet 1 and body data in Packet 2, streaming directly upstream would leak the secret before inspection finishes.
  • envtrap buffers initial chunks in headerBuffer until the end-of-headers delimiter \r\n\r\n is matched.
  • The entire header block is scanned. Only once verified as clean is it transmitted upstream.

B. Dynamic Sliding-Window Overlap

A secret token may straddle two sequential TCP packets (half in Chunk 1, half in Chunk 2):
  • Adaptive Sizing: The window size is dynamically set to Math.min(8192, Math.max(200, maxSecretLength)) based on the longest secret in your environment.
  • Low Memory Footprint: No need to buffer multi-gigabyte files in RAM; only a tiny sliding overlap is maintained.

C. Non-HTTP Raw TLS Detection

Non-HTTP TLS traffic (such as PostgreSQL, Redis, or MQTT over TLS) does not emit HTTP headers (\r\n\r\n).
  • envtrap sniffs the first 4–10 bytes for standard HTTP verbs (GET , POST , PUT , etc.).
  • If non-HTTP traffic is identified, envtrap immediately bypasses HTTP header gating, preventing socket deadlocks.

D. EOF Verification

If an attacker or malicious dependency abruptly drops or closes the socket (tlsSocket.on('end')), any remaining unflushed bytes in memory are scanned for secrets before the upstream connection is torn down.

4. Loopback & Domain Exclusions

To avoid intercepting internal microservices or authorized cloud services:
  1. Automatic Loopback Bypass: NO_PROXY is automatically populated with:
  2. Domain Exclusions: Domains specified in exclusions.domains (in envtrap.json) are automatically appended to NO_PROXY. Connections to these hosts bypass the proxy entirely, allowing raw, unmodified native socket speeds.