`container system dns create` unvalidated domain name allows pf rule injection
LowPublished Apr 30, 2026 · updated Aug 22, 2026
## Impact A local user granted only narrow `sudo` access to run `container system dns create --localhost`, or an automated pipeline that passes attacker-influenced data as the domain-name argument, may be able to embed a newline in the domain name to inject an arbitrary rule into the macOS packet-filter (`pf`) configuration — beyond the single `rdr ... -> 127.0.0.1` rule the command is documented to produce. The same unvalidated domain name reaches `dns create`'s and `dns delete`'s resolver-file path construction. If a subdirectory — or a symlink to a directory — exists under `/etc/resolver`, an attacker may be able to craft a path that appends `..` components to the subdirectory's path to traverse outside of `/etc/resolver`. Nothing in either command's normal flow creates such a subdirectory or symlink, so someone would first have to plant it there separately — and whoever can do that already has enough access to skip this bug entirely. ## Details `Parser.isValidDomainName` already existed in the codebase as a validator for domain-name input, but neither `DNSCreate.run()` nor `DNSDelete.run()` called it before passing the raw `domainName` string onward. That unvalidated string...
Affected versions
| Package | Affected | Fixed in |
|---|---|---|
| container Product | < 0.12.3 | 0.12.3 |
Details and references
## Impact A local user granted only narrow `sudo` access to run `container system dns create --localhost`, or an automated pipeline that passes attacker-influenced data as the domain-name argument, may be able to embed a newline in the domain name to inject an arbitrary rule into the macOS packet-filter (`pf`) configuration — beyond the single `rdr ... -> 127.0.0.1` rule the command is documented to produce. The same unvalidated domain name reaches `dns create`'s and `dns delete`'s resolver-file path construction. If a subdirectory — or a symlink to a directory — exists under `/etc/resolver`, an attacker may be able to craft a path that appends `..` components to the subdirectory's path to traverse outside of `/etc/resolver`. Nothing in either command's normal flow creates such a subdirectory or symlink, so someone would first have to plant it there separately — and whoever can do that already has enough access to skip this bug entirely. ## Details `Parser.isValidDomainName` already existed in the codebase as a validator for domain-name input, but neither `DNSCreate.run()` nor `DNSDelete.run()` called it before passing the raw `domainName` string onward. That unvalidated string reaches two independent sinks: - `PacketFilter.createRedirectRule` interpolates the domain name as a trailing `#`-comment on a `pf` rule line, with no escaping, before that line is written to `/etc/pf.anchors/com.apple.container` and loaded via `pfctl -f`. A domain name containing a newline terminates the comment and starts a new, fully attacker-controlled `pf` directive — the injected rule can specify any `from`/`to` address and any rule type (`rdr`, `pass`, `block`, `nat`), not just the `redirect-to-127.0.0.1` shape a legitimate invocation produces. - `HostDNSResolver.createDomain`/`deleteDomain` build a file path with `configURL.appending(path: "containerization.\(name)")`. `URL.appending(path:)` does not percent-encode `/`, so a name containing path-traversal sequences becomes part of the literal path string. Resolving that path still follows ordinary filesystem semantics, though: a `..` component only has an effect if the preceding path component already resolves to a directory or a symlink to one, and `containerization.<name>` is never a directory (or such a symlink) anywhere in this codebase's normal operation — so this mechanism only escapes `/etc/resolver` if that directory or symlink was already planted there by a separate privileged action. ## Affected code - `Sources/ContainerCommands/System/DNS/DNSCreate.swift` and `DNSDelete.swift` — accept `domainName` and forward it without calling `Parser.isValidDomainName`. - `Sources/Services/ContainerAPIService/Client/PacketFilter.swift` (`createRedirectRule`) — unescaped domain-name comment on a `pf` rule line. - `Sources/Services/ContainerAPIService/Client/HostDNSResolver.swift` (`createDomain`/`deleteDomain`) — unconfined resolver-file path construction. **Not affected:** `dns delete`'s `PacketFilter.removeRedirectRule` never writes a new `pf` rule — it only builds the expected rule string to find and strip a matching existing line — so the `pf`-injection vector is reachable only through `dns create --localhost`. The path-construction issue is reachable from both `create` and `delete`, but only under the directory-already-exists precondition described above, which normal usage of either command never produces on its own. ## Mitigations 1. Upgrade to `container` 0.12.3 or later, which validates the domain name against RFC 1035 hostname-label rules (rejecting newlines, `/`, and other non-hostname characters) before it reaches either the `pf` anchor file or the resolver path construction, in both `dns create` and `dns delete`. 2. If you can't upgrade immediately, don't delegate `sudo` access to `container system dns create`/`dns delete` to any principal or automated pipeline that sources the domain-name argument from data you don't fully trust (container labels, imag
- Severity from
- GitHub (reviewed advisory)
More Apple advisories
All Apple| Date | Advisory | Severity | Fixed in |
|---|---|---|---|
| May 21 | HTTP/2-to-HTTP/1 Request Smuggling via unvalidated :path pseudo-header in HTTP2ToHTTP1Codec | Low | 1.44.0 |
| May 21 | NIOHTTPRequestDecompressor ratio limit bypass via inflated Content-Length | Medium | 1.34.1 |
| May 21 | NIOHTTP1 HTTPDecoder accepts unbounded HTTP/1 header blocks, enabling remote DoS | Medium | 2.100.0 |
| May 21 | Out-of-bounds write via ByteBuffer index and length UInt32 overflow | High | 2.100.0 |
| May 21 | CRLF Injection in outbound HTTP request URI via NIOHTTPRequestHeadersValidator | Medium | 2.100.0 |
| Apr 30 | Insecure Hostname Validation Allows HTTP Downgrade Attack | Medium6.9 | 0.12.3 |