TCPMatcher (raw-TCP egress allowlist) matches hosts by exact string, so a non-canonical IPv6 config entry like [0:0:0:0:0:0:0:1]:5432 won't match the canonical runtime form ::1 that the SOCKS5 IPv6 ATYP path produces (net.IP(buf).String()).
Behavior today is fail-closed — a non-canonical entry silently denies rather than over-permits — and the docs already instruct operators to use the bracketed canonical form ([::1]:5432, [2001:db8::1]:6379). So this is a robustness nicety, not a security gap.
Fix
In parseTCPEntry (forge-core/security/tcp_matcher.go), after splitting host/port, run the host through net.ParseIP(host); if it parses as an IP, store ip.String() (the canonical form) so any operator-written IPv6 representation round-trips to the runtime form. Leave hostnames and *.suffix wildcards untouched.
Test
Add a TestTCPMatcher_IPv6Literal case: an expanded-form entry [0:0:0:0:0:0:0:1]:5432 should match runtime host ::1 on port 5432.
Priority
Low. Fail-closed, so no urgency. Surfaced in the #355 review; sibling follow-up to #360 (SOCKS5 audit attribution), kept separate because it's config-parse robustness in a different file.
TCPMatcher(raw-TCP egress allowlist) matches hosts by exact string, so a non-canonical IPv6 config entry like[0:0:0:0:0:0:0:1]:5432won't match the canonical runtime form::1that the SOCKS5 IPv6 ATYP path produces (net.IP(buf).String()).Behavior today is fail-closed — a non-canonical entry silently denies rather than over-permits — and the docs already instruct operators to use the bracketed canonical form (
[::1]:5432,[2001:db8::1]:6379). So this is a robustness nicety, not a security gap.Fix
In
parseTCPEntry(forge-core/security/tcp_matcher.go), after splitting host/port, run the host throughnet.ParseIP(host); if it parses as an IP, storeip.String()(the canonical form) so any operator-written IPv6 representation round-trips to the runtime form. Leave hostnames and*.suffixwildcards untouched.Test
Add a
TestTCPMatcher_IPv6Literalcase: an expanded-form entry[0:0:0:0:0:0:0:1]:5432should match runtime host::1on port5432.Priority
Low. Fail-closed, so no urgency. Surfaced in the #355 review; sibling follow-up to #360 (SOCKS5 audit attribution), kept separate because it's config-parse robustness in a different file.