diff --git a/java/ql/lib/semmle/code/java/regex/regex.qll b/java/ql/lib/semmle/code/java/regex/regex.qll index aca51b74a03..7c24892ff2e 100644 --- a/java/ql/lib/semmle/code/java/regex/regex.qll +++ b/java/ql/lib/semmle/code/java/regex/regex.qll @@ -472,12 +472,19 @@ abstract class RegexString extends StringLiteral { ) } - private predicate flagGroupStart(int start, int end, string c) { + private predicate flagGroupStart(int start, int end) { this.isGroupStart(start) and this.getChar(start + 1) = "?" and - end = start + 3 and - c = this.getChar(start + 2) and - c in ["i", "m", "s", "u", "x", "U"] + this.getChar(start + 2) in ["i", "m", "s", "u", "x", "U"] and + end = start + 2 + } + + private predicate flagGroup(int start, int end, string c) { + exists(int inStart, int inEnd | + this.flagGroupStart(start, inStart) and + this.groupContents(start, end, inStart, inEnd) and + this.getChar([inStart .. inEnd - 1]) = c + ) } /** @@ -485,7 +492,7 @@ abstract class RegexString extends StringLiteral { * it is defined by a prefix. */ string getModeFromPrefix() { - exists(string c | this.flagGroupStart(_, _, c) | + exists(string c | this.flagGroup(_, _, c) | c = "i" and result = "IGNORECASE" or c = "m" and result = "MULTILINE" @@ -540,7 +547,7 @@ abstract class RegexString extends StringLiteral { private predicate groupStart(int start, int end) { this.nonCapturingGroupStart(start, end) or - this.flagGroupStart(start, end, _) + this.flagGroupStart(start, end) or this.namedGroupStart(start, end) or diff --git a/java/ql/test/query-tests/security/CWE-730/ExpRedosTest.java b/java/ql/test/query-tests/security/CWE-730/ExpRedosTest.java index 51eec6e74e7..4a31060850b 100644 --- a/java/ql/test/query-tests/security/CWE-730/ExpRedosTest.java +++ b/java/ql/test/query-tests/security/CWE-730/ExpRedosTest.java @@ -87,7 +87,7 @@ class ExpRedosTest { "(?s)(.|\\n)*!", // $ hasExpRedos // NOT GOOD; attack: "\n".repeat(100) + "." - "(?is)(.|\\n)*!", // $ MISSING: hasExpRedos + "(?is)(.|\\n)*!", // $ hasExpRedos // GOOD "([\\w.]+)*",