Skip to content

Trim trailing dot from trusted IMDS hostnames#428

Open
bitterpanda63 wants to merge 2 commits into
mainfrom
fix/trusted-hostname-trailing-dot
Open

Trim trailing dot from trusted IMDS hostnames#428
bitterpanda63 wants to merge 2 commits into
mainfrom
fix/trusted-hostname-trailing-dot

Conversation

@bitterpanda63

@bitterpanda63 bitterpanda63 commented Jun 8, 2026

Copy link
Copy Markdown
Member

Summary

DNS resolvers sometimes return fully-qualified domain names with a trailing dot (e.g. metadata.google.internal.). The previous direct map lookup in isTrustedHostname did not match this form, so GCP IMDS requests could be incorrectly flagged as stored SSRF.

  • Normalize with strings.ToLower + strings.TrimRight(hostname, ".") before the map lookup
  • Add "strings" import

This is the same fix already applied in firewall-go (PR #459). Ported to Python, Ruby, .NET, PHP, and Java.

Test plan

  • Go tests in lib/request-processor/ pass

Summary by Aikido

Security Issues: 0 🔍 Quality Issues: 1 Resolved Issues: 0

🐛 Bugfixes

  • Normalized and trimmed trailing dots before trusted hostname comparison
  • Stripped trailing dot in NormalizeHostname to handle FQDNs

🔧 Refactors

  • Added helpers import and routed hostname checks through helper

More info

bitterpanda63 and others added 2 commits June 8, 2026 17:03
DNS resolvers may return hostnames with a trailing dot (FQDN form),
e.g. `metadata.google.internal.`. The direct map lookup failed to match
these, risking false-positive stored-SSRF blocks for GCP IMDS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Instead of inlining strings.TrimRight in isTrustedHostname, route
through the existing NormalizeHostname helper (which already handles
invisible chars, URL encoding, case, and IDN). Add trailing-dot
stripping to NormalizeHostname itself so all callers get the fix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
func isTrustedHostname(hostname string) bool {
// Check if the hostname is in the trusted hosts map
_, exists := trustedHosts[hostname]
_, exists := trustedHosts[helpers.NormalizeHostname(hostname)]

@aikido-pr-checks aikido-pr-checks Bot Jun 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replacing the direct trustedHosts map lookup with helpers.NormalizeHostname(hostname) adds expensive work (URL unescape + IDN conversion) on a likely hot path; consider pre-normalizing or caching hostnames.

Suggested change
_, exists := trustedHosts[helpers.NormalizeHostname(hostname)]
_, exists := trustedHosts[hostname]
Details

✨ AI Reasoning
​The code previously did a direct map lookup of the hostname (cheap O(1)). The diff replaces that with helpers.NormalizeHostname(hostname), which runs TrimInvisible, url.QueryUnescape, strings.ToLower, and idna.ToUnicode. These operations allocate and perform non-trivial work (especially IDN conversion). Because isTrustedHostname is likely called per-request for each resolved host, this introduces a performance regression by doing expensive normalization on every check. The added TrimSuffix itself is cheap, but the overall NormalizeHostname call makes the previously trivial lookup much heavier. A lightweight alternative would be to normalize trustedHosts keys up-front or cache normalization results.

Reply @AikidoSec feedback: [FEEDBACK] to get better review comments in the future.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant