Skip to content

fix(mitm): forward anti-loop — bypass-marked socket on the Agent (decrypt 4d, VPS-validated) - #4229

Merged
diegosouzapw merged 1 commit into
release/v3.8.29from
fix/mitm-tproxy-forward-antiloop
Jun 19, 2026
Merged

diegosouzapw merged 1 commit into
release/v3.8.29from
fix/mitm-tproxy-forward-antiloop

Conversation

@diegosouzapw

Copy link
Copy Markdown
Collaborator

Summary

Epic A / Fase 3 — decrypt 4d: the VPS e2e validation of the decrypt capture mode, which caught and fixed a real anti-loop bug in the merged forward path.

The bug. The decrypt forward (#4179/#4200) opened its upstream socket via https.request({ agent: false, createConnection }). But https.request silently ignores the createConnection request option whenever an agent is present — and agent: false still installs a fresh default Agent — so createConnection (and thus connectMarked) never ran. The forward opened its own unmarked socket. On a real TPROXY host the OUTPUT rule re-intercepts the proxy's own forward → decrypt → forward → re-intercept → infinite loop. The local unit test in #4179 couldn't catch this: with no kernel interception, an unmarked forward reaches the upstream just the same.

The fix. Move the bypass-marked socket onto a dedicated https.Agent's createConnection, where Node actually honors it (keepAlive:false, so no socket lingers).

VPS validation (Hard Rule #18 — documented live test)

Real merged code bundled (esbuild, only the buffer/DB sink stubbed) + the prebuilt native addon, run as root on the production VPS (kernel 6.8.0-124), on a TEST port 18443 (never 443), with sysctls saved/restored and rules/route/CA force-cleaned on exit:

before fix after fix
createConnection invoked 0× per-forward ✓
interceptions for one client request 1298 (loop) 1
client result timeout HTTP 200 PONG-DECRYPTED
captured entry 1298× in-flight source:"tproxy", GET /decrypt-probe, status:200, secret masked

A control run of the raw tunnel (no decrypt, same connectMarked) round-tripped cleanly (rawIntercepts:1), isolating the defect to the decrypt forward — not loopback. Post-run state: 0 rules, table empty, CA removed.

Test Plan

tests/unit/tproxy-tls-capture.test.ts (6/6) — adds "the forward dials its upstream through connectRaw (the bypass-marked seam)": spies on connectRaw and asserts it is invoked. It fails against the pre-fix code (createConnection never runs → connectRaw never called) and is the permanent regression guard. The existing decrypt round-trip + masking + 502 tests still pass.

Validation: typecheck:core ✓, lint ✓ (0), tproxy-tls-capture 6/6, tproxy-capture-mode + tproxy-capture-manager 16/16.

This closes the TLS-decrypt epic's validation: the kernel intercept → TLS-terminate → decrypt → capture (source:"tproxy") → re-encrypted forward → upstream → relay round-trip is now proven end-to-end on the real VPS. Remaining nice-to-have: native-addon prebuilds for distribution.

🤖 Generated with Claude Code

…ent (decrypt 4d)

The TPROXY decrypt forward (#4179/#4200) opened its upstream socket via
https.request({ agent: false, createConnection }). But https.request SILENTLY
IGNORES the createConnection request option whenever an agent is present -- and
agent: false still installs a fresh default Agent -- so createConnection (and
thus connectMarked) never ran. The forward opened its own UNMARKED socket.

On a real TPROXY host that re-intercepts the proxy's own forward, an unmarked
forward is re-intercepted -> decrypted -> forwarded -> re-intercepted -> infinite
loop. The local unit test could not catch it: with no kernel interception an
unmarked forward reaches the upstream just the same.

Fix: move the bypass-marked socket onto a dedicated https.Agent's createConnection
(where Node actually honors it; keepAlive:false so no socket lingers).

Validated on the production VPS (kernel 6.8.0, TEST port 18443, never 443):
- before: createConnection invoked 0 times, 1298-capture loop, client timeout;
- after: exactly 1 interception, full decrypt round-trip (client received the
  upstream body), the decrypted request captured as source "tproxy" with the
  bearer token masked; rules + route + CA cleanly reverted.

The new unit test asserts the forward dials through connectRaw (the marked seam) --
it fails against the pre-fix code (createConnection never invoked) and is the
permanent regression guard.
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@diegosouzapw
diegosouzapw merged commit 7f4d5f1 into release/v3.8.29 Jun 19, 2026
4 checks passed
@diegosouzapw
diegosouzapw deleted the fix/mitm-tproxy-forward-antiloop branch June 19, 2026 12:07
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
…ent (decrypt 4d) (cheaper-inference#4229)

Integrated into release/v3.8.29 (MITM TPROXY decrypt 4d — forward anti-loop: bypass-marked socket on the Agent; VPS-validated).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant