Open-source project
coreruleset/coreruleset avatar
coreruleset/coreruleset

coreruleset: the OWASP rules your ModSecurity or Coraza install is missing

OWASP CRS (Official Repository)

3,294 stars471 forksPythonApache-2.0

At a glance

What is it?
OWASP CRS is a directory of attack detection rules with no server of its own. It is loaded by an existing WAF engine, and its real costs are engine version requirements and false positive triage.
Who is it for?
CRS is the right pick when you already run ModSecurity v3 or Coraza and want an OWASP reviewed set of detection rules rather than a hand written list. It is the wrong pick if you want a firewall you can run on its own, since nothing in this repository listens on a port, and it is a poor fit for engines older than libmodsecurity v3.0.16, where a ctl action stops parsing and the config will not load.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 9, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A directory of rules that needs someone else's engine to run

The README describes the project in one sentence: a set of generic attack detection rules for use with OWASP ModSecurity, OWASP Coraza, or other compatible web application firewalls, aimed at a wide range of attacks including the OWASP Top Ten with a minimum of false alerts. That sentence is the whole scope. There is no binary to launch, no port to bind, no configuration server. The repository ships rules and the tooling to test them.

That shape has consequences for anyone evaluating it. A CRS deployment is really two decisions: which engine executes the rules, and which CRS version those rules are written against. The release notes show how tightly the two are coupled, because fixes get backported conditionally against engine versions rather than applied blindly.

The metadata reinforces the shape. The topic list is crs, owasp, ruleset, security, waf, and the declared primary language is Python, which describes the automation and test tooling rather than the rule payload. The last push was on 2026-09-23. Copyright runs 2006-2020 to Trustwave and contributors, then 2021-2026 to the CRS project, which tells you the governance changed hands once and has been stable since. The licence is Apache 2.0.

Rule IDs are the operational interface, not an implementation detail

If you read the release notes for this project, the first thing you notice is how much they talk about numbers: rule 932171, 942190, 942200, 942390, 901181, and the 934 and 941170 ranges. Those identifiers are how a CRS user does real work. They appear in audit log entries, in tuning files where a single rule is turned off for one path, and in `ctl` actions that remove a target from a rule's scope.

The v4.25.1 notes are the clearest example. A fix for XML attribute injection works by having rule 901181 remove the `XML://@*` target using `ctl:ruleRemoveTargetByTag`, and the same release adds a switch, `tx.crs_xml_attr_inspect`, to opt out of attribute inspection entirely. Both mechanisms are addressed by ID, so upgrading the engine rather than the ruleset can be a valid response to a configuration failure.

The repository tree backs this up. The `rules/` directory is the payload, `regex-assembly/` holds reusable pattern fragments, and `tests/` is what stands between a new pattern and a broken production WAF.

Configuration lives outside the rules, in crs-setup.conf.example

The top level tree carries `crs-setup.conf.example`, and the release notes refer to `tx.` variables such as `tx.crs_xml_attr_inspect` and `tx.crs_setup_version`. Taken together those point at how the project expects configuration to happen: variables set in a setup file, read by rules, rather than rules edited in place. Editing rule files directly is the option that guarantees pain at the next upgrade.

One switch in that file changed default behaviour recently. In v4.28.0 the maintainers enabled `crs_validate_utf8_encoding` by default, so an installation that upgrades inherits a new check without editing anything. Whether you want that on depends on whether your applications already reject malformed UTF-8 upstream, which is the sort of question the KNOWN_BUGS.md file exists to answer.

`plugins/` and `docs/` sit alongside `rules/` for the same reason. The rules are the part people need to reason about, and everything around them is packaging.

The v4.25.1 engine requirement that will break an older config load

The most operationally important entry in the release history is v4.25.1, published on 2026-07-02, and it is a breaking change rather than a detection addition. It requires libmodsecurity v3.0.16 or later. The reason is specific: the XML attribute injection fix depends on an upstream ModSecurity change that fixed the lexer's rejection of `@` inside `ctl:ruleRemoveTarget*` actions. On ModSecurity v3 older than v3.0.16 that `ctl` action fails to parse, and a parse failure at that point means the configuration does not load at all.

The same release notes carry a v2 caveat. Fully opting out of XML attribute inspection through `tx.crs_xml_attr_inspect` needs ModSecurity v2 at or above v2.9.14, and only once an upstream lexer issue is fixed, because `ctl:ruleRemoveTargetByTag` cannot remove the `XML://@*` target on that engine. So the opt-out is not symmetric between v2 and v3.

This is the kind of detail that decides whether an upgrade is an afternoon or an incident. It is also why the repository keeps a `BACKPORT_POLICY.md`: security fixes get cherry picked to older lines, with the engine constraints spelled out per backport.

