IceWhaleTech/CasaOS · warning
access using relative path is not allowed
Error message
access using relative path is not allowed
What it means
JoinBasePath rejects the incoming request path because it contains a '..' segment: either the path ends with '..' or contains a '../' substring. This is an intentional path-traversal guard that prevents callers from escaping the configured base directory via relative segments before the path is joined and cleaned.
Source
Thrown at pkg/utils/path.go:78
{"%", "%25"},
{"?", "%3F"},
{"#", "%23"},
}
for i := range seg {
if len(all) > 0 && all[0] {
seg[i] = url.PathEscape(seg[i])
} else {
for j := range toReplace {
seg[i] = strings.ReplaceAll(seg[i], toReplace[j].Src, toReplace[j].Dst)
}
}
}
return strings.Join(seg, "/")
}
func JoinBasePath(basePath, reqPath string) (string, error) {
if strings.HasSuffix(reqPath, "..") || strings.Contains(reqPath, "../") {
return "", errors.New("access using relative path is not allowed")
}
return stdpath.Join(FixAndCleanPath(basePath), FixAndCleanPath(reqPath)), nil
}
View on GitHub (pinned to 0d3b2f444e)
Solutions
- Sanitize request paths on the caller side: reject or clean segments containing '..' before calling JoinBasePath.
- If legitimate, rewrite '..' segments using stdpath.Clean on the request path first and ensure the result stays under the base — but never bypass the guard for raw user input.
- Return HTTP 400 to clients with a clear 'path traversal not allowed' message.
- Audit that the guard covers encoded variants by decoding before validation.
Example fix
// before
joined, err := utils.JoinBasePath(basePath, reqPath)
// after (validate first, then join)
if strings.Contains(reqPath, "..") {
return http.StatusBadRequest, fmt.Errorf("path must not contain '..' segments")
}
joined, err := utils.JoinBasePath(basePath, reqPath) Defensive patterns
Strategy: validation
Validate before calling
func IsSafeRelativePath(p string) bool {
if p == "" { return true }
for _, seg := range strings.Split(p, "/") {
if seg == ".." { return false }
}
return true
}
if !IsSafeRelativePath(reqPath) { return http.StatusBadRequest } Type guard
func IsSafeRelativePath(p string) bool {
for _, seg := range strings.Split(p, "/") {
if seg == ".." {
return false
}
}
return true
} Try / catch
joined, err := utils.JoinBasePath(basePath, reqPath)
if err != nil {
if strings.Contains(err.Error(), "relative path") {
return http.StatusBadRequest, errors.New("path traversal rejected") // never retry
}
return http.StatusInternalServerError, err
} Prevention
- URL-decode then validate every user-supplied path before joining
- Reject '..' segments at the HTTP handler boundary with 400
- After joining, verify the result still has the base path as prefix (defense in depth)
When it happens
Trigger: Any request path like '../../etc/passwd', '/safe/../..', or '/dir/../other' passed to JoinBasePath. The check runs before stdpath.Join, so any traversal attempt (accidental or malicious) fails closed.
Common situations: Malicious input probing for directory traversal; benign client sending unclean paths containing '..' (e.g. concatenating user folder names without sanitization); URL-decoded paths where %2e%2e%2f becomes '../'.
Related errors
AI-assisted analysis of IceWhaleTech/CasaOS@0d3b2f444e (2026-08-15).
Data as JSON: /api/errors/3a79f88efb067f30.
Report an issue: GitHub.