Fix 14 deep-review findings across security, concurrency, and API#7
Merged
Conversation
Security / TLS: - Add private key to TLS cache deduplication key (finding 7) - Zeroize private key PEM bytes on drop via zeroize::Zeroizing<Vec<u8>> (finding 13) - Change mTLS requireClientCert default from true→false so omitting the field does not silently lock out clients without certificates (finding 9) Concurrency: - Fix TOCTOU in per-IP concurrency check: use fetch_update atomic test-and-increment so concurrent threads cannot race past the limit (finding 3) - Fix rate-limit refill race: use CAS on last_refill_ns so only the first winner advances the refill window, preventing double-credits (finding 4); applied to both protection.rs and router.rs RouteTokenBucket - Add AllowBypassed Decision variant so allowlisted IPs do not trigger release() on a counter that was never incremented (finding 6) API / routing: - Add upstream connect timeout (defaults to TLS handshake timeout / 30s) to prevent a black-hole upstream from blocking tokio tasks indefinitely (finding 1) - Treat idleTimeoutMs: 0 as "no timeout" rather than firing instantly (finding 2) - Wildcard route matching now requires exactly one left-most label, preventing *.example.com from matching sub.sub.example.com (finding 5) - Surface invalid CIDR strings in allowlist/blocklist as config errors instead of silently dropping the rule (finding 10) - Normalize SNI: trim trailing dot, reject if empty, >253 chars, or contains ':' or '/' (finding 11) - PROXY v1 header: unwrap IPv4-mapped IPv6 addresses to TCP4 for backend compat (finding 12) - toJsRoute now forwards maxConnectionsPerSecond and burst so per-route rate limiting is no longer silently disabled (finding 8) - ResolveRoute.upstream changed from array to single Upstream; resolveConnection never supported multi-upstream balancing so the type now matches the semantics (finding 14) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…2 features Conflicts in proxy.rs, proxy_conn.rs, upstream.rs, ts/proxy.ts. In all cases: keep both sets of changes. - proxy_conn.rs: apply_source_header() (main) + copy_with_idle_timeout() (ours) now run in sequence, so source address forwarding and zero-idle-timeout both work correctly together. - proxy.rs: requireClientCert default=false (ours) + source_address_mode/http2 fields (main) both preserved in parse_resolve_spec. - upstream.rs: Duration + timeout imports (ours) merged with AsyncReadExt (main). - ts/proxy.ts: maxConnectionsPerSecond + burst (ours) + sourceAddressHeader (main) all forwarded in toJsRoute. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Newer npm versions require bufferutil, utf-8-validate, and node-gyp-build to be present in the lock file. Regenerated with current npm to fix CI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
npm install -g npm@latest is broken on Node 22.22.2 (missing promise-retry in the newly installed npm). The lock file was already regenerated with a current npm, so npm ci runs cleanly without the upgrade step. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Addresses all 14 findings from a deep code review of the symphony proxy. No new features — correctness and security fixes only.
Changes
Security / TLS
src/tls.rs)zeroize::Zeroizing<Vec<u8>>so key material is zeroed on drop (src/tls.rs,Cargo.toml)requireClientCertdefault changedtrue → false; omitting the field from anmtlsblock no longer silently enforces mandatory client certs — breaking change for callers that relied on the implicit default (src/proxy.rs,ts/types.ts)Concurrency
fetch_updateatomic test-and-increment to close the TOCTOU window (src/protection.rs)storeonlast_refill_nswithcompare_exchangeso concurrent threads cannot double-credit the same epoch (src/protection.rs,src/router.rs)AllowBypassedDecision variant — allowlisted connections no longer callrelease()on a counter that was never incremented (src/protection.rs,src/proxy_conn.rs)Reliability / API
src/upstream.rs)idleTimeoutMs: 0now means "no timeout" instead of dropping every connection instantly (src/proxy.rs,src/proxy_conn.rs)*.example.comno longer matchesa.b.example.com(src/router.rs)allowlist/blocklistare now config errors surfaced to JS, not silently dropped rules (src/proxy.rs)None(src/sni.rs)::ffff:1.2.3.4) now emitTCP4header so HAProxy/nginx don't reject the connection (src/upstream.rs)toJsRoutenow passesmaxConnectionsPerSecondandburst; previously per-route rate limiting was silently dead (ts/proxy.ts)ResolveRoute.upstreamchanged fromUpstream[]to singleUpstreamto match actual semantics (ts/types.ts,ts/proxy.ts,src/proxy.rs)Attention areas
requireClientCertdefault flip is the one change most likely to affect existing callers. Anyone withmtls: { clientCaCert: "..." }without an explicitrequireClientCert: truewill now get optional client auth instead of mandatory. Review call sites.suspended.spec.tstest updated for theupstreamrename.🤖 Generated by Claude Sonnet 4.6