ADR-0005: Unknown versus unsupported directives
ADR-0005: Unknown versus unsupported directives
- Status: proposed
- Date: 2026-10-06
- Deciders: @fzipi
- Category: Divergence
Context
- ModSecurity v2: an unknown directive is an Apache configuration error; the server does not start.
- libmodsecurity v3: the parser rejects an unknown directive and the configuration fails to load.
- Coraza 3.8.1:
internal/seclang/parser.gorejects an unknown directive (unknown directive %q), butdirectivesmap.gen.gomaps seven known names todirectiveUnsupported, which returnsnilwithout logging:SecArgumentSeparator,SecCookieFormat,SecRuleUpdateTargetByMsg,SecRuleScript,SecRulePerfTime,SecTmpDirandsecunicodemap.SecRemoteRulesreturns an error instead.SecIgnoreRuleCompilationErrors Onmakes rule compilation errors non-fatal; it does not affect unknown directives.
Two of the silently ignored names, SecArgumentSeparator and SecRequestBodyNoFilesLimit
(the latter parsed into a field with a TODO), are Core in this specification and change
what rules see. A user who sets them and gets no warning has a false sense of coverage.
Decision
- A directive name that this specification does not define MUST be a configuration error.
- A directive whose status is Deprecated, or Extended and not implemented by the engine, MUST be accepted; the engine MAY ignore it and SHOULD log a warning naming the directive once per configuration load.
- A directive that is Engine-specific to another engine is “not defined” for this engine (rule 1) unless the engine documents that it accepts it.
- A Core directive MUST be implemented. Accepting a Core directive without implementing its semantics is non-conforming; the engine’s conformance statement MUST list it as a known gap until fixed.
Options considered
- Ignore every unknown directive (lenient): hides typos and misconfigurations; rejected.
- Error on anything unimplemented (strict): makes Deprecated features unusable across engines even where they are harmless; rejected.
- Error on unknown, accept-and-warn on known-but-unimplemented (chosen): matches what
users of both engines already expect for
#-commented legacy directives.
Consequences
- For ModSecurity v2: no change.
- For libmodsecurity v3: it rejects several Deprecated and Extended names outright
(
seclang-parser.yy, “is not supported”:SecServerSignature,SecCacheTransformations,SecChrootDir,SecGsbLookupDb,SecGuardianLog,SecStreamInBodyInspection,SecStreamOutBodyInspection,SecHashKey,SecHashParam,SecHashMethodRx,SecHashMethodPm, and theOnvalue ofSecHashEngine,SecInterceptOnError,SecContentInjection,SecRuleInheritance,SecDisableBackendCompression), which rule 2 forbids; it should accept and warn. Where it parses and ignores (e.g.SecConnEngine Off) it should warn. - For Coraza: fourteen Deprecated names are unknown to its parser (
compat/matrix.md,-in the Coraza column), which rule 2 forbids; add them as accepted-and-warned. - For Coraza: log a warning in
directiveUnsupported; implementSecArgumentSeparatorandSecRequestBodyNoFilesLimitor list them as gaps. - For rule authors: a Deprecated directive in a shared configuration is safe on every engine; a misspelled one is caught everywhere.
Tests
tests/engine/directives/unknown-directive.yamltests/engine/directives/deprecated-directive-accepted.yaml
References
spec/04-directives.mdindex (statuses),spec/00-conventions.md