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

  1. Place the schema file under /var/lib/crowdsec/data/schemas/ (or your data dir's schemas subdir) and reference it by bare relative filename
  2. Remove any leading `/` or `../` from the configured filename
  3. Keep the file within the schemas directory — subdirectories are fine as long as the path stays inside
  4. 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

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


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/d1a992465dfd9e20. Report an issue: GitHub.