crowdsecurity/crowdsec · error

on_challenge_submit hooks are only valid in-band, not under

Error message

on_challenge_submit hooks are only valid in-band, not under outofband

What it means

CrowdSec AppSec component rules support challenge hooks (on_challenge / on_challenge_submit) only for in-band rule collections. The WAF config loader validates the whole WAF config tree and rejects the config if these hook names appear under the `outofband` section, where per-request challenge interaction is meaningless. This is a startup-time configuration validation error: the config fails to load and the AppSec component is not initialized.

Source

Thrown at pkg/appsec/appsec.go:1012

	if wc.InBand != nil {
		if ret.InBandHooks, err = buildPhaseHooks(ctx, "inband",
			wc.InBand.PreEval, wc.InBand.PostEval, wc.InBand.OnMatch, patcher); err != nil {
			return nil, err
		}
	}

	if wc.OutOfBand != nil {
		if ret.OutOfBandHooks, err = buildPhaseHooks(ctx, "outofband",
			wc.OutOfBand.PreEval, wc.OutOfBand.PostEval, wc.OutOfBand.OnMatch, patcher); err != nil {
			return nil, err
		}

		if len(wc.OutOfBand.OnChallenge) > 0 {
			return nil, errors.New("on_challenge hooks are only valid in-band, not under outofband")
		}

		if len(wc.OutOfBand.OnChallengeSubmit) > 0 {
			return nil, errors.New("on_challenge_submit hooks are only valid in-band, not under outofband")
		}
	}

	// on_challenge hooks: merge top-level and inband-scoped (both are in-band only).
	onChallengeHooks := wc.OnChallenge
	if wc.InBand != nil {
		onChallengeHooks = append(onChallengeHooks, wc.InBand.OnChallenge...)
	}

	if ret.CompiledOnChallenge, err = buildHookList(ctx, onChallengeHooks, hookOnChallenge, patcher); err != nil {
		return nil, err
	}

	// Defining any on_challenge hook implies we need the challenge runtime to
	// validate cookies and submissions, even if the hook bodies never call
	// SendChallenge() themselves.
	if len(ret.CompiledOnChallenge) > 0 {
		patcher.NeedWASMVM = true

View on GitHub (pinned to 909b515798)

Solutions

  1. Move the on_challenge / on_challenge_submit hook definitions from the `outofband:` section to the top level or the `inband:` section of the WAF config
  2. If the hook was added by mistake under outofband and is not needed, delete the entry
  3. Re-validate the config indentation: YAML nesting mistakes are the usual root cause

Example fix

// before (WAF config yaml)
outofband:
  on_challenge_submit:
    - console_log()

// after
inband:
  on_challenge_submit:
    - console_log()
Defensive patterns

Strategy: validation

Validate before calling

if cfg.OutOfBand != nil && (len(cfg.OutOfBand.OnChallenge) > 0 || len(cfg.OutOfBand.OnChallengeSubmit) > 0) {
    return fmt.Errorf("on_challenge/on_challenge_submit must be defined in-band, not under outofband")
}

Prevention

When it happens

Trigger: Loading a WAF AppSec config YAML where `outofband: on_challenge_submit: [...]` (or `outofband: on_challenge: [...]`) is defined; each hook list under OutOfBand is checked in the WAF-config compilation path in pkg/appsec/appsec.go.

Common situations: A user copies an in-band challenge example into their out-of-band collection; a config file merges snippets where challenge hooks ended up at the wrong YAML nesting level; upgrading an older config that predated the in-band/out-of-band hook split.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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