{"record":{"id":"cad3ee19f250cdfa","repo":"rancher/rancher","slug":"extra-key-q-must-not-contain","errorCode":null,"errorMessage":"extra key %q must not contain '/'","messagePattern":"extra key %q must not contain '/'","errorType":"http","errorClass":null,"httpStatus":403,"severity":"warning","filePath":"pkg/auth/requests/sar/sar.go","lineNumber":180,"sourceCode":"}\n\nfunc parseServiceAccountUsername(username string) (namespace string, name string, err error) {\n\tnamespacedName := strings.TrimPrefix(username, serviceaccount.ServiceAccountUsernamePrefix)\n\ttokens := strings.Split(namespacedName, \":\")\n\tif len(tokens) != 2 {\n\t\treturn \"\", \"\", fmt.Errorf(\"invalid service account username format: expected system:serviceaccount:<namespace>:<name>, but got '%s'\", username)\n\t}\n\tnamespace = tokens[0]\n\tname = tokens[1]\n\treturn namespace, name, nil\n}\n\nfunc validateExtraKey(name string) error {\n\tif name == \"\" {\n\t\treturn errors.New(\"extra key must not be empty\")\n\t}\n\tif strings.Contains(name, \"/\") {\n\t\treturn fmt.Errorf(\"extra key %q must not contain '/'\", name)\n\t}\n\treturn nil\n}\n","sourceCodeStart":162,"sourceCodeEnd":184,"githubUrl":"https://github.com/rancher/rancher/blob/932558d4e68565aff2d2f36e89ec4a391b06e7c5/pkg/auth/requests/sar/sar.go#L162-L184","documentation":"Thrown by validateExtraKey (pkg/auth/requests/sar/sar.go:180) during the extras impersonation check: each Impersonation-Extra-* key becomes the subresource token 'userextras/<key>' in a SubjectAccessReview, so a '/' in the key would corrupt the resource path (parsing as subresource/subsubresource). Keys containing '/' are rejected before any API call; the denial surfaces through the extras check wrapper with 403.","triggerScenarios":"Impersonation-Extra-scopes/email-address or any extra whose header-derived key contains '/', e.g. clients encoding namespaced or path-like identifiers into the extra name.","commonSituations":"Tools mapping arbitrary claim names (OIDC claim paths like 'ext/…' or URLs) into impersonation extras; proxies joining prefix+key with a slash; copied headers from upstream systems that use path-style keys.","solutions":["Use slash-free extra keys: letters, digits, '-', '_' (e.g. 'scopes' not 'auth/scopes')","Sanitize keys client-side before setting Impersonation-Extra-* headers","Grant RBAC on the sanitized userextras/<key> resource name that actually gets sent","Check Rancher logs: the wrapped 'error checking if user can impersonate extras' chains this exact message"],"exampleFix":"# before\nImpersonation-Extra-auth/scopes: openid\n\n# after\nImpersonation-Extra-auth-scopes: openid","handlingStrategy":"validation","validationCode":"for key := range impExtras {\n\tif strings.ContainsAny(key, \"/\") || key == \"\" {\n\t\treturn fmt.Errorf(\"extra key %q invalid: no '/' or empty\", key)\n\t}\n}","typeGuard":"func validExtraKey(k string) bool { return k != \"\" && !strings.Contains(k, \"/\") }","tryCatchPattern":null,"preventionTips":["Restrict extra keys to a safe charset at the client boundary","Remember the key becomes userextras/<key> in RBAC — the grant name must match the sanitized key","Reject path-like identifiers early instead of relying on the server 403"],"tags":["impersonation","extras","validation","headers","rbac","go"],"backgroundTag":null,"analyzedSha":"932558d4e68565aff2d2f36e89ec4a391b06e7c5","analyzedAt":"2026-08-16T04:37:02.125Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}