{"record":{"id":"3cd8a3e00d3ee905","repo":"JuliusBrussee/caveman","slug":"awscreds-aws-ec2-metadata-service-endpoint-is-not-a-valid","errorCode":null,"errorMessage":"awscreds: AWS_EC2_METADATA_SERVICE_ENDPOINT is not a valid URL","messagePattern":"awscreds: AWS_EC2_METADATA_SERVICE_ENDPOINT is not a valid URL","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/awscreds/awscreds.go","lineNumber":522,"sourceCode":"\t\treturn nil\n\tcase \"http\":\n\t\tif plaintextHostAllowed(u.Hostname(), containerCredentialHosts) {\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"awscreds: refusing plaintext container credentials endpoint at host %q (allowed: loopback, 169.254.170.2, 169.254.170.23, fd00:ec2::23)\", u.Hostname())\n\tdefault:\n\t\treturn fmt.Errorf(\"awscreds: unsupported container credentials scheme %q\", u.Scheme)\n\t}\n}\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}","sourceCodeStart":504,"sourceCodeEnd":540,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/shared/platform/awscreds/awscreds.go#L504-L540","documentation":"checkIMDSEndpoint validates AWS_EC2_METADATA_SERVICE_ENDPOINT: it must parse as a URL with a non-empty host, and be https or http to loopback/link-local IMDS addresses. This guard exists because the variable was previously dialed verbatim by the proxy-ignoring IMDS client, so any host named there became a proxy-bypassing request carrying the IMDSv2 token. A value that fails to parse or has an empty host yields this error.","triggerScenarios":"fromIMDS runs while AWS_EC2_METADATA_SERVICE_ENDPOINT is unset-but-nonempty-garbage, contains only a scheme with no host ('http://'), or otherwise fails url.Parse.","commonSituations":"Setting the endpoint to a bare hostname without scheme, truncated env values from misquoted shell exports, or an endpoint config written as '169.254.169.254' instead of 'http://169.254.169.254'.","solutions":["Set AWS_EC2_METADATA_SERVICE_ENDPOINT to a full URL including scheme and host, e.g. http://169.254.169.254/latest or https://custom-endpoint","Check shell/export quoting so the value is not truncated or space-split","Remove the variable entirely to use the default IMDS endpoint"],"exampleFix":"// before\nexport AWS_EC2_METADATA_SERVICE_ENDPOINT=169.254.169.254\n// after\nexport AWS_EC2_METADATA_SERVICE_ENDPOINT=http://169.254.169.254\n","handlingStrategy":"validation","validationCode":"func imdsEndpointIsValid(raw string) bool {\n\tu, err := url.Parse(raw)\n\tif err != nil || u.Host == \"\" { return false }\n\tif u.Scheme == \"https\" { return true }\n\tif u.Scheme == \"http\" {\n\t\th := u.Hostname()\n\t\treturn h == \"169.254.169.254\" || h == \"fd00:ec2::254\" || h == \"localhost\" || strings.HasPrefix(h, \"127.\")\n\t}\n\treturn false\n}\n","typeGuard":null,"tryCatchPattern":"if ep := os.Getenv(\"AWS_EC2_METADATA_SERVICE_ENDPOINT\"); ep != \"\" {\n\tif err := awscreds.CheckIMDSEndpoint(ep); err != nil {\n\t\t// unset or correct the variable before credential resolution\n\t}\n}\n","preventionTips":["Always include scheme and host in the endpoint value","Omit the variable to use the default IMDS endpoint","Validate env values in a startup check before relying on them"],"tags":["aws","imds","url-validation","ssrf"],"backgroundTag":"invalid-url-format","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"}