BudgetScan

Valid IPv4-embedded IPv6 addresses with '::' immediately before the IPv4 tail are rejected

low swesweep-fasthttp · ipv6.go · validateIPv6Literal · run #4

Description

For addresses like "1:2:3:4:5::1.2.3.4", the code sets seenDoubleAtSplit and strips one colon, leaving head with a trailing single colon. parseIPv6Hextets(head, false) then rejects the trailing colon, so syntactically valid IPv6 literals are reported as invalid. This can cause valid IP hosts to be misclassified as hostnames or rejected, leading to unexpected DNS lookups or denial-of-service in callers that use the validator for routing decisions.

Triage

Not triaged.

Raw scan report for this file

This file implements Go slice/byte parsing helpers, so the main risks are not classic C memory corruption but validation logic bugs that can be triggered by attacker-controlled host bytes. I traced `host` through `validateIPv6Literal`, then into `parseIPv6Hextets` and `validIPv4`.

### Bounds / panic analysis

- `validateIPv6Literal` checks `len(host) == 0` before `host[0]`.
- `bytes.IndexByte` and `bytes.LastIndexByte` are safe for empty/nil slices.
- `addr := host[1:end]` is only reached when `end > 1`.
- `addr[lastColon-1]` is guarded by `lastColon > 0`.
- `ipv4 := addr[lastColon+1:]` is guarded by `lastColon != len(addr)-1`.
- `parseIPv6Hextets` only dereferences `s[i+1]` after ensuring `i+1 < n` or after handling the end-of-string case.
- `validIPv4` only accesses `s[start]` when `digits > 1`.
- No fixed-size buffers, no integer overflow in `validIPv4` because digit length and value are bounded, no goroutines, no shared mutable state, no `unsafe`, no command/SQL execution.

So I did not find a slice-out-of-bounds, nil dereference, panic, race condition, or unbounded allocation issue in this file.

### Security-relevant validation issues

1. **Bytes after the first `]` are ignored.**  
   `validateIPv6Literal` finds the first `]` and uses that as the end of the IPv6 address, but it never verifies that this `]` is the final byte of the host. Therefore inputs like `[::1]junk` or `[::1]:80]` are accepted as valid bracketed IPv6 host literals. Since host bytes are attacker-controlled, this can let an attacker append arbitrary trailing data to an otherwise valid IPv6 literal. If the caller then uses the original host in a `Host` header, request line, dial string, or any IP-literal gating logic, this can lead to protocol confusion, header/request injection, or bypass of IP-literal restrictions.

2. **IPv6 zone is not restricted.**  
   When `%` is present, the code only rejects an empty zone. Everything after the first `%` up to the first `]` is accepted unchanged. The zone can contain colons, extra percents, and, if raw host bytes are accepted by the caller, control characters. This is too permissive for a strict HTTP IPv6 host literal validator and can create ambiguous or unsafe host values in downstream consumers.

3. **Some valid IPv4-embedded IPv6 addresses with `::` immediately before the IPv4 tail are rejected.**  
   For example, `1:2:3:4:5::1.2.3.4` is a valid IPv6 text representation, but the code strips one colon for `seenDoubleAtSplit`, leaving a head ending in a single trailing colon. `parseIPv6Hextets(head, false)` then rejects the trailing colon. This is primarily a correctness/availability issue, but it can cause valid IP literals to be misclassified as hostnames or rejected, which may affect caller behavior.

```json
[
  {
    "severity": "high",
    "title": "IPv6 host validation bypass via bytes after first closing bracket",
    "function": "validateIPv6Literal",
    "description": "validateIPv6Literal finds the first ']' with bytes.IndexByte and uses host[1:end] as the address, but never checks that end is the final byte. Inputs such as \"[::1]junk\" or \"[::1]:80]\" are accepted as valid bracketed IPv6 host literals. Because host bytes are attacker-controlled, this can allow trailing data to bypass validation and cause protocol confusion, Host/request-line injection, or bypass of IP-literal restrictions in callers that trust the validator."
  },
  {
    "severity": "medium",
    "title": "Unvalidated IPv6 zone allows arbitrary bytes",
    "function": "validateIPv6Literal",
    "description": "When a '%' is present, the code only rejects an empty zone and removes everything from the first percent onward. The zone may contain colons, additional percents, and other control characters. If the validated host is later placed in a Host header, request line, or dial string, this can produce ambiguous or unsafe host values. A strict HTTP IPv6 host validator should restrict zone characters or reject zones in this context."
  },
  {
    "severity": "low",
    "title": "Valid IPv4-embedded IPv6 addresses with '::' immediately before the IPv4 tail are rejected",
    "function": "validateIPv6Literal",
    "description": "For addresses like \"1:2:3:4:5::1.2.3.4\", the code sets seenDoubleAtSplit and strips one colon, leaving head with a trailing single colon. parseIPv6Hextets(head, false) then rejects the trailing colon, so syntactically valid IPv6 literals are reported as invalid. This can cause valid IP hosts to be misclassified as hostnames or rejected, leading to unexpected DNS lookups or denial-of-service in callers that use the validator for routing decisions."
  }
]
```