Skip to content
AppleGHSA-39g5-644c-qwcg

`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...

GitHub advisory

Affected versions

PackageAffectedFixed in
container
Product
< 0.12.30.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

Critical advisories by email

Wednesdays: the week’s critical and high advisories in the AI and data stack, with the fixed versions. Only in weeks that have some.

Double opt-in. Unsubscribe any time.