Regular expression denial of service in Rust's regex crate
Description
regex is an implementation of regular expressions for the Rust language. The regex crate features built-in mitigations to prevent denial of service attacks caused by untrusted regexes, or untrusted input matched by trusted regexes. Those (tunable) mitigations already provide sane defaults to prevent attacks. This guarantee is documented and it's considered part of the crate's API. Unfortunately a bug was discovered in the mitigations designed to prevent untrusted regexes to take an arbitrary amount of time during parsing, and it's possible to craft regexes that bypass such mitigations. This makes it possible to perform denial of service attacks by sending specially crafted regexes to services accepting user-controlled, untrusted regexes. All versions of the regex crate before or equal to 1.5.4 are affected by this issue. The fix is include starting from regex 1.5.5. All users accepting user-controlled regexes are recommended to upgrade immediately to the latest version of the regex crate. Unfortunately there is no fixed set of problematic regexes, as there are practically infinite regexes that could be crafted to exploit this vulnerability. Because of this, it us not recommend to deny known problematic regexes.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A bug in the regex crate's parsing mitigations allows crafted regexes to cause denial of service via excessive CPU usage.
Vulnerability
The regex crate for Rust includes built-in mitigations to prevent denial of service from untrusted regular expressions. However, versions up to and including 1.5.4 contain a bug where empty sub-expressions (e.g., from large repetitions like (?:){N}) do not properly contribute to the size limit check during compilation, allowing an attacker to bypass the mitigation and cause excessive CPU consumption during parsing [1][3][4].
Exploitation
An attacker can send a specially crafted regex containing a large repetition on an empty sub-expression to a service that accepts user-controlled regexes. No authentication or user interaction is required. The regex parser will spend an inordinate amount of time processing the empty sub-expression, leading to denial of service [1][4].
Impact
Successful exploitation results in denial of service, as the service becomes unresponsive due to CPU exhaustion. There is no impact on confidentiality or integrity. The CVSS score is 7.5 (High) with vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H [4].
Mitigation
The fix is included in regex version 1.5.5, released on 2022-03-08 [1][3][4]. All users accepting untrusted regexes should upgrade immediately. There is no practical workaround, as blacklisting known problematic patterns is not effective due to the infinite variety of exploitable regexes [1][4].
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
regexcrates.io | < 1.5.5 | 1.5.5 |
Affected products
79- ghsa-coords78 versionspkg:cargo/regexpkg:rpm/almalinux/firefoxpkg:rpm/almalinux/thunderbirdpkg:rpm/opensuse/aws-nitro-enclaves-cli&distro=openSUSE%20Leap%2015.4pkg:rpm/opensuse/bat&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/cargo-audit&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/firecracker&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/firefox-esr&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/git-delta&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/juliaup&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/kanidm&distro=openSUSE%20Leap%2015.6pkg:rpm/opensuse/macchina&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/MozillaFirefox&distro=openSUSE%20Leap%2015.3pkg:rpm/opensuse/MozillaFirefox&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/MozillaThunderbird&distro=openSUSE%20Leap%2015.3pkg:rpm/opensuse/parsec&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/parsec-tool&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/pijul&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/pleaser&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/rage-encryption&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/rustup&distro=openSUSE%20Leap%2015.3pkg:rpm/opensuse/rustup&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/sccache&distro=openSUSE%20Leap%2015.3pkg:rpm/opensuse/sccache&distro=openSUSE%20Leap%2015.4pkg:rpm/opensuse/sccache&distro=openSUSE%20Leap%2015.5pkg:rpm/opensuse/sccache&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/spotifyd&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/treefetch&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/tuigreet&distro=openSUSE%20Tumbleweedpkg:rpm/suse/afterburn&distro=SUSE%20Linux%20Enterprise%20Micro%205.2pkg:rpm/suse/afterburn&distro=SUSE%20Linux%20Enterprise%20Micro%205.3pkg:rpm/suse/afterburn&distro=SUSE%20Linux%20Enterprise%20Micro%205.4pkg:rpm/suse/afterburn&distro=SUSE%20Linux%20Enterprise%20Micro%205.5pkg:rpm/suse/aws-nitro-enclaves-cli&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Public%20Cloud%2015%20SP4pkg:rpm/suse/kanidm&distro=SUSE%20Package%20Hub%2015%20SP6pkg:rpm/suse/MozillaFirefox&distro=HPE%20Helion%20OpenStack%208pkg:rpm/suse/MozillaFirefox&distro=SUSE%20Enterprise%20Storage%206pkg:rpm/suse/MozillaFirefox&distro=SUSE%20Enterprise%20Storage%207pkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP1-ESPOSpkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP1-LTSSpkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP2-ESPOSpkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP2-LTSSpkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015-ESPOSpkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015-LTSSpkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Desktop%20Applications%2015%20SP3pkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Real%20Time%2015%20SP2pkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Server%2011%20SP4-LTSSpkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Server%2012%20SP2-BCLpkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Server%2012%20SP3-BCLpkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Server%2012%20SP3-LTSSpkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Server%2012%20SP4-LTSSpkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Server%2012%20SP5pkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Server%2015%20SP1-BCLpkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Server%2015%20SP1-LTSSpkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Server%2015%20SP2-BCLpkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Server%2015%20SP2-LTSSpkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Server%2015-LTSSpkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2012%20SP3pkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2012%20SP4pkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2012%20SP5pkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2015pkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2015%20SP1pkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2015%20SP2pkg:rpm/suse/MozillaFirefox&distro=SUSE%20Linux%20Enterprise%20Software%20Development%20Kit%2012%20SP5pkg:rpm/suse/MozillaFirefox&distro=SUSE%20Manager%20Proxy%204.1pkg:rpm/suse/MozillaFirefox&distro=SUSE%20Manager%20Retail%20Branch%20Server%204.1pkg:rpm/suse/MozillaFirefox&distro=SUSE%20Manager%20Server%204.1pkg:rpm/suse/MozillaFirefox&distro=SUSE%20OpenStack%20Cloud%208pkg:rpm/suse/MozillaFirefox&distro=SUSE%20OpenStack%20Cloud%209pkg:rpm/suse/MozillaFirefox&distro=SUSE%20OpenStack%20Cloud%20Crowbar%208pkg:rpm/suse/MozillaFirefox&distro=SUSE%20OpenStack%20Cloud%20Crowbar%209pkg:rpm/suse/MozillaThunderbird&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Package%20Hub%2015%20SP3pkg:rpm/suse/MozillaThunderbird&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Package%20Hub%2015%20SP4pkg:rpm/suse/MozillaThunderbird&distro=SUSE%20Linux%20Enterprise%20Workstation%20Extension%2015%20SP3pkg:rpm/suse/rustup&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Development%20Tools%2015%20SP3pkg:rpm/suse/sccache&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Development%20Tools%2015%20SP3pkg:rpm/suse/sccache&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Development%20Tools%2015%20SP4pkg:rpm/suse/sccache&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Development%20Tools%2015%20SP5
< 1.5.5+ 77 more
- (no CPE)range: < 1.5.5
- (no CPE)range: < 91.8.0-1.el8_5.alma
- (no CPE)range: < 91.8.0-1.el8_5.alma
- (no CPE)range: < 1.2.2~git0.4ccc639-150400.3.3.1
- (no CPE)range: < 0.21.0-1.1
- (no CPE)range: < 0.16.0~git0.625c965-3.1
- (no CPE)range: < 1.0.0-2.1
- (no CPE)range: < 128.5.1-1.1
- (no CPE)range: < 0.12.1-1.1
- (no CPE)range: < 1.5.37-2.1
- (no CPE)range: < 1.3.3~git0.f075d13-bp156.4.1
- (no CPE)range: < 6.0.6~git0.c21ce78-2.1
- (no CPE)range: < 91.8.0-150200.152.26.1
- (no CPE)range: < 99.0-1.1
- (no CPE)range: < 91.8.0-150200.8.65.1
- (no CPE)range: < 1.0.0~rc3-1.1
- (no CPE)range: < 0.5.2-1.1
- (no CPE)range: < 1.0.0~beta.2-1.1
- (no CPE)range: < 0.5.1~git0.ce9627c-4.1
- (no CPE)range: < 0.7.1+0-2.1
- (no CPE)range: < 1.25.1~0-150300.7.13.2
- (no CPE)range: < 1.24.3~0-3.1
- (no CPE)range: < 0.3.0~git5.14a4b8b-150300.7.9.1
- (no CPE)range: < 0.4.2~3-150400.3.3.1
- (no CPE)range: < 0.4.2~3-150400.3.3.1
- (no CPE)range: < 0.2.15~git0.6b6d2f7-11.1
- (no CPE)range: < 0.3.3-5.1
- (no CPE)range: < 2.0.0~git0.5b3eac1-2.1
- (no CPE)range: < 0.7.1-4.1
- (no CPE)range: < 5.9.0.git21.a73f509-150300.3.5.1
- (no CPE)range: < 5.9.0.git21.a73f509-150400.3.3.1
- (no CPE)range: < 5.9.0.git21.a73f509-150400.3.3.1
- (no CPE)range: < 5.9.0.git21.a73f509-150500.3.3.1
- (no CPE)range: < 1.2.2~git0.4ccc639-150400.3.3.1
- (no CPE)range: < 1.3.3~git0.f075d13-bp156.4.1
- (no CPE)range: < 91.8.0-112.98.1
- (no CPE)range: < 91.8.0-150000.150.27.1
- (no CPE)range: < 91.8.0-150200.152.26.1
- (no CPE)range: < 91.8.0-150000.150.27.1
- (no CPE)range: < 91.8.0-150000.150.27.1
- (no CPE)range: < 91.8.0-150200.152.26.1
- (no CPE)range: < 91.8.0-150200.152.26.1
- (no CPE)range: < 91.8.0-150000.150.27.1
- (no CPE)range: < 91.8.0-150000.150.27.1
- (no CPE)range: < 91.8.0-150200.152.26.1
- (no CPE)range: < 91.8.0-150200.152.26.1
- (no CPE)range: < 91.8.0-78.170.1
- (no CPE)range: < 91.8.0-112.98.1
- (no CPE)range: < 91.8.0-112.98.1
- (no CPE)range: < 91.8.0-112.98.1
- (no CPE)range: < 91.8.0-112.98.1
- (no CPE)range: < 91.8.0-112.98.1
- (no CPE)range: < 91.8.0-150000.150.27.1
- (no CPE)range: < 91.8.0-150000.150.27.1
- (no CPE)range: < 91.8.0-150200.152.26.1
- (no CPE)range: < 91.8.0-150200.152.26.1
- (no CPE)range: < 91.8.0-150000.150.27.1
- (no CPE)range: < 91.8.0-112.98.1
- (no CPE)range: < 91.8.0-112.98.1
- (no CPE)range: < 91.8.0-112.98.1
- (no CPE)range: < 91.8.0-150000.150.27.1
- (no CPE)range: < 91.8.0-150000.150.27.1
- (no CPE)range: < 91.8.0-150200.152.26.1
- (no CPE)range: < 91.8.0-112.98.1
- (no CPE)range: < 91.8.0-150200.152.26.1
- (no CPE)range: < 91.8.0-150200.152.26.1
- (no CPE)range: < 91.8.0-150200.152.26.1
- (no CPE)range: < 91.8.0-112.98.1
- (no CPE)range: < 91.8.0-112.98.1
- (no CPE)range: < 91.8.0-112.98.1
- (no CPE)range: < 91.8.0-112.98.1
- (no CPE)range: < 91.8.0-150200.8.65.1
- (no CPE)range: < 91.8.0-150200.8.65.1
- (no CPE)range: < 91.8.0-150200.8.65.1
- (no CPE)range: < 1.25.1~0-150300.7.13.2
- (no CPE)range: < 0.3.0~git5.14a4b8b-150300.7.9.1
- (no CPE)range: < 0.4.2~3-150400.3.3.1
- (no CPE)range: < 0.4.2~3-150400.3.3.1
- rust-lang/regexv5Range: < 1.5.5
Patches
1ae70b41d4f46security: fix denial-of-service bug in compiler
2 files changed · +95 −2
src/compile.rs+25 −2 modified@@ -38,6 +38,16 @@ pub struct Compiler { suffix_cache: SuffixCache, utf8_seqs: Option<Utf8Sequences>, byte_classes: ByteClassSet, + // This keeps track of extra bytes allocated while compiling the regex + // program. Currently, this corresponds to two things. First is the heap + // memory allocated by Unicode character classes ('InstRanges'). Second is + // a "fake" amount of memory used by empty sub-expressions, so that enough + // empty sub-expressions will ultimately trigger the compiler to bail + // because of a size limit restriction. (That empty sub-expressions don't + // add to heap memory usage is more-or-less an implementation detail.) In + // the second case, if we don't bail, then an excessively large repetition + // on an empty sub-expression can result in the compiler using a very large + // amount of CPU time. extra_inst_bytes: usize, } @@ -260,7 +270,7 @@ impl Compiler { self.check_size()?; match *expr.kind() { - Empty => Ok(None), + Empty => self.c_empty(), Literal(hir::Literal::Unicode(c)) => self.c_char(c), Literal(hir::Literal::Byte(b)) => { assert!(self.compiled.uses_bytes()); @@ -378,6 +388,19 @@ impl Compiler { } } + fn c_empty(&mut self) -> ResultOrEmpty { + // See: https://github.com/rust-lang/regex/security/advisories/GHSA-m5pq-gvj9-9vr8 + // See: CVE-2022-24713 + // + // Since 'empty' sub-expressions don't increase the size of + // the actual compiled object, we "fake" an increase in its + // size so that our 'check_size_limit' routine will eventually + // stop compilation if there are too many empty sub-expressions + // (e.g., via a large repetition). + self.extra_inst_bytes += std::mem::size_of::<Inst>(); + Ok(None) + } + fn c_capture(&mut self, first_slot: usize, expr: &Hir) -> ResultOrEmpty { if self.num_exprs > 1 || self.compiled.is_dfa { // Don't ever compile Save instructions for regex sets because @@ -496,7 +519,7 @@ impl Compiler { let mut exprs = exprs.into_iter(); let Patch { mut hole, entry } = loop { match exprs.next() { - None => return Ok(None), + None => return self.c_empty(), Some(e) => { if let Some(p) = self.c(e)? { break p;
tests/test_default.rs+70 −0 modified@@ -150,3 +150,73 @@ fn regex_is_reasonably_small() { assert_eq!(16, size_of::<bytes::Regex>()); assert_eq!(16, size_of::<bytes::RegexSet>()); } + +// See: https://github.com/rust-lang/regex/security/advisories/GHSA-m5pq-gvj9-9vr8 +// See: CVE-2022-24713 +// +// We test that our regex compiler will correctly return a "too big" error when +// we try to use a very large repetition on an *empty* sub-expression. +// +// At the time this test was written, the regex compiler does not represent +// empty sub-expressions with any bytecode instructions. In effect, it's an +// "optimization" to leave them out, since they would otherwise correspond +// to an unconditional JUMP in the regex bytecode (i.e., an unconditional +// epsilon transition in the NFA graph). Therefore, an empty sub-expression +// represents an interesting case for the compiler's size limits. Since it +// doesn't actually contribute any additional memory to the compiled regex +// instructions, the size limit machinery never detects it. Instead, it just +// dumbly tries to compile the empty sub-expression N times, where N is the +// repetition size. +// +// When N is very large, this will cause the compiler to essentially spin and +// do nothing for a decently large amount of time. It causes the regex to take +// quite a bit of time to compile, despite the concrete syntax of the regex +// being quite small. +// +// The degree to which this is actually a problem is somewhat of a judgment +// call. Some regexes simply take a long time to compile. But in general, you +// should be able to reasonably control this by setting lower or higher size +// limits on the compiled object size. But this mitigation doesn't work at all +// for this case. +// +// This particular test is somewhat narrow. It merely checks that regex +// compilation will, at some point, return a "too big" error. Before the +// fix landed, this test would eventually fail because the regex would be +// successfully compiled (after enough time elapsed). So while this test +// doesn't check that we exit in a reasonable amount of time, it does at least +// check that we are properly returning an error at some point. +#[test] +fn big_empty_regex_fails() { + use regex::Regex; + + let result = Regex::new("(?:){4294967295}"); + assert!(result.is_err()); +} + +// Below is a "billion laughs" variant of the previous test case. +#[test] +fn big_empty_reps_chain_regex_fails() { + use regex::Regex; + + let result = Regex::new("(?:){64}{64}{64}{64}{64}{64}"); + assert!(result.is_err()); +} + +// Below is another situation where a zero-length sub-expression can be +// introduced. +#[test] +fn big_zero_reps_regex_fails() { + use regex::Regex; + + let result = Regex::new(r"x{0}{4294967295}"); + assert!(result.is_err()); +} + +// Testing another case for completeness. +#[test] +fn empty_alt_regex_fails() { + use regex::Regex; + + let result = Regex::new(r"(?:|){4294967295}"); + assert!(result.is_err()); +}
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
18- github.com/advisories/GHSA-m5pq-gvj9-9vr8ghsaADVISORY
- lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/JANLZ3JXWJR7FSHE57K66UIZUIJZI67T/mitrevendor-advisoryx_refsource_FEDORA
- lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/O3YB7CURSG64CIPCDPNMGPE4UU24AB6H/mitrevendor-advisoryx_refsource_FEDORA
- lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/PDOWTHNVGBOP2HN27PUFIGRYNSNDTYRJ/mitrevendor-advisoryx_refsource_FEDORA
- nvd.nist.gov/vuln/detail/CVE-2022-24713ghsaADVISORY
- security.gentoo.org/glsa/202208-08ghsavendor-advisoryx_refsource_GENTOOWEB
- security.gentoo.org/glsa/202208-14ghsavendor-advisoryx_refsource_GENTOOWEB
- www.debian.org/security/2022/dsa-5113ghsavendor-advisoryx_refsource_DEBIANWEB
- www.debian.org/security/2022/dsa-5118ghsavendor-advisoryx_refsource_DEBIANWEB
- github.com/rust-lang/regex/commit/ae70b41d4f46641dbc45c7a4f87954aea356283eghsax_refsource_MISCWEB
- github.com/rust-lang/regex/security/advisories/GHSA-m5pq-gvj9-9vr8ghsax_refsource_CONFIRMWEB
- groups.google.com/g/rustlang-security-announcements/c/NcNNL1Jq7Ywghsax_refsource_MISCWEB
- lists.debian.org/debian-lts-announce/2022/04/msg00003.htmlghsamailing-listx_refsource_MLISTWEB
- lists.debian.org/debian-lts-announce/2022/04/msg00009.htmlghsamailing-listx_refsource_MLISTWEB
- lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/JANLZ3JXWJR7FSHE57K66UIZUIJZI67TghsaWEB
- lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/O3YB7CURSG64CIPCDPNMGPE4UU24AB6HghsaWEB
- lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/PDOWTHNVGBOP2HN27PUFIGRYNSNDTYRJghsaWEB
- rustsec.org/advisories/RUSTSEC-2022-0013.htmlghsaWEB
News mentions
0No linked articles in our index yet.