{"record":{"id":"47d44045212c80c4","repo":"thanos-io/thanos","slug":"invalid-tenant-id","errorCode":null,"errorMessage":"invalid tenant ID","messagePattern":"invalid tenant ID","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/cortex/tenant/resolver.go","lineNumber":74,"sourceCode":"\treturn &SingleResolver{}\n}\n\ntype SingleResolver struct {\n}\n\n// containsUnsafePathSegments will return true if the string is a directory\n// reference like `.` and `..` or if any path separator character like `/` and\n// `\\` can be found.\nfunc containsUnsafePathSegments(id string) bool {\n\t// handle the relative reference to current and parent path.\n\tif id == \".\" || id == \"..\" {\n\t\treturn true\n\t}\n\n\treturn strings.ContainsAny(id, \"\\\\/\")\n}\n\nvar errInvalidTenantID = errors.New(\"invalid tenant ID\")\n\nfunc (t *SingleResolver) TenantID(ctx context.Context) (string, error) {\n\t//lint:ignore faillint wrapper around upstream method\n\tid, err := user.ExtractOrgID(ctx)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif containsUnsafePathSegments(id) {\n\t\treturn \"\", errInvalidTenantID\n\t}\n\n\treturn id, nil\n}\n\nfunc (t *SingleResolver) TenantIDs(ctx context.Context) ([]string, error) {\n\torgID, err := t.TenantID(ctx)\n\tif err != nil {","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/internal/cortex/tenant/resolver.go#L56-L92","documentation":"errInvalidTenantID is returned by tenant resolvers (TenantID, TestSingleResolver) when the extracted tenant ID is unsafe — it contains path separators or unsafe path segments (e.g. \"..\", \"/\", \"\\\\\"). It guards multi-tenancy against path traversal via the X-Scope-OrgID header.","triggerScenarios":"Sending X-Scope-OrgID (or the configured tenant header) with values containing \"/\", \"\\\\\", or path segments like \"..\" so containsUnsafePathSegments returns true in resolver.go:84.","commonSituations":"Proxies/clients injecting odd tenant headers; malicious probing for path traversal in store paths; misconfigured load balancers that mangle header values; test suites expecting IDs with slashes.","solutions":["Use a tenant ID restricted to safe characters (letters, digits, dash, underscore)","Sanitize or reject such header values at the ingress/proxy before they reach Cortex","If legitimate tenants need hierarchical names, choose a different separator convention"],"exampleFix":"// before\ncurl -H 'X-Scope-OrgID: ../admin' ...\n// after\ncurl -H 'X-Scope-OrgID: tenant-admin' ...","handlingStrategy":"validation","validationCode":"var tenantIDRe = regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)\nfunc validTenantID(id string) bool { return tenantIDRe.MatchString(id) }","typeGuard":"func safeTenant(id string) bool {\n\treturn !strings.ContainsAny(id, \"\\\\/\") && !strings.Contains(id, \"..\")\n}","tryCatchPattern":"tid, err := resolver.TenantID(ctx)\nif errors.Is(err, tenant.ErrInvalidTenantID) {\n\thttp.Error(w, \"invalid tenant ID\", http.StatusBadRequest)\n\treturn\n}","preventionTips":["Restrict tenant header values to [a-zA-Z0-9_-] at ingress","Reject requests with suspicious tenant headers at the proxy (rate-limit + 400)","Never build tenant IDs from user-controlled path components"],"tags":["multi-tenancy","tenant-id","path-traversal","cortex"],"backgroundTag":"path-traversal-blocked","analyzedSha":"35b8b991177def87ed52dcf10f9b6d87f07282c8","analyzedAt":"2026-09-07T01:49:59.689Z","contentChangedAt":"2026-09-07T01:49:59.689Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}