Quarkus extension by SiteNetSoft that screens HTTP requests with libModSecurity v3 and the OWASP Core Rule Set (CRS), calling the engine through the Java Foreign Function & Memory API (java.lang.foreign). It works in JVM mode, dev mode and native image (proven on Mandrel 25.0.5: the integration tests pass against the native executable), with global or selective scope. The system library libmodsecurity is never bundled.
Status: experimental. Nothing is published yet.
Documentation: docs/modules/ROOT/pages (Antora; built with mvn -Pdocs -pl docs package).
| System | Install |
|---|---|
| Debian, Ubuntu | sudo apt install libmodsecurity3 |
| Alpine | apk add libmodsecurity |
| Fedora, RHEL, Rocky, Alma | no package: build from source, see installation |
| macOS (Homebrew, untested) | brew install modsecurity, then set quarkus.modsecurity.library |
| Windows | not supported |
A library elsewhere: quarkus.modsecurity.library=/path/to/libmodsecurity.so.3.
<dependency>
<groupId>org.sitenetsoft</groupId>
<artifactId>quarkus-modsecurity</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.sitenetsoft</groupId>
<artifactId>quarkus-modsecurity-crs</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>No configuration needed: every request (headers and the first 128 KiB of the body) is inspected with the CRS at paranoia level 1; an attack gets 403 with an empty body. /q/* (health, metrics) is never inspected. Run the JVM with --enable-native-access=ALL-UNNAMED (dev mode adds it for you).
quarkus.modsecurity.mode=enforce # default: block
quarkus.modsecurity.mode=detect # log what would be blocked, block nothing
quarkus.modsecurity.mode=off # no engine at allquarkus.modsecurity.scope=selective
quarkus.modsecurity.profile.api.paths=/api/*
quarkus.modsecurity.profile.upload.paths=/api/files/*
quarkus.modsecurity.profile.upload.methods=PUT,POST
quarkus.modsecurity.profile.upload.inspection=headersOnly /api/* is inspected; uploads have their headers inspected, not their bodies. Rules for which profile wins are in profiles.
-
Uploads: use
inspection=headers(orscope=selective) for upload endpoints. With thefullinspection in the defaultpartialmode, the filter buffers the whole body on the heap, up toquarkus.http.limits.max-body-size, before forwarding it (the engine still sees only the firstbody-limitbytes). Raisingmax-body-sizefor uploads without giving them theheadersinspection keeps every upload in memory. A body inspected in full is answered with 413 past 2139095039 bytes (Integer.MAX_VALUE - 8 MiB: a Vert.x buffer is indexed byint, and Netty's last growth step jumps to that maximum); amax-body-sizeof 2G or more starts with a WARN naming that cap. -
Bodies read before the filter. With RESTEasy Classic, or any extension that makes Quarkus install the Vert.x body handler (
RequireBodyHandlerBuildItem), that handler runs before the filter and never keeps amultipart/form-databody: such requests are inspected without their body. A WARN says so once per profile andmodsecurity.body.skippedcounts them. See body inspection, Limits.
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import org.sitenetsoft.quarkus.modsecurity.ModSecurityConfig.Inspection;
import org.sitenetsoft.quarkus.modsecurity.Waf;
@Path("/hooks")
public class HookResource {
@POST
@Waf(inspection = Inspection.OFF) // signed payloads, verified by the endpoint
public void receive(byte[] body) { ... }
}@Waf on a class covers all its endpoints; on a method it beats the class, and it beats a configured profile for the same path.
quarkus.modsecurity.rules=classpath:modsecurity/before-crs.conf
quarkus.modsecurity.rules-after=/etc/myapp/exclusions.conf
quarkus.modsecurity.crs.paranoia-level=2In dev mode, editing a .conf under src/main/resources/modsecurity/ restarts the application.
The CRS blocks Expect: 100-continue at paranoia level 1 (rule 920450; curl sends it for large bodies). To allow it, in a quarkus.modsecurity.rules file (the CRS 4.30 default list without /expect/):
SecAction "id:900250,phase:1,pass,t:none,nolog,\
setvar:'tx.restricted_headers_basic=/content-encoding/ /proxy/ /lock-token/ /content-range/ /if/ /x-http-method-override/ /x-http-method/ /x-method-override/ /x-middleware-subrequest/'"
More in configuration (allowed content types, rule 920420).
Apache-2.0. libModSecurity and the OWASP CRS are Apache-2.0 too; quarkus-modsecurity-crs redistributes the CRS files with their license.