CRS versions 4.30.0 and 4.25.2 LTS released

The OWASP CRS team is pleased to announce two coordinated releases today: v4.30.0 (main branch) and v4.25.2 (v4 LTS). Both fix the same three security vulnerabilities, published today as GitHub security advisories, along with a file upload bypass in the PHP and Java upload checks. Users on either supported v4 line are strongly encouraged to update.

For downloads and installation instructions, please refer to the Installation page.

Security fixes

All three vulnerabilities affect both release lines. CVE identifiers have been requested and will be added to the advisories once assigned.

Path-based command injection bypass of the RCE rules (GHSA-575j-qr6p-9763)

Severity: MEDIUM — CVSS 3.1 score 5.4 (AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:N)
CWE: CWE-693 — Protection Mechanism Failure

Impact

The 932 (Remote Command Execution) rule family did not include REQUEST_FILENAME in its targets. A command injection payload that CRS detects in a query or body argument was not inspected when the same payload was placed in the URL path instead, even at paranoia level 4. For example, GET /files?f=x%3Bid triggers rule 932350, while GET /files/x%3Bid triggered no 932 rule at all.

Who is impacted: applications that pass a URL path segment to a shell (for example os.popen, or child_process.exec with shell: true). Calls that don’t go through a shell, such as execFile, are not affected.

Fix

REQUEST_FILENAME is now a target of the RCE rules 932125–932390, with one exception: rule 932200 does not inspect the path, because it requires a / and every URL path contains one, so it would fire on ordinary filenames like John's report.pdf.

Workaround

If you can’t update right away, add the target to the rules that close the reported bypass:

SecRuleUpdateTargetById 932130 "REQUEST_FILENAME"
SecRuleUpdateTargetById 932235 "REQUEST_FILENAME"
SecRuleUpdateTargetById 932236 "REQUEST_FILENAME"
SecRuleUpdateTargetById 932240 "REQUEST_FILENAME"
SecRuleUpdateTargetById 932260 "REQUEST_FILENAME"
SecRuleUpdateTargetById 932281 "REQUEST_FILENAME"
SecRuleUpdateTargetById 932340 "REQUEST_FILENAME"
SecRuleUpdateTargetById 932350 "REQUEST_FILENAME"
SecRuleUpdateTargetById 932380 "REQUEST_FILENAME"

CRS 3.x is also affected and will not receive a fix. In 3.x, SecRuleUpdateTargetById 932130 "REQUEST_FILENAME" covers the only rule from this list that exists there.

Credit goes to @SoraMoko for reporting this issue and to @theseion for the fix.

Charset allow-list bypass via mixed-case CHARSET (GHSA-89h9-2j8h-9gp2)

Severity: HIGH — CVSS 3.1 score 7.2 (AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N)
CWE: CWE-178 — Improper Handling of Case Sensitivity; CWE-436 — Interpretation Conflict

Impact

Rule 920480 enforces the allow-list of charsets a client may declare in the Content-Type header (tx.allowed_request_content_type_charset). Its anchor regex matched only the lowercase parameter name charset. Media-type parameter names are case-insensitive (RFC 9110 §8.3.1), so Content-Type: application/x-www-form-urlencoded; CHARSET=utf-7 never matched, and the allow-list check never ran. This reopens the encoding-based evasion class the rule exists to block, such as UTF-7 XSS, whenever the backend honors the declared charset.

Who is impacted: every CRS v4 release up to and including 4.29.0 and 4.25.1, at the default paranoia levels. CRS 3.3.x is not affected, because its equivalent rule already lowercases the header.

Workaround

SecRuleUpdateActionById 920480 "t:lowercase"

Credit goes to @HackingRepo for reporting this issue and to @fzipi for the fix.

Multipart _charset_ shadowing bypass (GHSA-qmx4-jfcv-fgww)

Severity: MEDIUM — CVSS 3.1 score 5.8 (AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N)
CWE: CWE-235 — Improper Handling of Extra Parameters; CWE-436 — Interpretation Conflict

Impact

Rule 922100 blocks multipart requests whose global _charset_ field declares a charset that isn’t allowed by policy. It only checked one _charset_ value. An attacker could add a second, allowed _charset_, either in the query string or in another multipart part, and the disallowed one went unchecked. That let the attacker inject multipart parts in any encoding. Which value was checked depended on the engine: ModSecurity v2 expands %{ARGS._charset_} to the first value, libmodsecurity3 to the last.

Fix

Every _charset_ value is now collected and checked individually, so no value can shadow another on either engine.

Credit goes to @airween for reporting this issue, and to @airween and @fzipi for the fix.

Trailing-slash bypass of the upload extension checks

Rules 933110 (PHP) and 944140 (Java) block uploads of script files by extension. They tolerated trailing dots after the extension (shell.php.) but not a trailing slash, so shell.php/ was not blocked. That matters for frameworks that strip a trailing path separator before saving the file. Both rules now tolerate any mix of trailing dots and slashes. (#4815)

Changes in v4.30.0

Important changes

New features and detections

Rule removals

Other changes

Changes in v4.25.2 LTS

This release backports security and selected bug fixes onto the v4.25.x LTS branch.

Security fixes

All three advisories and the upload extension fix described above, plus:

Bug fixes

Other changes

The response compression consolidation (#4806) is not part of v4.25.2, so the per-file compression rules (950010–956010) remain on the LTS line.

Upgrading

Both releases are available on the CRS GitHub releases page.

Because the RCE rules now inspect the URL path, review your false-positive logs for 932xxx alerts on REQUEST_FILENAME after updating, especially if your application uses shell-like characters in path segments.

If you have questions or concerns, please reach out via the CRS GitHub repository, in our Slack channel (#coreruleset on owasp.slack.com), or on our mailing list.

Felipe Zipitria