Summary
The 3c.3 relay Trojan front (bin/yip-rendezvous/src/conn.rs) has a narrow but real timing side-channel on fully-silent connections that an active prober could use to distinguish the relay from a bare web server.
Mechanism
handle_connection trial-reads the first frame under CLASSIFY_TIMEOUT (~3s) to decide tunnel-vs-decoy. On a connection that sends nothing, that timeout fires, and only then does into_decoy open the TCP connection to the decoy backend and start copy_bidirectional. So the decoy's own idle-close clock starts ~3s late: the relay's observable time-to-close for a silent client is CLASSIFY_TIMEOUT + decoy_native_timeout (~63s) versus a bare server's native timeout (~60s).
An adversary who baselines "connect, stay silent, measure time-to-close" against the real decoy directly vs. through the relay can observe the ~3s differential — the class of behavioral fingerprint 3c.3 exists to eliminate.
Scope / severity
- Narrow: only the fully-silent case. Any real HTTP request (or any first byte) classifies as decoy essentially instantly (a
GET prefix exceeds MAX_FIRST_FRAME), so an ordinary probe sees no differential.
- Real-world web servers already exhibit timing jitter (load balancers, connection pooling), which partly masks a fixed ~3s offset — but a careful adversary with a clean baseline could still measure it.
- Accepted as a defense-in-depth follow-up during 3c.3 brainstorming, not a 3c.3 blocker.
Fix directions
- Connect the decoy backend eagerly/concurrently with the trial-read (so the decoy's idle clock aligns with the client's connect time), splicing once classification resolves to decoy. Cost: a decoy connection per not-yet-classified connection.
- Or reduce
CLASSIFY_TIMEOUT so the offset falls within normal server jitter.
- Or randomize the classification deadline to blur a fixed offset.
Surfaced by the Task 6 whole-branch-style review during 3c.3 subagent-driven execution.
Summary
The 3c.3 relay Trojan front (
bin/yip-rendezvous/src/conn.rs) has a narrow but real timing side-channel on fully-silent connections that an active prober could use to distinguish the relay from a bare web server.Mechanism
handle_connectiontrial-reads the first frame underCLASSIFY_TIMEOUT(~3s) to decide tunnel-vs-decoy. On a connection that sends nothing, that timeout fires, and only then doesinto_decoyopen the TCP connection to the decoy backend and startcopy_bidirectional. So the decoy's own idle-close clock starts ~3s late: the relay's observable time-to-close for a silent client isCLASSIFY_TIMEOUT + decoy_native_timeout(~63s) versus a bare server's native timeout (~60s).An adversary who baselines "connect, stay silent, measure time-to-close" against the real decoy directly vs. through the relay can observe the ~3s differential — the class of behavioral fingerprint 3c.3 exists to eliminate.
Scope / severity
GETprefix exceedsMAX_FIRST_FRAME), so an ordinary probe sees no differential.Fix directions
CLASSIFY_TIMEOUTso the offset falls within normal server jitter.Surfaced by the Task 6 whole-branch-style review during 3c.3 subagent-driven execution.