{"record":{"id":"a61cd7792e4e77dd","repo":"JuliusBrussee/caveman","slug":"awscreds-refusing-plaintext-imds-endpoint-at-host-q-allowed","errorCode":null,"errorMessage":"awscreds: refusing plaintext IMDS endpoint at host %q (allowed: loopback, 169.254.169.254, fd00:ec2::254)","messagePattern":"awscreds: refusing plaintext IMDS endpoint at host %q \\(allowed: loopback, 169\\.254\\.169\\.254, fd00:ec2::254\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/awscreds/awscreds.go","lineNumber":531,"sourceCode":"}\n\n// checkIMDSEndpoint is checkContainerURI for AWS_EC2_METADATA_SERVICE_ENDPOINT.\n// That variable was taken verbatim and then dialled with p.link — the client\n// that deliberately ignores every proxy setting — so any host named there became\n// a proxy-bypassing outbound request with the IMDSv2 token attached.\nfunc checkIMDSEndpoint(raw string) error {\n\tu, err := url.Parse(raw)\n\tif err != nil || u.Host == \"\" {\n\t\treturn errors.New(\"awscreds: AWS_EC2_METADATA_SERVICE_ENDPOINT is not a valid URL\")\n\t}\n\tswitch u.Scheme {\n\tcase \"https\":\n\t\treturn nil\n\tcase \"http\":\n\t\tif plaintextHostAllowed(u.Hostname(), imdsHosts) {\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"awscreds: refusing plaintext IMDS endpoint at host %q (allowed: loopback, 169.254.169.254, fd00:ec2::254)\", u.Hostname())\n\tdefault:\n\t\treturn fmt.Errorf(\"awscreds: unsupported IMDS endpoint scheme %q\", u.Scheme)\n\t}\n}\n\nfunc (p *Provider) fromIMDS(ctx context.Context) (*result, error) {\n\tif strings.EqualFold(p.env(\"AWS_EC2_METADATA_DISABLED\"), \"true\") {\n\t\treturn nil, nil\n\t}\n\tbase := p.env(\"AWS_EC2_METADATA_SERVICE_ENDPOINT\")\n\tif base == \"\" {\n\t\tbase = defaultIMDSBase\n\t}\n\tif err := checkIMDSEndpoint(base); err != nil {\n\t\treturn nil, err\n\t}\n\tbase = strings.TrimSuffix(base, \"/\")\n","sourceCodeStart":513,"sourceCodeEnd":549,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/shared/platform/awscreds/awscreds.go#L513-L549","documentation":"checkIMDSEndpoint rejects an IMDS endpoint (AWS_EC2_METADATA_SERVICE_ENDPOINT) that uses plain http:// to a host not on its allowlist (loopback, 169.254.169.254, fd00:ec2::254). Like the container check, it prevents IMDS tokens/credentials from being sent over plaintext HTTP to arbitrary hosts.","triggerScenarios":"AWS_EC2_METADATA_SERVICE_ENDPOINT is set to an http:// URL with a hostname other than loopback or the EC2 metadata link-local addresses; runs before fromIMDS makes any request.","commonSituations":"Redirecting IMDS at a test/staging metadata simulator on a LAN hostname over http; typos in the endpoint; a custom IMDS proxy bound to a non-loopback address; leftover endpoint config from a hybrid-cloud setup.","solutions":["Use the default endpoint (http://169.254.169.254/latest) or set AWS_EC2_METADATA_SERVICE_ENDPOINT to exactly that host.","Serve the metadata endpoint over https:// if it is remote.","Bind a custom IMDS simulator to 127.0.0.1 and point the env var at the loopback URL.","Unset AWS_EC2_METADATA_SERVICE_ENDPOINT when running on real EC2 instances."],"exampleFix":"// before\nos.Setenv(\"AWS_EC2_METADATA_SERVICE_ENDPOINT\", \"http://imds.lab.internal\")\n// after\nos.Setenv(\"AWS_EC2_METADATA_SERVICE_ENDPOINT\", \"http://127.0.0.1:8080\") // simulator on loopback","handlingStrategy":"validation","validationCode":"u, _ := url.Parse(os.Getenv(\"AWS_EC2_METADATA_SERVICE_ENDPOINT\"))\nimdsOK := map[string]bool{\"169.254.169.254\": true, \"127.0.0.1\": true, \"::1\": true, \"fd00:ec2::254\": true}\nif u != nil && u.Scheme == \"http\" && !imdsOK[u.Hostname()] {\n    return fmt.Errorf(\"IMDS endpoint %q not allowed over plaintext http\", u.Host)\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"refusing plaintext IMDS\") {\n    log.Fatal(\"use the default IMDS endpoint or bind your simulator to loopback\")\n}","preventionTips":["Leave AWS_EC2_METADATA_SERVICE_ENDPOINT unset on real EC2 instances","Point IMDS-mock tooling at 127.0.0.1 only","Review any endpoint override in code review for plaintext http on non-loopback hosts"],"tags":["aws","security","imds","ssrf","plaintext-http"],"backgroundTag":"invalid-config-value","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}