Summary
BoxLite's allow_net enforcement can be bypassed when hostname-based rules are used for HTTP (port 80) and HTTPS (port 443) traffic. In the gvproxy-bridge inspection path, BoxLite validates the guest-controlled HTTP Host header or TLS SNI against the hostname allowlist, but then connects to the previously selected destination IP without checking that the authorized hostname actually resolves to that IP. As a result, unprivileged code inside a guest can reach an arbitrary IP address while presenting an allowlisted hostname.
Verified Code Facts
forked_tcp.go:112-121 computes destAddr from the selected destination IP before hostname inspection occurs.
forked_tcp.go:76-77 routes hostname-only rules for ports 80 and 443 into the inspectAndForward() path.
forked_tcp.go:203-210 authorizes the connection only by checking filter.MatchesHostname(hostname) against the guest-controlled HTTP Host header or TLS SNI.
forked_tcp.go:218-236 then calls net.Dial("tcp", destAddr) without verifying that the approved hostname corresponds to the destination IP being dialed.
tcp_filter.go:126-140 shows that MatchesHostname() performs string matching only; it does not bind the hostname rule to the actual network destination.
- The documented product behavior in
README.md:25 and docs/reference/README.md:153-168 presents allow_net as a guest egress restriction.
- The existing tests in
sdks/python/tests/test_tcp_filter.py:235-289 cover allowlisted-host success and direct-IP blocking, but do not cover the hostname/IP mismatch case required for this bypass.
Security Impact
An attacker who can run ordinary code inside a BoxLite guest can bypass a host-configured outbound policy on ports 80 and 443.
This enables:
- reaching arbitrary external IPs despite hostname-only
allow_net restrictions;
- exfiltrating data to attacker-controlled infrastructure while presenting an allowlisted hostname;
- bypassing network segmentation or outbound policy assumptions that rely on BoxLite's documented egress controls.
Reproduction
Prerequisite: configure a guest with a hostname-only allowlist such as allow_net=["api.openai.com"].
Example HTTP PoC:
# Connect to an attacker-chosen IP while keeping an allowlisted Host header.
curl --resolve api.openai.com:80:203.0.113.10 http://api.openai.com/
Example HTTPS PoC:
# Connect to an attacker-chosen IP while keeping an allowlisted SNI value.
curl --resolve api.openai.com:443:203.0.113.10 -k https://api.openai.com/
Live validation that was actually performed during owner review:
# Owner validation: preserve Host while connecting to a caller-chosen IP.
curl --resolve allowed.example:18080:127.0.0.1 http://allowed.example:18080/
# Owner validation: preserve SNI while connecting to a caller-chosen IP.
curl --resolve allowed.example:18443:127.0.0.1 -k https://allowed.example:18443/
The owner recorded that these reproductions preserved Host=allowed.example:18080 and SNI=allowed.example while the TCP connection went to 127.0.0.1, matching the traced exploit primitive.
Why This Crosses a Security Boundary
This is not a documentation-only unsafe mode and it is not permission-equivalent to host administration.
Before exploitation, the attacker can only run unprivileged code inside a guest that is supposed to be restricted by a hostname-based outbound policy. After exploitation, the attacker can reach arbitrary IP destinations on ports 80/443 while satisfying BoxLite's hostname check with guest-controlled application-layer metadata. That breaks the product's promised outbound restriction boundary.
Remediation
- Bind hostname authorization to the actual destination being dialed.
- After extracting HTTP
Host or TLS SNI, resolve the approved hostname and verify that the chosen destination IP matches the resolved address set before forwarding.
- Alternatively, for hostname-based rules, establish the upstream connection using trusted resolution of the approved hostname rather than the guest-selected destination IP.
- Add regression tests covering hostname/IP mismatch cases for both HTTP and HTTPS inspection paths.
Evidence Reviewed
/tmp/redbull-boxlite/rebuttals/rebuttals.json
/root/cve-audit/boxlite/src/deps/libgvproxy-sys/gvproxy-bridge/forked_tcp.go
/root/cve-audit/boxlite/src/deps/libgvproxy-sys/gvproxy-bridge/tcp_filter.go
/root/cve-audit/boxlite/sdks/python/tests/test_tcp_filter.py
/root/cve-audit/boxlite/README.md
/root/cve-audit/boxlite/docs/reference/README.md
Summary
BoxLite's
allow_netenforcement can be bypassed when hostname-based rules are used for HTTP (port 80) and HTTPS (port 443) traffic. In thegvproxy-bridgeinspection path, BoxLite validates the guest-controlled HTTPHostheader or TLS SNI against the hostname allowlist, but then connects to the previously selected destination IP without checking that the authorized hostname actually resolves to that IP. As a result, unprivileged code inside a guest can reach an arbitrary IP address while presenting an allowlisted hostname.Verified Code Facts
forked_tcp.go:112-121computesdestAddrfrom the selected destination IP before hostname inspection occurs.forked_tcp.go:76-77routes hostname-only rules for ports 80 and 443 into theinspectAndForward()path.forked_tcp.go:203-210authorizes the connection only by checkingfilter.MatchesHostname(hostname)against the guest-controlled HTTPHostheader or TLS SNI.forked_tcp.go:218-236then callsnet.Dial("tcp", destAddr)without verifying that the approved hostname corresponds to the destination IP being dialed.tcp_filter.go:126-140shows thatMatchesHostname()performs string matching only; it does not bind the hostname rule to the actual network destination.README.md:25anddocs/reference/README.md:153-168presentsallow_netas a guest egress restriction.sdks/python/tests/test_tcp_filter.py:235-289cover allowlisted-host success and direct-IP blocking, but do not cover the hostname/IP mismatch case required for this bypass.Security Impact
An attacker who can run ordinary code inside a BoxLite guest can bypass a host-configured outbound policy on ports 80 and 443.
This enables:
allow_netrestrictions;Reproduction
Prerequisite: configure a guest with a hostname-only allowlist such as
allow_net=["api.openai.com"].Example HTTP PoC:
# Connect to an attacker-chosen IP while keeping an allowlisted Host header. curl --resolve api.openai.com:80:203.0.113.10 http://api.openai.com/Example HTTPS PoC:
# Connect to an attacker-chosen IP while keeping an allowlisted SNI value. curl --resolve api.openai.com:443:203.0.113.10 -k https://api.openai.com/Live validation that was actually performed during owner review:
The owner recorded that these reproductions preserved
Host=allowed.example:18080andSNI=allowed.examplewhile the TCP connection went to127.0.0.1, matching the traced exploit primitive.Why This Crosses a Security Boundary
This is not a documentation-only unsafe mode and it is not permission-equivalent to host administration.
Before exploitation, the attacker can only run unprivileged code inside a guest that is supposed to be restricted by a hostname-based outbound policy. After exploitation, the attacker can reach arbitrary IP destinations on ports 80/443 while satisfying BoxLite's hostname check with guest-controlled application-layer metadata. That breaks the product's promised outbound restriction boundary.
Remediation
Hostor TLS SNI, resolve the approved hostname and verify that the chosen destination IP matches the resolved address set before forwarding.Evidence Reviewed
/tmp/redbull-boxlite/rebuttals/rebuttals.json/root/cve-audit/boxlite/src/deps/libgvproxy-sys/gvproxy-bridge/forked_tcp.go/root/cve-audit/boxlite/src/deps/libgvproxy-sys/gvproxy-bridge/tcp_filter.go/root/cve-audit/boxlite/sdks/python/tests/test_tcp_filter.py/root/cve-audit/boxlite/README.md/root/cve-audit/boxlite/docs/reference/README.md