{"record":{"id":"eb6e52636bab8dad","repo":"JuliusBrussee/caveman","slug":"compat-route-path-rejected-w","errorCode":null,"errorMessage":"compat route path rejected: %w","messagePattern":"compat route path rejected: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/providers/openaicompat/openaicompat.go","lineNumber":482,"sourceCode":"// Gateways call this with the original URL (including RawPath), while the\n// adapter MatchRoute/ResolveUpstreamURL checks provide a second fail-closed\n// boundary for direct callers.\nfunc ValidateRequestPath(u *url.URL) error {\n\tif u == nil {\n\t\treturn fmt.Errorf(\"request URL is missing\")\n\t}\n\tif !strings.HasPrefix(u.Path, \"/compat/\") {\n\t\treturn nil\n\t}\n\treturn validateCompatPath(u.Path, u.RawPath)\n}\n\nfunc validateCompatPath(path, rawPath string) error {\n\tif !strings.HasPrefix(path, \"/compat/\") {\n\t\treturn nil\n\t}\n\tif err := validatePathComponents(path, rawPath); err != nil {\n\t\treturn fmt.Errorf(\"compat route path rejected: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc validatePathComponents(path, rawPath string) error {\n\tif strings.Contains(path, `\\`) {\n\t\treturn fmt.Errorf(\"backslash is not allowed in path\")\n\t}\n\tsegments := strings.Split(path, \"/\")\n\tfor i, segment := range segments {\n\t\tif segment == \"\" && i > 0 && i < len(segments)-1 {\n\t\t\treturn fmt.Errorf(\"repeated path separators are not allowed\")\n\t\t}\n\t\tif segment == \".\" || segment == \"..\" {\n\t\t\treturn fmt.Errorf(\"dot segments are not allowed in path\")\n\t\t}\n\t}\n\t// URL.Path is decoded by net/url while RawPath retains a valid escaped","sourceCodeStart":464,"sourceCodeEnd":500,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/proxy/providers/openaicompat/openaicompat.go#L464-L500","documentation":"validateCompatPath applies strict component validation to any path under /compat/ and wraps the underlying cause with 'compat route path rejected'. It exists so a path cannot change route identity after decoding by another proxy hop. The wrapped cause is one of: backslash, repeated separators, dot segments, or ambiguous escapes.","triggerScenarios":"Requesting any /compat/... path containing a backslash, '//' inside the path, '.'/'..' segments, or %2f/%5c/%2e escapes in Path or RawPath; configuring an upstream BaseURL whose path contains such components (via parseBaseURL's validation).","commonSituations":"Clients URL-encoding slashes in model names or resource ids; buggy client code double-encoding paths; misconfigured base URLs containing '..' or '//'; security scanners probing path traversal.","solutions":["Remove backslashes, empty inner segments, and dot segments from the request path","URL-encode payloads so no %2f, %5c, or %2e appear in the path (put variable data in the body or query where allowed)","Fix the upstream BaseURL in config if it contains such components","Send the request without a rawPath escape spelling that differs from the decoded path"],"exampleFix":"// before\nGET /compat/openai/v1/chat/../completions\n\n// after\nGET /compat/openai/v1/chat/completions","handlingStrategy":"validation","validationCode":"func safeCompatPath(p string) error {\n    if strings.Contains(p, \"\\\\\") || strings.Contains(p, \"..\") || strings.Contains(p, \"//\") {\n        return fmt.Errorf(\"unsafe path %q\", p)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := ValidateRequestPath(req.URL); err != nil {\n    log.Warnf(\"rejected compat path: %v\", err)\n    http.Error(w, \"invalid path\", http.StatusBadRequest)\n    return\n}","preventionTips":["Never build compat URLs by string concatenation of untrusted segments","Keep ids path-safe (alphanumeric, dash, underscore) or move them to the body","Test clients against ValidateRequestPath in CI"],"tags":["go","proxy","security","path-validation"],"backgroundTag":"path-traversal-blocked","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"}