diff --git a/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll index dfe33630401..d1dff2c3ed7 100644 --- a/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll +++ b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll @@ -386,6 +386,14 @@ abstract class RegExp extends Expr { // wide hex char \Uhhhhhhhh this.getChar(start + 1) = "U" and end = start + 10 or + // variable width hex char \x{hh...} or \u{hh...} (1-6 digits) + this.getChar(start + 1) = ["x", "u"] and + this.getChar(start + 2) = "{" and + this.getChar(end - 1) = "}" and + end > start and + end <= start + 10 and + not exists(int i | start + 2 < i and i < end - 1 | this.getChar(i) = "}") + or // escape not handled above; update when adding a new case not this.getChar(start + 1) in ["x", "u", "U"] and not exists(this.getChar(start + 1).toInt()) and diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift index bd706e9dab5..f11131d1b5b 100644 --- a/swift/ql/test/library-tests/regex/redos_variants.swift +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -516,10 +516,10 @@ func myRegexpVariantsTests(myUrl: URL) throws { // BAD TODO: we should get this one // attack string: "X" + "a" x lots - _ = try Regex(#"X(\x{061}|a)*Y"#).firstMatch(in: tainted) // $ hasParseFailure= MISSING: redos-vulnerable= + _ = try Regex(#"X(\x{061}|a)*Y"#).firstMatch(in: tainted) // $ MISSING: redos-vulnerable= // GOOD - _ = try Regex(#"X(\x{061}|b)+Y"#).firstMatch(in: tainted) // $ hasParseFailure + _ = try Regex(#"X(\x{061}|b)+Y"#).firstMatch(in: tainted) // BAD // attack string: "X" + "7" x lots