Four points on the request path
Each layer is independent — enable only what you need. The cheapest checks run first, so a caller already known to be hostile never reaches the rule engine.
Honeypot paths and global validators, evaluated off the global configuration — so traffic matching no route at all is still covered.
Standing bans, threat feeds, CrowdSec decisions, network classification, bot verification and traffic surges, all before the request is parsed.
The API contract, then CRS and your own SecLang rules over the URI, headers, cookies, arguments and body, uploaded files, logins and objects. Then the fabric reads the accumulated score and acts.
The same engine over the backend response, error leakage replaced and sensitive data masked — and failed statuses and logins counted towards the cluster-wide memory.
What the suite gives you
Four detection modules — payload, reputation, bots and behaviour — feeding one decision fabric, sharing the same entities, the same admin section and the same analytics events.
Detectors contribute weighted signals instead of each blocking alone. One component reads the total and applies one graded action — log, challenge, throttle, tarpit, deny or ban — with the full attribution kept, so any decision can be explained afterwards.
A shared ban registry and a cross-request ledger: a caller banned anywhere is refused everywhere, and one that trips a rule a minute for an hour is eventually promoted to a ban even though every single request looked innocent.
Every outcome emits one normalised ECS-shaped event, correlated per identity into incidents — so a scan is one line in your SIEM with a count on it, not a pager storm.
A native JVM implementation of the SecLang rule language, passing 100% of the OWASP Core Rule Set v4 regression suite. No native library, no sidecar, no separate process.
CRS v4 ships inside the extension. Import it with one directive, then layer your own rules on top — or run only your own.
Disguised scripts and executables, polyglots, archive bombs and zip slips refused from what a file is rather than what it is called — and every file handed to a clamd or ICAP antivirus before the upload completes, when you have one.
Match callers against public blocklists, cloud provider ranges and Tor exit nodes before a byte is parsed, from a catalog of fourteen curated sources. Refreshed on a schedule, matched in memory, rollback-able.
Consume decisions from a CrowdSec Local API, and report detections back as alerts — so Otoroshi becomes a CrowdSec detector, not only an enforcement point.
Address-to-ASN from the public routing table, classified into cdn, hosting and vpn. It ships as a low weight and never as a block: a datacenter is a hint, not a verdict.
Forward-confirmed reverse DNS over twenty-seven known signatures. Googlebot is the most forged user-agent on the web, and a failed check turns a suspicious string into a demonstrated lie.
An embedded proof of work — no third party, no external call, difficulty scaled by the score. Or plug in a widget: Friendly Captcha and captcha.eu for a European deployment, Turnstile and hCaptcha otherwise.
Per-category rules over AI, search, SEO and monitoring crawlers, actually enforced, with a matching robots.txt and llms.txt generated from them — plus honeypot paths that catch a scanner with almost no false-positive risk.
Credential stuffing, password spraying and likely account takeovers on the login endpoints; a surge away from the traffic each route usually gets; a consumer walking object identifiers one after another — each scored on the shared judgement, never an account locked out.
A scraper that keeps under your rate limit still reads the whole catalogue. A budget of distinct objects per consumer, counted across the cluster, refuses the next new one and never the ones already read.
Stack traces and debug pages replaced by a neutral error; card numbers, IBANs, national identifiers and secrets masked in place, each checked the way its issuer would, the response read as it streams and kept valid.
Every request checked against the route's OpenAPI 3.0 or 3.1 contract — paths, methods, parameters and bodies. Whole classes of attack never reach the backend, because the payload does not match the contract to begin with.
Endpoints the backend answers that nobody documented, operations nobody calls, fields the backend returns that the contract never mentions, and the credential each endpoint actually checks — in the console, and served to your CI.
Every module runs in monitoring mode first, and a fresh threat policy starts in dry run — emitting events without denying anything, so you can measure the false-positive cost before arming it.
Feed lookups hit a sorted in-memory range index. Refreshes, DNS and CrowdSec syncs run off the request path, and every external dependency fails open — visibly, as an event.
Two steps to a running suite
Download the jar from the releases page — no build step. Then add the preset plugin to a route: one slot that lays down the whole fabric in the right order, and starts in dry run until the events look clean.
# grab otoroshi and the extension
curl -L -o otoroshi.jar \
'https://github.com/MAIF/otoroshi/releases/download/v18.0.0-preview6/otoroshi.jar'
# the threat protection suite jar, from github.com/cloud-apim/otoroshi-waf-extension/releases/latest
curl -L -o waf.jar \
'.../releases/download/<version>/otoroshi-waf-extension_3-<version>.jar'
# run them together, with the extension enabled
java -cp "./waf.jar:./otoroshi.jar" \
-Dotoroshi.admin-extensions.configurations.cloud-apim_extensions_waf.enabled=true \
play.core.server.ProdServerStart