DomainNameServers is propagated to task metadata verbatim, including values that are not valid IP addresses
- Dominant language
- Go
- Stars
- 2.2k
- Forks
- 662
- Avg merge
- 3d 22h
- Merged PRs (30d)
- 24
Description
## Summary
On a Fargate task, the v4 task metadata endpoint returned a nameserver of `" 10.221.2.239"` — with a
leading space — which is not parseable as an IP address by a conforming parser. The value originates in
the VPC's DHCP option set and appears to be passed through to the metadata response without trimming
or validation.
## Where the value comes from
The address originates in the VPC's DHCP option set, which for this VPC held:
```
domain-name-servers 10.0.0.2, 10.0.0.3
```
`describe-dhcp-options` returns those as two values, the second being `" 10.0.0.3"` with the space
retained — EC2 stores `domain-name-servers` as entered and does not appear to validate the entries.
Verified against the same API response, where `netbios-name-servers` on that option set is stored
without padding, so the space is stored data rather than a display artifact.
That value then flows DHCP option set → control plane → agent → task metadata endpoint, and nothing
along the way normalizes it.
## Expected behaviour
`DomainNameServers` in the task metadata response contains either a valid IP address or nothing. The
field is documented as nameserver IP addresses, including in this repo's own type definition
(`ecs-agent/api/attachment/eni/eni.go:44-45`):
```go
// DomainNameServers specifies the nameserver IP addresses for the eni
DomainNameServers []string `json:",omitempty"`
```
## Observed behaviour
The value is returned verbatim, including the leading space.
**Caveat on attribution:** we observed this on Fargate, where the agent is managed by AWS and not
open source, so we cannot inspect the code path that actually served this response. We are filing here
because the open-source agent contains exactly the verbatim copy that would produce this, and we assume
shared lineage — but that is an inference, not something we can verify.
In this repo, `ENIFromACS` copies the field through without normalization
(`ecs-agent/api/attachment/eni/eni.go:333-334`):
```go
for _, nameserverIP := range acsENI.DomainNameServers {
eni.DomainNameServers = append(eni.DomainNameServers, aws.ToString(nameserverIP))
}
```
`ValidateENI` (`eni.go:344`), which `ENIFromACS` calls first, already performs shape validation on
neighbouring fields — it rejects a missing `Ipv4Addresses`, a `SubnetGatewayIpv4Address` that doesn't
split into two parts on `/`, an empty `MacAddress` or `Ec2Id` — but has no check for
`DomainNameServers`.
If the Fargate agent is a separate codebase, please route this accordingly rather than closing it as
not reproducible here.
## Impact
Any consumer that parses the field with a strict IP parser fails. In Go, binding the field to
`netip.Addr` fails through `TextUnmarshaler`, and because a failing `UnmarshalText` aborts the whole
`json.Decode`, the consumer loses the *entire* metadata document — task ARN, cluster, family, launch
type — over one malformed nameserver:
```
ParseAddr(" 10.0.0.3"): unexpected character (at " 10.0.0.3")
```
The failure is also silent and permanent: the payload doesn't change, so retries don't help, and
nothing in the response indicates which field was at fault.
## Suggested fix
Either would resolve it:
1. `strings.TrimSpace` each value before appending, and skip values that still don't parse as an IP.
2. Reject or drop non-IP values in `ValidateENI`, consistent with how it already validates
`SubnetGatewayIpv4Address`.
Option 1 seems preferable for whitespace specifically, since failing the whole ENI over a cosmetically
malformed nameserver would be a worse outcome than dropping it.
The same argument applies to `DomainNameSearchList` on the following lines, which is copied the same
way.
## Steps to reproduce
Observed rather than constructed — we have not verified whether `create-dhcp-options` preserves the
padding on the way in, only that an existing option set has it stored.
1. Obtain a DHCP option set whose `domain-name-servers` has an entry with a leading space, and
associate it with a VPC. Confirm the padding is stored:
```bash
aws ec2 describe-dhcp-options --dhcp-options-ids | jq -r '
.DhcpOptions[].DhcpConfigurations[]
| select(.Key=="domain-name-servers") | .Values[].Value | @json'
```
2. Run an `awsvpc` Fargate task in that VPC.
3. From inside the task:
```bash
curl -s "$ECS_CONTAINER_METADATA_URI_V4/task" | jq '.Containers[].Networks[].DomainNameServers'
```
The padded value appears verbatim.
## Environment
- Launch type: **Fargate**
- Network mode: `awsvpc`
- Agent version: not available — the Fargate agent is managed by AWS and not reported to the task
We assume this also affects the open-source agent on EC2, since the code path above has no
normalization, but we have only observed it on Fargate.
Contributor guide
Research direction
Start in ecs-agent/api/attachment/eni/eni.go at ENIFromACS (lines 333-334) and ValidateENI (around line 344), then inspect how DomainNameServers and DomainNameSearchList are copied. Reproduce or add coverage for padded and invalid nameserver values, and confirm the metadata fields contain only valid IP addresses or no value without breaking the rest of the ENI response.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, go
- Domain
- api, networking
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100