crowdsecurity/crowdsec · error
schema filename %q must be relative to %s and stay within it
Error message
schema filename %q must be relative to %s and stay within it
What it means
loadAPISchema validates that the schema filename is a local, relative path (filepath.IsLocal) before joining it under <data_dir>/schemas. Absolute paths or paths escaping the schemas directory (../ traversal) are rejected with this error to prevent reading arbitrary files. It is a security guard on user-supplied schema references in API validation config.
Source
Thrown at pkg/appsec/appsec.go:1879
// Custom remediations use the same status code logic as ban/captcha
resp.HTTPStatus = response.UserHTTPResponseCode
if resp.HTTPStatus == 0 {
resp.HTTPStatus = w.Config.UserBlockedHTTPCode
}
bouncerStatusCode = response.BouncerHTTPResponseCode
if bouncerStatusCode == 0 {
bouncerStatusCode = w.Config.BouncerBlockedHTTPCode
}
}
return bouncerStatusCode, resp
}
const schemasSubDir = "schemas"
func (w *AppsecRuntimeConfig) loadAPISchema(ref, filename string, opts *apivalidation.SchemaOptions) error {
if !filepath.IsLocal(filename) {
return fmt.Errorf("schema filename %q must be relative to %s and stay within it", filename, schemasSubDir)
}
schemaPath := filepath.Join(w.DataDir, schemasSubDir, filename)
w.Logger.Debugf("loading schema %s for ref %s", schemaPath, ref)
schema, err := os.ReadFile(schemaPath)
if err != nil {
return fmt.Errorf("unable to read schema file %s : %w", schemaPath, err)
}
return w.RequestValidator.LoadSchema(ref, string(schema), opts)
}
func (w *AppsecRuntimeConfig) LoadAPISchemaWithName(ref string, filename string) error {
return w.loadAPISchema(ref, filename, nil)
}
// LoadAPISchemaWithOptions behaves like LoadAPISchemaWithName but accepts a
// map of policy overrides. Supported keys:
// - "on_route_not_found": "drop" | "ignore" (default: "drop")
// - "on_method_not_allowed": "drop" | "ignore" (default: "drop")View on GitHub (pinned to 909b515798)
Solutions
- Place the schema file under /var/lib/crowdsec/data/schemas/ (or your data dir's schemas subdir) and reference it by bare relative filename
- Remove any leading `/` or `../` from the configured filename
- Keep the file within the schemas directory — subdirectories are fine as long as the path stays inside
- If you need schemas elsewhere, this is intentionally unsupported; move the file
Example fix
// before api_validation: schema: /etc/crowdsec/schemas/user.json // after (file at <data_dir>/schemas/user.json) api_validation: schema: user.json
Defensive patterns
Strategy: validation
Validate before calling
func isSafeSchemaName(name string) bool {
return filepath.IsLocal(name) && name != "." && !strings.Contains(name, "..")
} Try / catch
if err := rt.LoadAPISchema(ref, filename); err != nil {
if strings.Contains(err.Error(), "must be relative to") {
log.Fatalf("move schema into %s and use a relative name: %v", schemasDir, err)
}
return err
} Prevention
- Always reference schemas by bare filename relative to the schemas dir
- Never template absolute paths into schema config
- Sanitize any user/externally supplied schema names before passing them
When it happens
Trigger: Configuring an API validation schema with an absolute path (/etc/crowdsec/schemas/x.json), a filename containing `..`, or a path starting with `/` or a drive letter.
Common situations: User puts the full path to a schema file instead of just the name; templating injects a leading slash; a malicious or buggy config attempts path traversal.
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
- %q: must be a relative path
- appsec datasource requires a hub. this is a bug, please repo
- appsec datasource requires a lapi client configuration. this
- missing lapi client credentials
- no appsec_config provided
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/d1a992465dfd9e20.
Report an issue: GitHub.