Skip to content

Commit f7b8838

Browse files
committed
Move security details and known limitations from README to docs/security.md
1 parent 96ee9c6 commit f7b8838

File tree

2 files changed

+110
-95
lines changed

2 files changed

+110
-95
lines changed

README.md

Lines changed: 5 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -342,105 +342,15 @@ buildcage blocks outbound connections to domains not on your allowlist during Do
342342
- **Command-and-control (C2) communication** — blocks compromised dependencies from phoning home to attacker-controlled servers
343343
- **Unexpected telemetry** — stops analytics, tracking, or other undisclosed network calls that packages may make during installation
344344

345-
### Security Mechanisms
345+
### Security mechanisms and attack resistance
346346

347-
#### Direct IP Address Connections
347+
buildcage enforces network isolation through DNS-level control, HTTP/HTTPS proxy filtering, iptables rules, and CNI network isolation. These mechanisms defend against SNI spoofing, ECH bypass, DNS tunneling, non-TCP protocol tunneling, IPv6 bypass, and alternative DNS transports (DoH/DoT).
348348

349-
All connections using direct IP addresses from within RUN steps (e.g., `curl http://1.2.3.4/`) are **blocked by iptables**. All outbound connections must go through the proxy via domain names.
349+
For full technical details, see the [Security Details](./docs/security.md) document.
350350

351-
This is intentional — it ensures all traffic can be inspected and logged.
351+
### Known limitations
352352

