Configuration
OAShield is configured through the OpenAPI Generator --additional-properties flag,
passed comma-separated:
java -cp oashield-cli.jar org.openapitools.codegen.OpenAPIGenerator \ generate -g modsecurity3 -i api.yaml -o out \ --additional-properties engineFlavor=coraza,schemaRulePath=rules/schema.jsonOptions
| Option | Default | Description |
|---|---|---|
engineFlavor | modsecurity3 | Target engine: modsecurity3 or coraza |
validateBodySchema | true | Emit request-body validation rules |
generateJsonSchema | true | Emit the JSON Schema file |
jsonSchemaOutputFile | schema.json | JSON Schema file name |
schemaRulePath | same as jsonSchemaOutputFile | Schema path written inside the @validateSchema rule. Coraza resolves it relative to the server process working directory, not the rules directory |
denyAction | deny | What happens when a rule blocks: deny, drop, redirect, or pass (detection-only: violations are logged but requests go through) |
denyStatus | 403 | HTTP status returned on deny (100–599). With denyAction=redirect, set a 3xx status; non-3xx values make the engine fall back to 302 |
denyRedirectUrl | (none) | Absolute http(s) URL to redirect blocked requests to; required when denyAction=redirect |
enableLogging | true | Emit log,auditlog on generated rules; false emits nolog instead |
includeEngineConfig | true | Emit SecRuleEngine On, SecRequestBodyAccess On, and the SecDefaultAction in mainconfig.conf. Set false when your existing WAF configuration already defines these |
unknownMediaTypePolicy | pass | Handling of declared request media types the WAF cannot inspect (e.g. application/octet-stream, text/plain): pass lets them through after the content-type gate, block rejects them |
basePath | auto | Path prefix for all generated path-match rules. Defaults to the path component of the spec’s first servers.url (server variables match one path segment). Pass an empty string to disable prefixing |
validateXmlSchema | false | Generate an XSD from the models and emit @validateSchema XML rules (modsecurity3 flavor only). Off by default due to current engine limitations; see the engine behavior notes |
xsdOutputFile | schema.xsd | XSD output file name |
xsdRulePath | same as xsdOutputFile | XSD path written inside the @validateSchema XML rule |
Deny behavior and logging
Every generated rule uses the block action, so the actual disruptive behavior is
decided in one place: the SecDefaultAction emitted at the top of mainconfig.conf.
denyAction, denyStatus, and denyRedirectUrl control that line:
# Return 429 instead of 403--additional-properties denyStatus=429
# Detection-only: log violations, let requests through--additional-properties denyAction=pass
# Redirect blocked requests--additional-properties denyAction=redirect,denyRedirectUrl=https://example.com/blocked,denyStatus=302If your ModSecurity/Coraza deployment already configures the engine (rule engine mode,
body access, default action), generate only the rules with includeEngineConfig=false.
Your existing SecDefaultAction then decides what blocking means.
Engine flavors
Most generated rules are identical across both engines. The flavor only changes how JSON request bodies are validated.
| Flavor | JSON body validation |
|---|---|
modsecurity3 (default) | Per-field rules generated from the OpenAPI schema: required-property presence, per-property type patterns, numeric minimum/maximum, and an ARGS_NAMES allowlist that rejects undeclared properties |
coraza | The same per-field rules plus a @validateSchema rule that validates the raw body against the generated JSON Schema. @validateSchema is Coraza-only; ModSecurity v3’s operator of the same name is XSD/XML-only |
Limitations of per-field body validation
These apply to the modsecurity3 flavor’s per-field checks. Coraza’s @validateSchema
additionally covers all of them:
- Type coercion: values are validated after the engine flattens JSON to strings, so a
JSON number where a free-form string is expected (e.g.
"name": 123) is not distinguishable. requiredscope: enforced for object properties (nested ones only when their parent object is present, per JSON Schema semantics), but not per array element. An empty array satisfies a required array property only on thecorazaflavor.- Nesting depth: model nesting is flattened to 5 levels; deeper properties are covered only by the unknown-property allowlist.
- Numeric bounds on path parameters:
minimum/maximumon path parameters is enforced only lexically, via the embedded path pattern. oneOf/anyOfcomposition: enforced as the union of the member schemas. Primitive unions are validated against an alternation of the member patterns; model unions validate and allowlist the properties of every branch, butrequiredproperties inside a branch are not enforced, andoneOf’s exactly-one semantics are not distinguished fromanyOf.allOfmodels are validated fully (members are merged). The generated JSON Schema keeps the exactoneOf/anyOfkeywords for Coraza’s@validateSchema.