{"record":{"id":"5f7d97131c145bc4","repo":"JuliusBrussee/caveman","slug":"bedrock-malformed-aws-credentials-want-accesskey","errorCode":null,"errorMessage":"bedrock: malformed AWS credentials (want accessKeyId:secretAccessKey[:sessionToken])","messagePattern":"bedrock: malformed AWS credentials \\(want accessKeyId:secretAccessKey\\[:sessionToken\\]\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/providers/bedrock/signing.go","lineNumber":230,"sourceCode":"\t\tif strings.HasPrefix(key, \"AKIA\") || strings.HasPrefix(key, \"ASIA\") {\n\t\t\treturn \"aws_access_keys\", nil\n\t\t}\n\t\treturn \"bedrock_api_key\", nil\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"bedrock: unsupported credential auth kind\")\n\t}\n}\n\n// parseAWSCredentials decodes the \"accessKeyId:secretAccessKey[:sessionToken]\"\n// form carried in x-cave-upstream-key into awssig.Credentials. It fails closed:\n// a missing access key or secret is an error, never an unsigned passthrough.\nfunc parseAWSCredentials(raw string) (awssig.Credentials, error) {\n\tif raw == \"\" {\n\t\treturn awssig.Credentials{}, fmt.Errorf(\"bedrock: missing AWS credentials in x-cave-upstream-key\")\n\t}\n\tparts := strings.SplitN(raw, \":\", 3)\n\tif len(parts) < 2 || parts[0] == \"\" || parts[1] == \"\" {\n\t\treturn awssig.Credentials{}, fmt.Errorf(\"bedrock: malformed AWS credentials (want accessKeyId:secretAccessKey[:sessionToken])\")\n\t}\n\tcreds := awssig.Credentials{AccessKeyID: parts[0], SecretAccessKey: parts[1]}\n\tif len(parts) == 3 {\n\t\tcreds.SessionToken = parts[2]\n\t}\n\treturn creds, nil\n}\n\n// copyIfPresent copies a header from src to dst when present (case-insensitive).\nfunc copyIfPresent(dst, src http.Header, name string) {\n\tif values := src.Values(name); len(values) > 0 {\n\t\tfor _, v := range values {\n\t\t\tdst.Add(name, v)\n\t\t}\n\t}\n}\n","sourceCodeStart":212,"sourceCodeEnd":247,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/proxy/providers/bedrock/signing.go#L212-L247","documentation":"The credential string is expected as accessKeyId:secretAccessKey[:sessionToken]. If splitting on \":\" (max 3 parts) yields fewer than 2 parts, or the access key or secret part is empty, the value is malformed and rejected so no partial SigV4 credentials are ever used.","triggerScenarios":"parseAWSCredentials receives a non-empty string that is not colon-form: a lone access key (\"AKIA...\"), only a secret, \":secret\" with empty key part, \"key:\" with empty secret part, or a key pasted with the colon omitted.","commonSituations":"Storing only the AWS access key ID in x-cave-upstream-key; copying the key pair but dropping the colon or pasting only one half; a session-token-only value; config tools stripping the colon or splitting the value across fields.","solutions":["Set the value to the complete accessKeyId:secretAccessKey form (append :sessionToken if using temporary credentials)","Verify no intermediate config step split or trimmed the colon-delimited value","If you only have a Bedrock API key (not IAM keys), do not use it here — set it as a plain key so it is inferred as bedrock_api_key"],"exampleFix":"// before\n// x-cave-upstream-key: AKIAIOSFODNN7EXAMPLE\n// after\n// x-cave-upstream-key: AKIAIOSFODNN7EXAMPLE:wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY","handlingStrategy":"validation","validationCode":"func validAWSKeyForm(raw string) bool {\n\tparts := strings.SplitN(raw, \":\", 3)\n\treturn len(parts) >= 2 && parts[0] != \"\" && parts[1] != \"\"\n}\nif !validAWSKeyForm(raw) { return errors.New(\"x-cave-upstream-key must be accessKeyId:secretAccessKey[:sessionToken]\") }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate the colon form whenever AWS keys are stored or rotated","Never store only the access key ID","Add a smoke test that parses stored credentials at deploy time"],"tags":["bedrock","aws","credentials","format"],"backgroundTag":"invalid-argument-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"}