Half of the recent work is about not blocking legitimate traffic

Detection additions in this project are the visible half. The other half is subtraction, and it takes up more of the v4.29.0 and v4.28.0 notes than the feature lists do.

In v4.29.0, rule 942190 was changed to require an operator or a quote after `!`, which the notes describe as cutting natural language false positives. Rule 942200 had its comma branch tightened to stop firing on User-Agent and Referer headers. Rule 942390 had a bypassable length bound on quoted and unary literals removed. In v4.28.0, `restricted-files.data` was updated to include NPM subdirectories without causing false positives, and rule 932171 was relaxed to allow an optional `json.` prefix in its `ARGS_NAMES` pattern. Earlier, in v4.28.0, an ORM lookup operator injection detection was added to rule 934.

Read together, those changes describe a project trading detection breadth for precision. Rule 934 catching ORM lookup injection is a gain; a rule that flags ordinary English in a query string is a cost that shows up as a support ticket. The project also expanded the web shell detection set in v4.29.0 and added backslash prefix evasion and unix quote evasion handling to the 932 shell command rules, so both directions move at once.

The Python in the repository is test and lint plumbing

The files that describe how changes get validated are worth reading before you contribute anything. `crs-linter.toml` configures a ruleset linter, so a malformed rule is caught by a machine rather than by a reviewer. `.pre-commit-config.yaml`, `.yamllint.yml` and `.linelint.yml` cover formatting across the YAML-heavy rule files and the data files. `renovate.json` tracks dependency updates. `.coderabbit.yaml` configures automated review.

The README's status table makes the same point from the outside: the `main` branch badge is for regression tests, wired through `.github/`. A repository of regular expressions that gate a production WAF cannot rely on eyeballing, and the layout suggests the project knows that.

The documentation set is similarly deliberate. `INSTALL.md` covers deployment, `KNOWN_BUGS.md` records problems that are known rather than fixed, `CHANGES.md` accumulates behaviour changes, `CONTRIBUTING.md` explains the workflow, and `docs/` holds the longer form. The README itself stays short on purpose and sends readers to coreruleset.org for installation, configuration, related projects and the list of useful tools.

How the project expects problems to be reported

The README is unusually specific about the feedback loop, and the detail matters for anyone running CRS in production. False positives and false negatives go to GitHub issues, and the project asks for the installed version plus the relevant portions of the audit log, because without both a rule ID and a log excerpt a detection cannot be reproduced or confirmed.

It also states a policy that explains part of the issue tracker: stale issues are flagged and closed after 120 days, with a saved search for the label. General usage questions belong in the project's Google Group, and day to day discussion in the `#coreruleset` channel on OWASP Slack, which the README notes is open to non-members.

That arrangement tells you something about the project's centre of gravity. The rules are the contribution, the log excerpts are the evidence, and the engine version is the context. Anyone planning to spend time on tuning should expect to be asked for those three things, and anyone evaluating a rule change should expect to wait for a regression run on `main` first.

Editorial conclusion

CRS is the right pick when you already run ModSecurity v3 or Coraza and want an OWASP reviewed set of detection rules rather than a hand written list. It is the wrong pick if you want a firewall you can run on its own, since nothing in this repository listens on a port, and it is a poor fit for engines older than libmodsecurity v3.0.16, where a ctl action stops parsing and the config will not load. Before deploying, check the engine version first, then read KNOWN_BUGS.md and the CHANGES.md entry for the version you are moving to, because that is where the behaviour differences show up.

Frequently asked questions

What is the OWASP CRS and what detection rules does it contain?

The OWASP CRS is a set of generic attack detection rules meant to run inside a WAF such as ModSecurity or Coraza, covering a wide range of attacks including the OWASP Top Ten. It contains no engine of its own, so the rules only do anything once a compatible firewall loads them.

What is ModSecurity used for in relation to CRS?

ModSecurity is one of the firewall engines the CRS rules are written for, alongside OWASP Coraza and other compatible WAFs. CRS supplies the rules and ModSecurity evaluates them against requests, which is why the two have to be version matched before an upgrade.

Which ModSecurity version is required for recent CRS releases?

Release v4.25.1 requires libmodsecurity v3.0.16 or later, because its XML attribute injection fix depends on a lexer change in ModSecurity. Older v3 releases fail to parse the `ctl:ruleRemoveTarget*` action used by rule 901181, and the configuration will not load.

Official sources

  1. coreruleset/coreruleset on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/coreruleset-coreruleset.svg)](https://hysenlabs.com/projects/coreruleset-coreruleset)