Summary
If an operator configures an IPv6 bind address, that listener may fail to start; this only hurts the operator's own deployment.
Impact
The affected listener fails to start (or the process errors out at bootstrap) when an IPv6 bind address is configured — a self-inflicted, recoverable availability loss for the operator's own deployment.
Severity: low
Exploitability: theoretical — Trivially reproducible by the operator, but there is no external attacker — the only party who can set the value is the same party harmed by the failure, and they already control service availability.
Location
- monguard/src/config/validated.rs:252 in ListenerPort::listen_addr
- monguard/src/listeners/mod.rs:106 in build_listeners
- monguard/src/listeners/mod.rs:112 in build_listeners
- monguard/src/config/resolver.rs:810 in resolve_listener_port
- monguard/src/config/resolver.rs:869 in resolve_bind_address
Reproduction / trigger path
Analyzed trigger path from static analysis — not an executed PoC. Confirm with a concrete repro before handing off.
Attacker controls: Operator fully controls the YAML `listeners.address` / `listeners.ports[].address` string; no remote or lower-privileged input reaches this field.
- (source) monguard/src/config/loader.rs:27 in load_config — Operator-authored YAML config file is read from local disk via std::fs::read_to_string(&cli.config).
- (hop) monguard/src/config/resolver.rs:810 in resolve_listener_port — Per-port address string parsed with IpAddr::from_str — accepts IPv6 literals and stores IpAddr::V6.
- (hop) monguard/src/config/resolver.rs:869 in resolve_bind_address — Listeners-level default address likewise parsed with IpAddr::from_str — accepts IPv6.
- (hop) monguard/src/config/validated.rs:252 in ListenerPort::listen_addr — format!("{}:{}", self.address, self.port) renders IPv6 without brackets.
- (hop) monguard/src/main.rs:303 in MonguardServer::run (listener loop) — build_listener_service is invoked once per configured port at process startup.
- (hop) monguard/src/listeners/mod.rs:36 in build_listener_service — proxy_bind = port.listen_addr() — unbracketed string captured.
- (sink) monguard/src/listeners/mod.rs:112 in build_listeners — listeners.add_tcp_with_settings(bind_addr, ...) (and :106 for TLS) hands the malformed string to Pingora, which fails the socket-address parse/bind.
Root cause
- `ListenerPort.address` is typed `IpAddr` and admits IPv6 values (monguard/src/config/validated.rs:238); the resolver accepts IPv6 literals via `IpAddr::from_str` with no v4-only guard (monguard/src/config/resolver.rs:810, :869).
- `listen_addr()` formats with `format!("{}:{}", self.address, self.port)` (monguard/src/config/validated.rs:252); `IpAddr::V6`'s `Display` impl emits e.g. `::1` without square brackets, producing `::1:27017`.
- `build_listener_service` passes this string verbatim to Pingora's `add_tls_with_settings` / `add_tcp_with_settings` (monguard/src/listeners/mod.rs:36, :106, :112), which later parses it as a socket address when binding.
- Standard `SocketAddr` parsing rejects unbracketed IPv6 host:port strings, so the listener bind fails at startup.
Filed from Aegis finding 780a21ba934e (scan scan-3c7821728fe9) · primitive: Operator-authored IPv6 bind address is rendered without brackets, yielding an unparseable bind string at service startup. · categories: Crash, Other