Report vulnerabilities privately through GitHub: open the repository's Security tab and choose Report a vulnerability (https://github.com/OmarAlaaeldein/OpenTailcat/security/advisories/new). Do not open a public issue, and never include a live gateway token, signing key, or traffic capture in a report; describe how to reproduce instead.
OpenTailcat 1.5.1 in the current source tree is a development build. It has an
integrated Go Mobile Tailcat engine with Phase 0 fail-closed capability gates,
Phase 1 reproducible builds, Phase 2 official token validation, and Phase 3
tunneled UDP userspace netstack code. IPv4 test-routing capabilities are true so
a live token can Connect. ipv6 is true (client dual-stack path; session
ipv6Egress depends on gateway WAN). The capability JSON also reports
testRouting: true, which marks that Phase 8 physical leak acceptance has not
passed; Kotlin surfaces this in Settings and does not gate Connect on it.
Physical-device leak acceptance and full release gates are pending; it must not
be relied on as a production privacy VPN.
- The native Meow/Meowed gateway handshake runs during
prepare. Kotlin will not callprepareor create a TUN while the IPv4 capability set is incomplete. - The Android engine boundary (
TunnelEngine) enforces an API v2 native capability contract. IPv4 default-route installation requiresdataPlane,wireGuard,magicsock,twoPhaseStart,ipv4,tcp,udp,dns,liveStats, andcancelSafeLifecycle.requireIpv6exists but production Connect usesrequireIpv6 = false, so::/0is installed while dual-stack egress still depends on the gateway. Unknown capability JSON fields fail closed.testRoutingis an optional non-gating field that signals Phase 8 acceptance is still pending. - Token validation in Android and Go strictly enforces official token structures,
rejects legacy/synthetic disco keys, rejects duplicate CBOR keys, rejects
surrounding and interior whitespace, and rejects
expired tokens. Embedded DERP maps allow only region fields
i/c/m/Nand node fieldsn/i/h/t/4/6/s/d. Nodex(InsecureForTests) is rejected so a pasted token cannot disable DERP TLS. Loopback, unspecified, link-local, and multicasth/4/6values are rejected. Pairing UI labels embedded maps as "Embedded DERP Map", not an official city name, and setsFLAG_SECUREwhile the token paste dialog is open. - Tunneled UDP uses a single gVisor netstack proxy routing datagrams exclusively
through Tailcat WireGuard/Magicsock via
Client.DialUDPwithout direct OS UDP sockets incore-engine. IPv4udpis test-enabled; Phase 8 leak capture is still pending. - TCP-only gateways can
prepare. The UDP capability probe uses a 5s bound at prepare and re-probes every 30s while latched, so a slow DERP path cannot permanently drop non-DNS UDP for the session. DNS port 53 is carried over TCP and other UDP is dropped on such gateways; the measuredtcpOnlystate is reported in telemetry and the UI. A compatible exit gateway was observed answering native UDP (DNS query viaClient.DialUDP); TCP-only remains the fallback (tcpOnlysession). Gateway UDP support is deployment-specific and still needs Phase 8 capture proof per gateway. - Profiles and tokens are stored in encrypted preferences backed by Android Keystore. Android backup and device-to-device transfer are disabled.
- Transport sockets must be protected with
VpnService.protect(netns re-enabled after TailcatSetEnabled(false)). The app does not exclude its own UID: while the VPN is up its other HTTP (public-IP display, update check, speed test when not CONNECTED) is routed into the TUN like any app's. - Cleartext traffic is disabled for the Android application.
- Audit H1–H7 code fixes shipped in 1.3.5 source and the checked-in AAR (lockdown-after-warm-TUN, transport protect re-enable, dead-reader attach, DNS TCP stop bound, DiscoPing health honesty, FD lifecycle serialization, phase8 fail-closed). Host Go tests cover the native pieces. Always-on emulator/device run and Phase 8 dual capture remain before any production claim.
- IPv4 flags are test-enabled, not Phase 8 accepted: leak capture still pending.
- IPv6 dual-stack egress: Android installs
::/0after pumps are live. Native proxies IPv6 TCP/UDP (public IPv6 is rejected before dial whenipv6Egressis false, otherwise IPv6 uses the IPv4 dial budget (15 s TCP / 10 s UDP)); ICMPv6 echo is dropped; oversized IPv6 gets a local Packet Too Big. Live IPv6 internet depends on the gateway. Capabilityipv6is true; without gateway IPv6 WAN, public IPv6 is fail-closed (RST/drop) so Happy Eyeballs can fall back to tunneled IPv4. - Test-routing marker: capability JSON includes
testRouting: truewhile Phase 8 physical leak acceptance has not passed. Settings surfaces this; it does not gate Connect. - Lifecycle / telemetry promotion: two-phase start (host-only TUN, then
default routes after pumps), sticky VPN service, TUN closed before native stop,
plus live
DiscoPingRTT.twoPhaseStart,cancelSafeLifecycle, andliveStatsare test-enabled until Phase 8 evidence. - Live physical-device acceptance: Uplink packet capture on multi-interface devices to verify zero direct destination leaks (Phase 8).
- Production release signing: Signing with a production keystore (Phase 8).
See handoff.md for the ordered continuation plan and test gates.