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

  1. Sanitize request paths on the caller side: reject or clean segments containing '..' before calling JoinBasePath.
  2. 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.
  3. Return HTTP 400 to clients with a clear 'path traversal not allowed' message.
  4. 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

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.