{"id":"CVE-2026-77422","aliases":["GHSA-r2xf-8xr9-62gw"],"url":"https://o3.security/vulnerability/CVE-2026-77422","summary":"JLine: ReDoS in Built-in grep Command Amplified by Automatic `.*` Wrapping","details":"### Summary\n\nThe JLine3 built-in `grep` command wraps the user-supplied regular expression with\n`.*` before compiling it with Java's backtracking regex engine. This amplifies\ncatastrophic backtracking and allows a short pattern such as `(a+)+b` to hang the\ncommand thread on non-matching input. In environments that expose the JLine shell to\nremote users, this is a denial-of-service issue.\n\n### Details\n\nIn `builtins/src/main/java/org/jline/builtins/PosixCommands.java`, the grep\nimplementation rewrites the user pattern before compilation:\n\n```java\nString regex = args.remove(0);\nString regexp = regex;\nif (opt.isSet(\"word-regexp\")) {\n    regexp = \"\\\\b\" + regexp + \"\\\\b\";\n}\nif (opt.isSet(\"line-regexp\")) {\n    regexp = \"^\" + regexp + \"$\";\n} else {\n    regexp = \".*\" + regexp + \".*\";\n}\n```\n\nThe transformed pattern is compiled with `Pattern.compile(...)` and then used to test\neach input line. For a payload such as `(a+)+b`, the automatic `.*` prefix and suffix\nincrease the backtracking search space substantially.\n\nAffected source location:\n- `builtins/src/main/java/org/jline/builtins/PosixCommands.java`\n- `grep(...)`\n\n### PoC\n\n1. Create a file containing a long run of `a` characters:\n\n```sh\nprintf 'aaaaaaaaaaaaaaaaaaaaaaa\\n' > /tmp/testfile.txt\n```\n\n2. Run JLine3's built-in `grep` against that file:\n\n```sh\ngrep '(a+)+b' /tmp/testfile.txt\n```\n\nExpected result:\n- The command stops responding.\n- The executing thread consumes high CPU.\n\nReproduction environment:\n- JLine3 on x86_64 Linux\n- OpenJDK 25.0.2\n\n### Impact\n\nThis is a denial-of-service vulnerability caused by catastrophic regex backtracking.\nAny application embedding `org.jline:jline-builtins` and exposing the built-in `grep`\ncommand is impacted. In remote shell deployments, an attacker can occupy a worker\nthread indefinitely and repeat the attack across multiple sessions to reduce service\navailability for other users.\n\n### Suggested Fix\n\nThe preferred fix for the current git head is:\n- stop rewriting non-line-regexp searches as `.*...*`\n- use `Matcher.find()` for substring semantics\n- compile user patterns with a linear-time engine such as RE2/J\n\nSuggested patch:\n\n```diff\ndiff --git a/builtins/pom.xml b/builtins/pom.xml\n--- a/builtins/pom.xml\n+++ b/builtins/pom.xml\n@@\n         <dependency>\n+            <groupId>com.google.re2j</groupId>\n+            <artifactId>re2j</artifactId>\n+            <version>1.8</version>\n+        </dependency>\n+        <dependency>\n             <groupId>org.jline</groupId>\n             <artifactId>jline-reader</artifactId>\n         </dependency>\n\ndiff --git a/builtins/src/main/java/org/jline/builtins/PosixCommands.java b/builtins/src/main/java/org/jline/builtins/PosixCommands.java\n--- a/builtins/src/main/java/org/jline/builtins/PosixCommands.java\n+++ b/builtins/src/main/java/org/jline/builtins/PosixCommands.java\n@@\n-import java.util.regex.Pattern;\n+import com.google.re2j.Pattern;\n@@\n         if (opt.isSet(\"line-regexp\")) {\n             regexp = \"^\" + regexp + \"$\";\n-        } else {\n-            regexp = \".*\" + regexp + \".*\";\n         }\n@@\n-        boolean m = p.matcher(line).matches();\n+        boolean m = opt.isSet(\"line-regexp\")\n+                ? p.matcher(line).matches()\n+                : p.matcher(line).find();\n```\n\n### Credits\n\nThis issue was identified by Michał Majchrowicz and Marcin Wyczechowski, members of the AFINE Team.","published":"2026-09-23T18:09:32.308Z","modified":"2026-10-21T10:46:20.930764848Z","cvss":{"score":7.5,"severity":"HIGH","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"},"epss":null,"cisaKev":null,"exploitsKnown":null,"affectedPackages":[{"ecosystem":"Maven","name":"org.jline:jline-builtins","fixedVersion":"4.3.1"},{"ecosystem":"Maven","name":"org.jline:jline-builtins","fixedVersion":"3.30.15"}],"fix":{"url":"https://github.com/jline/jline3/commit/1d5fc3099e77938b971e197211cad2d4fbb17541","label":"jline/jline3@1d5fc30"},"references":[{"type":"WEB","url":"https://github.com/jline/jline3/releases/tag/4.3.1"},{"type":"WEB","url":"https://github.com/jline/jline3/releases/tag/jline-3.30.15"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/77xxx/CVE-2026-77422.json"},{"type":"ADVISORY","url":"https://github.com/jline/jline3/security/advisories/GHSA-r2xf-8xr9-62gw"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-77422"},{"type":"FIX","url":"https://github.com/jline/jline3/commit/1d5fc3099e77938b971e197211cad2d4fbb17541"},{"type":"FIX","url":"https://github.com/jline/jline3/commit/341ee69ccc57b7733c1b40d6993219b64b3206ae"},{"type":"FIX","url":"https://github.com/jline/jline3/pull/2012"},{"type":"FIX","url":"https://github.com/jline/jline3/pull/2018"},{"type":"PACKAGE","url":"https://github.com/jline/jline3"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-10-21T10:46:20.930764848Z"}}