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 toView on GitHub (pinned to 909b515798)
Solutions
- Move the on_challenge (and on_challenge_submit) hooks out of the outofband section into the in-band section
- Delete them from outofband if you don't need the challenge flow
- If you intended challenge behavior, ensure your acquisition is in-band (the challenge flow cannot work out-of-band) and configure hooks under inband
- 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
- Never copy inband hook blocks into the outofband section
- Remember challenge/captcha requires in-band acquisition and only works in the inband phase
- Validate appsec configs with the provided test tooling before deploying
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
- unable to build %s hook : %w
- no appsec-config found for %s
- path must start with /
- ref cannot be empty
- on_challenge_submit hooks are only valid in-band, not under
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/2191a16f22cbbb31.
Report an issue: GitHub.