353-
#### DNS-Level Control
354-
355-
- **Full redirect**: Returns the proxy IP for all DNS queries.
356-
- **ECH prevention**: The internal DNS server operates without any upstream resolvers, so DNS HTTPS (type 65) records — required to initiate Encrypted Client Hello (ECH) — are never returned to build containers.
357-
358-
#### HTTP/HTTPS Proxy Control
359-
360-
- **HTTPS**: Determines the target server name by reading the SNI field, without terminating TLS. Certificate validation is unaffected.
361-
- **HTTP**: Domain determination via Host header.
362-
- **Dynamic allowlist**: Controlled via environment variables.
363-
364-
#### Network Isolation
365-
366-
- **CNI configuration**: Places temporary containers from BuildKit RUN steps into isolated-net (buildkit0 bridge, 172.20.0.0/24).
367-
- **iptables**: Drops all FORWARD from buildkit0, also blocks direct access to buildkitd API.
368-
- **Gateway enforcement**: All traffic must go through the proxy on 172.20.0.1.
369-
370-
### Attack Resistance
371-
372-
#### SNI Spoofing
373-
374-
An attacker may attempt to set the SNI field in a TLS ClientHello to an allowed domain while actually trying to reach an unauthorized server.
375-
376-
**Why this is prevented:** The proxy resolves the domain name presented in the SNI field using external DNS and forwards the connection to the resulting IP address. Regardless of what SNI value the client provides, the proxy always connects to the legitimate server for that domain — never to an attacker-controlled server.
377-
378-
#### Encrypted Client Hello (ECH)
379-
380-
TLS 1.3 Encrypted Client Hello (ECH) encrypts the true SNI, which could theoretically bypass SNI-based filtering.
381-
382-
**Why this is prevented:** ECH requires the client to obtain ECHConfig public keys via DNS HTTPS (type 65) records. The internal DNS server has no upstream resolvers and cannot return these records, so build containers can never initiate an ECH handshake.
383-
384-
#### DNS Tunneling
385-
386-
An attacker may attempt to encode data into DNS queries to exfiltrate information or establish communication with external servers.
387-
388-
**Why this is prevented:** The internal DNS server has no upstream resolvers and answers all queries locally. Additionally, iptables rules block direct DNS traffic to any external server. With no path for DNS queries to reach the outside, encoded data has no route to an attacker's infrastructure.
389-
390-
#### Non-TCP Protocol Tunneling (ICMP, UDP, QUIC)
391-
392-
An attacker may attempt to tunnel data using non-TCP protocols such as ICMP echo packets, raw UDP, or QUIC (HTTP/3) to bypass the proxy.
393-
394-
**Why this is prevented:** The iptables FORWARD rule drops all traffic from the isolated network regardless of protocol — not just TCP. Since the proxy only handles TCP-based HTTP and HTTPS connections, there is no exit path for UDP or ICMP traffic. QUIC, which relies on UDP, is also blocked as a result.
395-
396-
#### IPv6 Bypass
397-
398-
An attacker may attempt to use IPv6 to circumvent IPv4-based iptables rules.
399-
400-
**Why this is prevented:** Equivalent ip6tables rules drop all forwarded IPv6 traffic from the isolated network. Additionally, the internal DNS server returns an empty IPv6 address for all queries, effectively disabling IPv6 name resolution within build containers.
401-
402-
#### Alternative DNS Transports (DoH / DoT)
403-
404-
An attacker may attempt to use DNS over HTTPS (DoH) or DNS over TLS (DoT) to bypass the internal DNS server and resolve domains through encrypted channels.
405-
406-
**Why this is prevented:** DoT uses port 853, which the proxy does not listen on — making it unreachable from the isolated network. DoH operates over HTTPS and is therefore subject to the same SNI-based allowlist check as any other HTTPS connection. Only DoH servers hosted on explicitly allowed domains could be reached, and exploiting them would require the same preconditions as domain fronting (the attacker must control infrastructure behind an allowed domain).
407-
408-
### Known Limitations
409-
410-
#### Domain Fronting
411-
412-
buildcage inspects the **SNI (Server Name Indication)** field in HTTPS connections but cannot decrypt the actual request content inside the TLS tunnel. This creates a potential bypass technique called "domain fronting."
413-
414-
**How it works:**
415-
416-
```
417-
Attack flow:
418-
1. ClientHello SNI: allowed.example.com ← buildcage only sees this → ✅ allowed
419-
2. HTTP Host header: malicious.example.com ← encrypted, cannot be inspected
420-
3. CDN routes based on Host header → reaches attacker's server
421-
```
422-
423-
For this attack to succeed, the allowed domain and the attack target domain must reside on **the same CDN or hosting infrastructure**.
424-
425-
**Why we don't prevent this:**
426-
427-
To fully defend against domain fronting, the proxy would need to terminate TLS (MITM) and inspect HTTP contents. However, this presents significant challenges:
428-
429-
- **MITM CA certificate generation and management** — The proxy would need to generate TLS certificates for each domain on the fly.
430-
- **CA certificate injection into build containers** — Build containers generated by BuildKit's OCI worker have independent filesystems, making it technically difficult to trust a MITM CA (would require modifications to buildkitd itself).
431-
- **Interference with TLS validation** — Trusting a self-signed CA would affect normal TLS certificate validation within build containers.
432-
433-
Given these implementation costs versus the strict preconditions for the attack (the attacker's server must be on the same infrastructure as the allowed domain), this is treated as an **accepted risk**.
434-
435-
**Mitigation strategies:**
436-
437-
- **Keep allowed domains to a minimum** — Only specify the domains you need in `allowed_http_domains` / `allowed_https_domains`.
438-
- **Be specific with allowed domains** — Avoid broad wildcard CDN domains (e.g., `*.cdn.example.com`) when possible.
439-
- **Use service-specific domains** — Prefer `registry.npmjs.org` over generic CDN wildcard domains.
440-
- **Major CDN countermeasures** — Major CDN providers like CloudFront and Cloudflare have already introduced measures to restrict domain fronting. Consult your CDN provider's documentation for current details.
441-
- **Regular audits** — Periodically run in audit mode to detect anomalies in connection patterns.
442-
443-
---
353+
The only known bypass is **domain fronting** — a technique where an attacker sets the SNI to an allowed domain but routes the actual request to a different server on the same CDN. This requires the attacker's server to share infrastructure with an allowed domain, making it a narrow attack surface. See [Known Limitations](./docs/security.md#known-limitations) for details and mitigation strategies.
444354

445355
## FAQ
446356

docs/security.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Security Details
2+
3+
This document provides in-depth technical details on how buildcage enforces network isolation during Docker builds.
4+
5+
For a high-level overview, see the [Security Considerations](../README.md#security-considerations) section in the README.
6+
7+
## Security Mechanisms
8+
9+
### Direct IP Address Connections
10+
11+
All connections using direct IP addresses from within RUN steps (e.g., `curl http://1.2.3.4/`) are **blocked by iptables**. All outbound connections must go through the proxy via domain names.
12+
13+
This is intentional — it ensures all traffic can be inspected and logged.
14+
15+
### DNS-Level Control
16+
17+
- **Full redirect**: Returns the proxy IP for all DNS queries.
18+
- **ECH prevention**: The internal DNS server operates without any upstream resolvers, so DNS HTTPS (type 65) records — required to initiate Encrypted Client Hello (ECH) — are never returned to build containers.
19+
20+
### HTTP/HTTPS Proxy Control
21+
22+
- **HTTPS**: Determines the target server name by reading the SNI field, without terminating TLS. Certificate validation is unaffected.
23+
- **HTTP**: Domain determination via Host header.
24+
- **Dynamic allowlist**: Controlled via environment variables.
25+
26+
### Network Isolation
27+
28+
- **CNI configuration**: Places temporary containers from BuildKit RUN steps into isolated-net (buildkit0 bridge, 172.20.0.0/24).
29+
- **iptables**: Drops all FORWARD from buildkit0, also blocks direct access to buildkitd API.
30+
- **Gateway enforcement**: All traffic must go through the proxy on 172.20.0.1.
31+
32+
## Attack Resistance
33+
34+
The following attack vectors are defended against by buildcage's architecture.
35+
36+
### SNI Spoofing
37+
38+
An attacker may attempt to set the SNI field in a TLS ClientHello to an allowed domain while actually trying to reach an unauthorized server.
39+
40+
**Why this is prevented:** The proxy resolves the domain name presented in the SNI field using external DNS and forwards the connection to the resulting IP address. Regardless of what SNI value the client provides, the proxy always connects to the legitimate server for that domain — never to an attacker-controlled server.
41+
42+
### Encrypted Client Hello (ECH)
43+
44+
TLS 1.3 Encrypted Client Hello (ECH) encrypts the true SNI, which could theoretically bypass SNI-based filtering.
45+
46+
**Why this is prevented:** ECH requires the client to obtain ECHConfig public keys via DNS HTTPS (type 65) records. The internal DNS server has no upstream resolvers and cannot return these records, so build containers can never initiate an ECH handshake.
47+
48+
### DNS Tunneling
49+
50+
An attacker may attempt to encode data into DNS queries to exfiltrate information or establish communication with external servers.
51+
52+
**Why this is prevented:** The internal DNS server has no upstream resolvers and answers all queries locally. Additionally, iptables rules block direct DNS traffic to any external server. With no path for DNS queries to reach the outside, encoded data has no route to an attacker's infrastructure.
53+
54+
### Non-TCP Protocol Tunneling (ICMP, UDP, QUIC)
55+
56+
An attacker may attempt to tunnel data using non-TCP protocols such as ICMP echo packets, raw UDP, or QUIC (HTTP/3) to bypass the proxy.
57+
58+
**Why this is prevented:** The iptables FORWARD rule drops all traffic from the isolated network regardless of protocol — not just TCP. Since the proxy only handles TCP-based HTTP and HTTPS connections, there is no exit path for UDP or ICMP traffic. QUIC, which relies on UDP, is also blocked as a result.
59+
60+
### IPv6 Bypass
61+
62+
An attacker may attempt to use IPv6 to circumvent IPv4-based iptables rules.
63+
64+
**Why this is prevented:** Equivalent ip6tables rules drop all forwarded IPv6 traffic from the isolated network. Additionally, the internal DNS server returns an empty IPv6 address for all queries, effectively disabling IPv6 name resolution within build containers.
65+
66+
### Alternative DNS Transports (DoH / DoT)
67+
68+
An attacker may attempt to use DNS over HTTPS (DoH) or DNS over TLS (DoT) to bypass the internal DNS server and resolve domains through encrypted channels.
69+
70+
**Why this is prevented:** DoT uses port 853, which the proxy does not listen on — making it unreachable from the isolated network. DoH operates over HTTPS and is therefore subject to the same SNI-based allowlist check as any other HTTPS connection. Only DoH servers hosted on explicitly allowed domains could be reached, and exploiting them would require the same preconditions as domain fronting (the attacker must control infrastructure behind an allowed domain).
71+
72+
## Known Limitations
73+
74+
### Domain Fronting
75+
76+
buildcage inspects the **SNI (Server Name Indication)** field in HTTPS connections but cannot decrypt the actual request content inside the TLS tunnel. This creates a potential bypass technique called "domain fronting."
77+
78+
**How it works:**
79+
80+
```
81+
Attack flow:
82+
1. ClientHello SNI: allowed.example.com ← buildcage only sees this → ✅ allowed
83+
2. HTTP Host header: malicious.example.com ← encrypted, cannot be inspected
84+
3. CDN routes based on Host header → reaches attacker's server
85+
```
86+
87+
For this attack to succeed, the allowed domain and the attack target domain must reside on **the same CDN or hosting infrastructure**.
88+
89+
**Why we don't prevent this:**
90+
91+
To fully defend against domain fronting, the proxy would need to terminate TLS (MITM) and inspect HTTP contents. However, this presents significant challenges:
92+
93+
- **MITM CA certificate generation and management** — The proxy would need to generate TLS certificates for each domain on the fly.
94+
- **CA certificate injection into build containers** — Build containers generated by BuildKit's OCI worker have independent filesystems, making it technically difficult to trust a MITM CA (would require modifications to buildkitd itself).
95+
- **Interference with TLS validation** — Trusting a self-signed CA would affect normal TLS certificate validation within build containers.
96+
97+
Given these implementation costs versus the strict preconditions for the attack (the attacker's server must be on the same infrastructure as the allowed domain), this is treated as an **accepted risk**.
98+
99+
**Mitigation strategies:**
100+
101+
- **Keep allowed domains to a minimum** — Only specify the domains you need in `allowed_http_domains` / `allowed_https_domains`.
102+
- **Be specific with allowed domains** — Avoid broad wildcard CDN domains (e.g., `*.cdn.example.com`) when possible.
103+
- **Use service-specific domains** — Prefer `registry.npmjs.org` over generic CDN wildcard domains.
104+
- **Major CDN countermeasures** — Major CDN providers like CloudFront and Cloudflare have already introduced measures to restrict domain fronting. Consult your CDN provider's documentation for current details.
105+
- **Regular audits** — Periodically run in audit mode to detect anomalies in connection patterns.

0 commit comments

Comments
 (0)