crowdsecurity/crowdsec · error

on_challenge hooks are only valid in-band, not under outofba

Error message

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

What it means

When building a WAF config's phases, hook lists are grouped by phase. on_challenge and on_challenge_submit hooks implement the challenge flow, which only runs in the in-band pipeline; placing them under the outofband section is a configuration error rejected at config load time.

Source

Thrown at pkg/appsec/appsec.go:1008

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

	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

View on GitHub (pinned to 909b515798)

Solutions

  1. Move the on_challenge (and on_challenge_submit) hooks out of the outofband section into the in-band section
  2. Delete them from outofband if you don't need the challenge flow
  3. If you intended challenge behavior, ensure your acquisition is in-band (the challenge flow cannot work out-of-band) and configure hooks under inband
  4. Re-validate the appsec config with cscli/appsec test config after editing

Example fix

// before
outofband:
  on_challenge:
    - return_challenge
// after
inband:
  on_challenge:
    - return_challenge
Defensive patterns

Strategy: validation

Validate before calling

if len(cfg.OutOfBand.OnChallenge) > 0 || len(cfg.OutOfBand.OnChallengeSubmit) > 0 { return errors.New("challenge hooks must live under inband, not outofband") }

Try / catch

if _, err := appsec.LoadConfig(cfg); err != nil { if strings.Contains(err.Error(), "on_challenge hooks") { /* move hooks to inband section */ } }

Prevention

When it happens

Trigger: Loading a crowdsec appsec config whose outofband section contains non-empty on_challenge (or on_challenge_submit) hook entries — detected in buildPhaseHooks/setup during config parsing, before serving traffic.

Common situations: Copy-pasting hook blocks from the in-band section into outofband; misunderstanding that challenge/captcha flow requires in-band acquisition; merging config snippets from docs/examples that mix the two phases.

Related errors


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