JuliusBrussee/caveman · error
dot segments are not allowed in path
Error message
dot segments are not allowed in path
What it means
validatePathComponents rejects '.' and '..' segments outright in /compat/ paths and upstream base URLs. Dot segments allow path traversal and are resolved differently by different HTTP stacks, so a path could escape its route prefix after a decode hop. This is a deliberate fail-closed security choice rather than lexical normalization.
Solutions
- Remove dot segments and send the canonical absolute path
- Stay within the intended route prefix instead of using '..' to reach other routes
- Fix the configured upstream BaseURL to an absolute normalized path
Example fix
// before GET /compat/openai/v1/../v0/models // after GET /compat/openai/v0/models (if that route exists) or use the correct named route
Defensive patterns
Strategy: validation
Validate before calling
if strings.Contains(path, "/../") || strings.HasSuffix(path, "/..") || strings.Contains(path, "/./") {
return errors.New("dot segments are not allowed")
} Try / catch
if err := ValidateRequestPath(req.URL); err != nil {
http.Error(w, "path traversal blocked", http.StatusBadRequest)
return
} Prevention
- Treat any dot segment in API paths as an attack or a bug
- Keep route ids within the prefix; never climb with '..'
- Normalize paths before logging or routing
When it happens
Trigger: Request path like /compat/../admin or /compat/openai/./v1; BaseURL config containing '..'; traversal probes with multiple dot segments.
Common situations: Path traversal attacks/scanners; clients trying to reach sibling routes by climbing out of the compat prefix; misconfigured upstream URLs.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- backslash is not allowed in path
- provider upstream URL path rejected
- ambiguous escaped path sequence
- cave_live_eval_sandbox_profile_escapes_root
- cave_sandbox_source_read_grant_escapes_staging
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/9cbfe6c55e4457cc.
Report an issue: GitHub.
Appendix: source
Thrown at proxy/providers/openaicompat/openaicompat.go:497
return nil
}
if err := validatePathComponents(path, rawPath); err != nil {
return fmt.Errorf("compat route path rejected: %w", err)
}
return nil
}
func validatePathComponents(path, rawPath string) error {
if strings.Contains(path, `\`) {
return fmt.Errorf("backslash is not allowed in path")
}
segments := strings.Split(path, "/")
for i, segment := range segments {
if segment == "" && i > 0 && i < len(segments)-1 {
return fmt.Errorf("repeated path separators are not allowed")
}
if segment == "." || segment == ".." {
return fmt.Errorf("dot segments are not allowed in path")
}
}
// URL.Path is decoded by net/url while RawPath retains a valid escaped
// spelling. Reject separators, backslashes, and dot bytes in either form so
// a path cannot change route identity after another decoder or proxy hop.
for _, escape := range []string{"%2f", "%5c", "%2e"} {
if strings.Contains(strings.ToLower(path), escape) || strings.Contains(strings.ToLower(rawPath), escape) {
return fmt.Errorf("ambiguous escaped path sequence %s", escape)
}
}
return nil
}
func parseBaseURL(raw, provider string) (*url.URL, error) {
if strings.TrimSpace(raw) == "" {
return nil, fmt.Errorf("provider %q has no configured upstream URL", provider)
}
u, err := url.Parse(strings.TrimSpace(raw))View on GitHub (pinned to 3ee70a1026)