{"record":{"id":"2191a16f22cbbb31","repo":"crowdsecurity/crowdsec","slug":"on-challenge-hooks-are-only-valid-in-band-not-und","errorCode":null,"errorMessage":"on_challenge hooks are only valid in-band, not under outofband","messagePattern":"on_challenge hooks are only valid in-band, not under outofband","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/appsec/appsec.go","lineNumber":1008,"sourceCode":"\tif ret.CommonHooks, err = buildPhaseHooks(ctx, \"\", wc.PreEval, wc.PostEval, wc.OnMatch, patcher); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif wc.InBand != nil {\n\t\tif ret.InBandHooks, err = buildPhaseHooks(ctx, \"inband\",\n\t\t\twc.InBand.PreEval, wc.InBand.PostEval, wc.InBand.OnMatch, patcher); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif wc.OutOfBand != nil {\n\t\tif ret.OutOfBandHooks, err = buildPhaseHooks(ctx, \"outofband\",\n\t\t\twc.OutOfBand.PreEval, wc.OutOfBand.PostEval, wc.OutOfBand.OnMatch, patcher); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif len(wc.OutOfBand.OnChallenge) > 0 {\n\t\t\treturn nil, errors.New(\"on_challenge hooks are only valid in-band, not under outofband\")\n\t\t}\n\n\t\tif len(wc.OutOfBand.OnChallengeSubmit) > 0 {\n\t\t\treturn nil, errors.New(\"on_challenge_submit hooks are only valid in-band, not under outofband\")\n\t\t}\n\t}\n\n\t// on_challenge hooks: merge top-level and inband-scoped (both are in-band only).\n\tonChallengeHooks := wc.OnChallenge\n\tif wc.InBand != nil {\n\t\tonChallengeHooks = append(onChallengeHooks, wc.InBand.OnChallenge...)\n\t}\n\n\tif ret.CompiledOnChallenge, err = buildHookList(ctx, onChallengeHooks, hookOnChallenge, patcher); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Defining any on_challenge hook implies we need the challenge runtime to","sourceCodeStart":990,"sourceCodeEnd":1026,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/appsec/appsec.go#L990-L1026","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\noutofband:\n  on_challenge:\n    - return_challenge\n// after\ninband:\n  on_challenge:\n    - return_challenge","handlingStrategy":"validation","validationCode":"if len(cfg.OutOfBand.OnChallenge) > 0 || len(cfg.OutOfBand.OnChallengeSubmit) > 0 { return errors.New(\"challenge hooks must live under inband, not outofband\") }","typeGuard":null,"tryCatchPattern":"if _, err := appsec.LoadConfig(cfg); err != nil { if strings.Contains(err.Error(), \"on_challenge hooks\") { /* move hooks to inband section */ } }","preventionTips":["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"],"tags":["appsec","config","crowdsec","hooks"],"backgroundTag":"conflicting-config-options","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}