From 7fb3d81d2fb0489bb89efa133e348ff88f0ecba0 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 14 Feb 2022 18:49:57 +0100 Subject: [PATCH] add further normalization of char classses --- .../java/security/performance/ReDoSUtil.qll | 66 ++++- .../security/performance/ReDoSUtil.qll | 66 ++++- .../ReDoS/PolynomialBackTracking.expected | 267 +++++++++--------- .../ReDoS/PolynomialReDoS.expected | 28 +- .../Performance/ReDoS/ReDoS.expected | 82 +++--- .../python/security/performance/ReDoSUtil.qll | 66 ++++- .../Security/CWE-730-ReDoS/ReDoS.expected | 14 +- .../ruby/security/performance/ReDoSUtil.qll | 66 ++++- .../cwe-1333-exponential-redos/ReDoS.expected | 12 +- 9 files changed, 415 insertions(+), 252 deletions(-) diff --git a/java/ql/lib/semmle/code/java/security/performance/ReDoSUtil.qll b/java/ql/lib/semmle/code/java/security/performance/ReDoSUtil.qll index 35f8ffc0e65..58900594158 100644 --- a/java/ql/lib/semmle/code/java/security/performance/ReDoSUtil.qll +++ b/java/ql/lib/semmle/code/java/security/performance/ReDoSUtil.qll @@ -199,7 +199,7 @@ CharClass getCanonicalCharClass(RegExpTerm term) { /** * Holds if `a` and `b` are input symbols from the same regexp. */ -private predicate sharesRoot(TInputSymbol a, TInputSymbol b) { +private predicate sharesRoot(InputSymbol a, InputSymbol b) { exists(RegExpRoot root | belongsTo(a, root) and belongsTo(b, root) @@ -209,7 +209,7 @@ private predicate sharesRoot(TInputSymbol a, TInputSymbol b) { /** * Holds if the `a` is an input symbol from a regexp that has root `root`. */ -private predicate belongsTo(TInputSymbol a, RegExpRoot root) { +private predicate belongsTo(InputSymbol a, RegExpRoot root) { exists(State s | getRoot(s.getRepr()) = root | delta(s, a, _) or @@ -378,6 +378,13 @@ private module CharacterClasses { ) } + bindingset[char, cc] + private string caseNormalize(string char, RegExpTerm cc) { + if RegExpFlags::isIgnoreCase(cc.getRootTerm()) + then result = char.toLowerCase() + else result = char + } + /** * An implementation of `CharacterClass` for positive (non inverted) character classes. */ @@ -386,7 +393,7 @@ private module CharacterClasses { PositiveCharacterClass() { this = getCanonicalCharClass(cc) and not cc.isInverted() } - override string getARelevantChar() { result = getAMentionedChar(cc) } + override string getARelevantChar() { result = caseNormalize(getAMentionedChar(cc), cc) } override predicate matches(string char) { hasChildThatMatches(cc, char) } } @@ -400,8 +407,8 @@ private module CharacterClasses { InvertedCharacterClass() { this = getCanonicalCharClass(cc) and cc.isInverted() } override string getARelevantChar() { - result = nextChar(getAMentionedChar(cc)) or - nextChar(result) = getAMentionedChar(cc) + result = nextChar(caseNormalize(getAMentionedChar(cc), cc)) or + nextChar(result) = caseNormalize(getAMentionedChar(cc), cc) } bindingset[char] @@ -428,13 +435,12 @@ private module CharacterClasses { */ private class PositiveCharacterClassEscape extends CharacterClass { string charClass; + RegExpTerm cc; PositiveCharacterClassEscape() { - exists(RegExpTerm cc | - isEscapeClass(cc, charClass) and - this = getCanonicalCharClass(cc) and - charClass = ["d", "s", "w"] - ) + isEscapeClass(cc, charClass) and + this = getCanonicalCharClass(cc) and + charClass = ["d", "s", "w"] } override string getARelevantChar() { @@ -445,7 +451,9 @@ private module CharacterClasses { result = " " or charClass = "w" and - result = ["a", "Z", "_", "0", "9"] + if RegExpFlags::isIgnoreCase(cc.getRootTerm()) + then result = ["a", "z", "_", "0", "9"] + else result = ["a", "Z", "_", "0", "9"] } override predicate matches(string char) { classEscapeMatches(charClass, char) } @@ -492,6 +500,34 @@ private module CharacterClasses { not classEscapeMatches(charClass.toLowerCase(), char) } } + + /** Gets a representative for all char classes that match the same chars as `c`. */ + CharacterClass normalize(CharacterClass c) { + exists(string normalization | + normalization = getMormalizationString(c) and + result = + min(CharacterClass cc, string raw | + getMormalizationString(cc) = normalization and cc = CharClass(raw) + | + cc order by raw + ) + ) + } + + /** Gets a string representing all the chars matched by `c` */ + private string getMormalizationString(CharacterClass c) { + (c instanceof PositiveCharacterClass or c instanceof PositiveCharacterClassEscape) and + result = concat(string char | c.matches(char) and char = CharacterClasses::getARelevantChar()) + or + (c instanceof InvertedCharacterClass or c instanceof NegativeCharacterClassEscape) and + // the string produced by the concat can not contain repeated chars + // so by starting the below with "nn" we can guarantee that + // it will not overlap with the above case. + // and a negative char class can never match the same chars as a positive one, so we don't miss any results from this. + result = + "nn:" + + concat(string char | not c.matches(char) and char = CharacterClasses::getARelevantChar()) + } } private class EdgeLabel extends TInputSymbol { @@ -620,13 +656,17 @@ predicate delta(State q1, EdgeLabel lbl, State q2) { cc.isUniversalClass() and q1 = before(cc) and lbl = Any() and q2 = after(cc) or q1 = before(cc) and - lbl = CharClass(cc.getRawValue() + "|" + getCanonicalizationFlags(cc.getRootTerm())) and + lbl = + CharacterClasses::normalize(CharClass(cc.getRawValue() + "|" + + getCanonicalizationFlags(cc.getRootTerm()))) and q2 = after(cc) ) or exists(RegExpTerm cc | isEscapeClass(cc, _) | q1 = before(cc) and - lbl = CharClass(cc.getRawValue() + "|" + getCanonicalizationFlags(cc.getRootTerm())) and + lbl = + CharacterClasses::normalize(CharClass(cc.getRawValue() + "|" + + getCanonicalizationFlags(cc.getRootTerm()))) and q2 = after(cc) ) or diff --git a/javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll b/javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll index 35f8ffc0e65..58900594158 100644 --- a/javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll +++ b/javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll @@ -199,7 +199,7 @@ CharClass getCanonicalCharClass(RegExpTerm term) { /** * Holds if `a` and `b` are input symbols from the same regexp. */ -private predicate sharesRoot(TInputSymbol a, TInputSymbol b) { +private predicate sharesRoot(InputSymbol a, InputSymbol b) { exists(RegExpRoot root | belongsTo(a, root) and belongsTo(b, root) @@ -209,7 +209,7 @@ private predicate sharesRoot(TInputSymbol a, TInputSymbol b) { /** * Holds if the `a` is an input symbol from a regexp that has root `root`. */ -private predicate belongsTo(TInputSymbol a, RegExpRoot root) { +private predicate belongsTo(InputSymbol a, RegExpRoot root) { exists(State s | getRoot(s.getRepr()) = root | delta(s, a, _) or @@ -378,6 +378,13 @@ private module CharacterClasses { ) } + bindingset[char, cc] + private string caseNormalize(string char, RegExpTerm cc) { + if RegExpFlags::isIgnoreCase(cc.getRootTerm()) + then result = char.toLowerCase() + else result = char + } + /** * An implementation of `CharacterClass` for positive (non inverted) character classes. */ @@ -386,7 +393,7 @@ private module CharacterClasses { PositiveCharacterClass() { this = getCanonicalCharClass(cc) and not cc.isInverted() } - override string getARelevantChar() { result = getAMentionedChar(cc) } + override string getARelevantChar() { result = caseNormalize(getAMentionedChar(cc), cc) } override predicate matches(string char) { hasChildThatMatches(cc, char) } } @@ -400,8 +407,8 @@ private module CharacterClasses { InvertedCharacterClass() { this = getCanonicalCharClass(cc) and cc.isInverted() } override string getARelevantChar() { - result = nextChar(getAMentionedChar(cc)) or - nextChar(result) = getAMentionedChar(cc) + result = nextChar(caseNormalize(getAMentionedChar(cc), cc)) or + nextChar(result) = caseNormalize(getAMentionedChar(cc), cc) } bindingset[char] @@ -428,13 +435,12 @@ private module CharacterClasses { */ private class PositiveCharacterClassEscape extends CharacterClass { string charClass; + RegExpTerm cc; PositiveCharacterClassEscape() { - exists(RegExpTerm cc | - isEscapeClass(cc, charClass) and - this = getCanonicalCharClass(cc) and - charClass = ["d", "s", "w"] - ) + isEscapeClass(cc, charClass) and + this = getCanonicalCharClass(cc) and + charClass = ["d", "s", "w"] } override string getARelevantChar() { @@ -445,7 +451,9 @@ private module CharacterClasses { result = " " or charClass = "w" and - result = ["a", "Z", "_", "0", "9"] + if RegExpFlags::isIgnoreCase(cc.getRootTerm()) + then result = ["a", "z", "_", "0", "9"] + else result = ["a", "Z", "_", "0", "9"] } override predicate matches(string char) { classEscapeMatches(charClass, char) } @@ -492,6 +500,34 @@ private module CharacterClasses { not classEscapeMatches(charClass.toLowerCase(), char) } } + + /** Gets a representative for all char classes that match the same chars as `c`. */ + CharacterClass normalize(CharacterClass c) { + exists(string normalization | + normalization = getMormalizationString(c) and + result = + min(CharacterClass cc, string raw | + getMormalizationString(cc) = normalization and cc = CharClass(raw) + | + cc order by raw + ) + ) + } + + /** Gets a string representing all the chars matched by `c` */ + private string getMormalizationString(CharacterClass c) { + (c instanceof PositiveCharacterClass or c instanceof PositiveCharacterClassEscape) and + result = concat(string char | c.matches(char) and char = CharacterClasses::getARelevantChar()) + or + (c instanceof InvertedCharacterClass or c instanceof NegativeCharacterClassEscape) and + // the string produced by the concat can not contain repeated chars + // so by starting the below with "nn" we can guarantee that + // it will not overlap with the above case. + // and a negative char class can never match the same chars as a positive one, so we don't miss any results from this. + result = + "nn:" + + concat(string char | not c.matches(char) and char = CharacterClasses::getARelevantChar()) + } } private class EdgeLabel extends TInputSymbol { @@ -620,13 +656,17 @@ predicate delta(State q1, EdgeLabel lbl, State q2) { cc.isUniversalClass() and q1 = before(cc) and lbl = Any() and q2 = after(cc) or q1 = before(cc) and - lbl = CharClass(cc.getRawValue() + "|" + getCanonicalizationFlags(cc.getRootTerm())) and + lbl = + CharacterClasses::normalize(CharClass(cc.getRawValue() + "|" + + getCanonicalizationFlags(cc.getRootTerm()))) and q2 = after(cc) ) or exists(RegExpTerm cc | isEscapeClass(cc, _) | q1 = before(cc) and - lbl = CharClass(cc.getRawValue() + "|" + getCanonicalizationFlags(cc.getRootTerm())) and + lbl = + CharacterClasses::normalize(CharClass(cc.getRawValue() + "|" + + getCanonicalizationFlags(cc.getRootTerm()))) and q2 = after(cc) ) or diff --git a/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected b/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected index 96919f8717d..8aac110e9e0 100644 --- a/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected +++ b/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected @@ -1,5 +1,5 @@ -| highlight.js:2:26:2:979 | ((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firewall\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+ | Strings starting with '/' and with many repetitions of 'ip ' can start matching anywhere after the start of the preceeding (\\.\\.\\/\|\\/\|\\s)((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firewall\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+X | -| highlight.js:3:27:3:971 | ((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+ | Strings starting with '/' and with many repetitions of 'ip ' can start matching anywhere after the start of the preceeding (\\.\\.\\/\|\\/\|\\s)((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+X | +| highlight.js:2:26:2:979 | ((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firewall\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+ | Strings starting with '/' and with many repetitions of 'ip\\t' can start matching anywhere after the start of the preceeding (\\.\\.\\/\|\\/\|\\s)((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firewall\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+X | +| highlight.js:3:27:3:971 | ((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+ | Strings starting with '/' and with many repetitions of 'ip\\t' can start matching anywhere after the start of the preceeding (\\.\\.\\/\|\\/\|\\s)((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+X | | highlight.js:6:12:6:695 | (Add\|Clear\|Close\|Copy\|Enter\|Exit\|Find\|Format\|Get\|Hide\|Join\|Lock\|Move\|New\|Open\|Optimize\|Pop\|Push\|Redo\|Remove\|Rename\|Reset\|Resize\|Search\|Select\|Set\|Show\|Skip\|Split\|Step\|Switch\|Undo\|Unlock\|Watch\|Backup\|Checkpoint\|Compare\|Compress\|Convert\|ConvertFrom\|ConvertTo\|Dismount\|Edit\|Expand\|Export\|Group\|Import\|Initialize\|Limit\|Merge\|New\|Out\|Publish\|Restore\|Save\|Sync\|Unpublish\|Update\|Approve\|Assert\|Complete\|Confirm\|Deny\|Disable\|Enable\|Install\|Invoke\|Register\|Request\|Restart\|Resume\|Start\|Stop\|Submit\|Suspend\|Uninstall\|Unregister\|Wait\|Debug\|Measure\|Ping\|Repair\|Resolve\|Test\|Trace\|Connect\|Disconnect\|Read\|Receive\|Send\|Write\|Block\|Grant\|Protect\|Revoke\|Unblock\|Unprotect\|Use\|ForEach\|Sort\|Tee\|Where)+ | Strings with many repetitions of 'Add' can start matching anywhere after the start of the preceeding (Add\|Clear\|Close\|Copy\|Enter\|Exit\|Find\|Format\|Get\|Hide\|Join\|Lock\|Move\|New\|Open\|Optimize\|Pop\|Push\|Redo\|Remove\|Rename\|Reset\|Resize\|Search\|Select\|Set\|Show\|Skip\|Split\|Step\|Switch\|Undo\|Unlock\|Watch\|Backup\|Checkpoint\|Compare\|Compress\|Convert\|ConvertFrom\|ConvertTo\|Dismount\|Edit\|Expand\|Export\|Group\|Import\|Initialize\|Limit\|Merge\|New\|Out\|Publish\|Restore\|Save\|Sync\|Unpublish\|Update\|Approve\|Assert\|Complete\|Confirm\|Deny\|Disable\|Enable\|Install\|Invoke\|Register\|Request\|Restart\|Resume\|Start\|Stop\|Submit\|Suspend\|Uninstall\|Unregister\|Wait\|Debug\|Measure\|Ping\|Repair\|Resolve\|Test\|Trace\|Connect\|Disconnect\|Read\|Receive\|Send\|Write\|Block\|Grant\|Protect\|Revoke\|Unblock\|Unprotect\|Use\|ForEach\|Sort\|Tee\|Where)+(-)[\\w\\d]+ | | highlight.js:7:13:7:692 | (Add\|Clear\|Close\|Copy\|Enter\|Exit\|Find\|Format\|Get\|Hide\|Join\|Lock\|Move\|New\|Open\|Optimize\|Pop\|Push\|Redo\|Remove\|Rename\|Reset\|Resize\|Search\|Select\|Set\|Show\|Skip\|Split\|Step\|Switch\|Undo\|Unlock\|Watch\|Backup\|Checkpoint\|Compare\|Compress\|Convert\|ConvertFrom\|ConvertTo\|Dismount\|Edit\|Expand\|Export\|Group\|Import\|Initialize\|Limit\|Merge\|Out\|Publish\|Restore\|Save\|Sync\|Unpublish\|Update\|Approve\|Assert\|Complete\|Confirm\|Deny\|Disable\|Enable\|Install\|Invoke\|Register\|Request\|Restart\|Resume\|Start\|Stop\|Submit\|Suspend\|Uninstall\|Unregister\|Wait\|Debug\|Measure\|Ping\|Repair\|Resolve\|Test\|Trace\|Connect\|Disconnect\|Read\|Receive\|Send\|Write\|Block\|Grant\|Protect\|Revoke\|Unblock\|Unprotect\|Use\|ForEach\|Sort\|Tee\|Where)+ | Strings with many repetitions of 'Add' can start matching anywhere after the start of the preceeding (Add\|Clear\|Close\|Copy\|Enter\|Exit\|Find\|Format\|Get\|Hide\|Join\|Lock\|Move\|New\|Open\|Optimize\|Pop\|Push\|Redo\|Remove\|Rename\|Reset\|Resize\|Search\|Select\|Set\|Show\|Skip\|Split\|Step\|Switch\|Undo\|Unlock\|Watch\|Backup\|Checkpoint\|Compare\|Compress\|Convert\|ConvertFrom\|ConvertTo\|Dismount\|Edit\|Expand\|Export\|Group\|Import\|Initialize\|Limit\|Merge\|Out\|Publish\|Restore\|Save\|Sync\|Unpublish\|Update\|Approve\|Assert\|Complete\|Confirm\|Deny\|Disable\|Enable\|Install\|Invoke\|Register\|Request\|Restart\|Resume\|Start\|Stop\|Submit\|Suspend\|Uninstall\|Unregister\|Wait\|Debug\|Measure\|Ping\|Repair\|Resolve\|Test\|Trace\|Connect\|Disconnect\|Read\|Receive\|Send\|Write\|Block\|Grant\|Protect\|Revoke\|Unblock\|Unprotect\|Use\|ForEach\|Sort\|Tee\|Where)+(-)[\\w\\d]+ | | highlight.js:14:17:14:52 | [a-z0-9&#*=?@\\\\><:,()$[\\]_.{}!+%^-]+ | Strings with many repetitions of '!' can start matching anywhere after the start of the preceeding ([ ]*[a-z0-9&#*=?@\\\\><:,()$[\\]_.{}!+%^-]+)+ | @@ -39,20 +39,20 @@ | lib/snapdragon.js:23:22:23:23 | a* | Strings starting with 'a' and with many repetitions of 'a' can start matching anywhere after the start of the preceeding aa*$ | | lib/subLib4/factory.js:8:3:8:4 | f* | Strings with many repetitions of 'f' can start matching anywhere after the start of the preceeding f*g | | lib/sublib/factory.js:13:14:13:15 | f* | Strings with many repetitions of 'f' can start matching anywhere after the start of the preceeding f*g | -| polynomial-redos.js:7:24:7:26 | \\s+ | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding \\s+$ | +| polynomial-redos.js:7:24:7:26 | \\s+ | Strings with many repetitions of '\\t' can start matching anywhere after the start of the preceeding \\s+$ | | polynomial-redos.js:8:17:8:18 | * | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding *, * | -| polynomial-redos.js:9:19:9:21 | \\s* | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding \\s*\\n\\s* | +| polynomial-redos.js:9:19:9:21 | \\s* | Strings with many repetitions of '\\t' can start matching anywhere after the start of the preceeding \\s*\\n\\s* | | polynomial-redos.js:11:19:11:20 | .* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding .*[/\\\\] | | polynomial-redos.js:12:19:12:20 | .* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding .*\\. | -| polynomial-redos.js:15:28:15:35 | [\\s\\S]*? | Strings starting with '`' and with many repetitions of ' ' can start matching anywhere after the start of the preceeding `+ | -| polynomial-redos.js:15:41:15:43 | \\s* | Strings starting with '`_' and with many repetitions of ' ' can start matching anywhere after the start of the preceeding \\s* | +| polynomial-redos.js:15:28:15:35 | [\\s\\S]*? | Strings starting with '`' and with many repetitions of '\\t' can start matching anywhere after the start of the preceeding `+ | +| polynomial-redos.js:15:41:15:43 | \\s* | Strings starting with '`_' and with many repetitions of '\\t' can start matching anywhere after the start of the preceeding \\s* | | polynomial-redos.js:16:25:16:32 | [\\s\\S]*? | Strings starting with '`' and with many repetitions of '``' can start matching anywhere after the start of the preceeding `+ | | polynomial-redos.js:17:5:17:6 | .* | Strings with many repetitions of ',' can start matching anywhere after the start of the preceeding (.*,)+ | | polynomial-redos.js:17:11:17:12 | .+ | Strings starting with ',' and with many repetitions of ',,' can start matching anywhere after the start of the preceeding .* | | polynomial-redos.js:18:83:18:100 | [\\u0600-\\u06FF\\/]+ | Strings with many repetitions of '/' can start matching anywhere after the start of the preceeding [\\u0600-\\u06FF\\/]+(\\s*?[\\u0600-\\u06FF]+){1,2} | | polynomial-redos.js:19:17:19:22 | [0-9]* | Strings with many repetitions of '0' can start matching anywhere after the start of the preceeding [0-9]*['a-z\\u00A0-\\u05FF\\u0700-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]{1,256} | -| polynomial-redos.js:20:56:20:58 | \\d+ | Strings with many repetitions of '9' can start matching anywhere after the start of the preceeding \\d* | -| polynomial-redos.js:22:57:22:59 | \\d+ | Strings with many repetitions of '9' can start matching anywhere after the start of the preceeding \\d* | +| polynomial-redos.js:20:56:20:58 | \\d+ | Strings with many repetitions of '0' can start matching anywhere after the start of the preceeding \\d* | +| polynomial-redos.js:22:57:22:59 | \\d+ | Strings with many repetitions of '0' can start matching anywhere after the start of the preceeding \\d* | | polynomial-redos.js:25:37:25:56 | [a-zA-Z0-9+\\/ \\t\\n]+ | Strings starting with '-\\t' and with many repetitions of '\\t\\t' can start matching anywhere after the start of the preceeding [ \\t]+ | | polynomial-redos.js:25:63:25:64 | .* | Strings starting with '-\\t\\t' and with many repetitions of '=' can start matching anywhere after the start of the preceeding [=]* | | polynomial-redos.js:30:19:30:22 | [?]+ | Strings with many repetitions of '?' can start matching anywhere after the start of the preceeding [?]+.*$ | @@ -68,7 +68,7 @@ | polynomial-redos.js:38:34:38:35 | .* | Strings starting with ' | | polynomial-redos.js:75:35:75:36 | .* | Strings starting with '([0-9]\|[ ]\|[-]\|[\\(]\|[\\)]\|ext.\|[,])+)([ ]\|[:]\|\\t\|[-])*(?Home\|Office\|Work\|Away\|Fax\|FAX\|Phone) | | regexplib/address.js:85:51:85:67 | ([ ]\|[:]\|\\t\|[-])* | Strings starting with '0' and with many repetitions of ' ' can start matching anywhere after the start of the preceeding ([0-9]\|[ ]\|[-]\|[\\(]\|[\\)]\|ext.\|[,])+ | -| regexplib/address.js:93:3:93:5 | \\s* | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding (\\s*\\(?0\\d{4}\\)?(\\s*\|-)\\d{3}(\\s*\|-)\\d{3}\\s*) | -| regexplib/address.js:93:48:93:50 | \\s* | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding (\\s*\\(?0\\d{3}\\)?(\\s*\|-)\\d{3}(\\s*\|-)\\d{4}\\s*) | -| regexplib/address.js:93:93:93:95 | \\s* | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding (\\s*(7\|8)(\\d{7}\|\\d{3}(\\-\|\\s{1})\\d{4})\\s*) | +| regexplib/address.js:93:3:93:5 | \\s* | Strings with many repetitions of '\\t' can start matching anywhere after the start of the preceeding (\\s*\\(?0\\d{4}\\)?(\\s*\|-)\\d{3}(\\s*\|-)\\d{3}\\s*) | +| regexplib/address.js:93:48:93:50 | \\s* | Strings with many repetitions of '\\t' can start matching anywhere after the start of the preceeding (\\s*\\(?0\\d{3}\\)?(\\s*\|-)\\d{3}(\\s*\|-)\\d{4}\\s*) | +| regexplib/address.js:93:93:93:95 | \\s* | Strings with many repetitions of '\\t' can start matching anywhere after the start of the preceeding (\\s*(7\|8)(\\d{7}\|\\d{3}(\\-\|\\s{1})\\d{4})\\s*) | | regexplib/address.js:95:379:95:755 | [a-zA-Z0-9ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïñòóôõöøùúûüýÿ\\.\\,\\-\\/\\' ]+ | Strings starting with '#' and with many repetitions of '#' can start matching anywhere after the start of the preceeding [a-zA-Z0-9ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïñòóôõöøùúûüýÿ\\.\\,\\-\\/\\']+ | | regexplib/address.js:99:19:99:24 | [0-9]* | Strings with many repetitions of '0' can start matching anywhere after the start of the preceeding [0-9]* | | regexplib/email.js:1:16:1:22 | [-.\\w]* | Strings starting with '0' and with many repetitions of '0' can start matching anywhere after the start of the preceeding ([-.\\w]*[0-9a-zA-Z])* | -| regexplib/email.js:2:5:2:12 | [-._\\w]* | Strings starting with 'a' and with many repetitions of '0' can start matching anywhere after the start of the preceeding (\\w[-._\\w]*\\w@\\w[-._\\w]*\\w\\.\\w{2,3}) | +| regexplib/email.js:2:5:2:12 | [-._\\w]* | Strings starting with '0' and with many repetitions of '0' can start matching anywhere after the start of the preceeding (\\w[-._\\w]*\\w@\\w[-._\\w]*\\w\\.\\w{2,3}) | | regexplib/email.js:5:24:5:35 | [a-zA-Z0-9]+ | Strings starting with '0' and with many repetitions of '0' can start matching anywhere after the start of the preceeding ([_\\.\\-]?[a-zA-Z0-9]+)* | | regexplib/email.js:5:63:5:74 | [a-zA-Z0-9]+ | Strings starting with '0@0' and with many repetitions of '0' can start matching anywhere after the start of the preceeding [A-Za-z0-9]+ | | regexplib/email.js:8:16:8:49 | [^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+ | Strings with many repetitions of '!' can start matching anywhere after the start of the preceeding (?(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\"))(?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\")))*)@(?(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\[(?:(?:[^\\[\\]\\\\\\r\\n])\|(?:\\\\.))*\\]))(?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\[(?:(?:[^\\[\\]\\\\\\r\\n])\|(?:\\\\.))*\\])))*) | @@ -163,20 +163,20 @@ | regexplib/email.js:8:89:8:174 | (?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\")))* | Strings starting with '!' and with many repetitions of '.!' can start matching anywhere after the start of the preceeding (?(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\"))(?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\")))*)@(?(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\[(?:(?:[^\\[\\]\\\\\\r\\n])\|(?:\\\\.))*\\]))(?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\[(?:(?:[^\\[\\]\\\\\\r\\n])\|(?:\\\\.))*\\])))*) | | regexplib/email.js:8:100:8:133 | [^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+ | Strings starting with '!.' and with many repetitions of '!.!' can start matching anywhere after the start of the preceeding (?(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\"))(?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\")))*)@(?(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\[(?:(?:[^\\[\\]\\\\\\r\\n])\|(?:\\\\.))*\\]))(?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\[(?:(?:[^\\[\\]\\\\\\r\\n])\|(?:\\\\.))*\\])))*) | | regexplib/email.js:8:141:8:168 | (?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))* | Strings starting with '!."' and with many repetitions of '".!."' can start matching anywhere after the start of the preceeding (?(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\"))(?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\")))*)@(?(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\[(?:(?:[^\\[\\]\\\\\\r\\n])\|(?:\\\\.))*\\]))(?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\[(?:(?:[^\\[\\]\\\\\\r\\n])\|(?:\\\\.))*\\])))*) | -| regexplib/email.js:12:2:12:4 | \\w+ | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding \\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*([,;]\\s*\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*)* | -| regexplib/email.js:12:5:12:15 | ([-+.]\\w+)* | Strings starting with 'a' and with many repetitions of '+a' can start matching anywhere after the start of the preceeding \\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*([,;]\\s*\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*)* | -| regexplib/email.js:12:11:12:13 | \\w+ | Strings starting with 'a+' and with many repetitions of 'a+' can start matching anywhere after the start of the preceeding \\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*([,;]\\s*\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*)* | +| regexplib/email.js:12:2:12:4 | \\w+ | Strings with many repetitions of '0' can start matching anywhere after the start of the preceeding \\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*([,;]\\s*\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*)* | +| regexplib/email.js:12:5:12:15 | ([-+.]\\w+)* | Strings starting with '0' and with many repetitions of '+0' can start matching anywhere after the start of the preceeding \\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*([,;]\\s*\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*)* | +| regexplib/email.js:12:11:12:13 | \\w+ | Strings starting with '0+' and with many repetitions of '0+' can start matching anywhere after the start of the preceeding \\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*([,;]\\s*\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*)* | | regexplib/email.js:13:47:13:49 | \\s+ | Strings starting with 'A' and with many repetitions of ' ' can start matching anywhere after the start of the preceeding [a-zA-Z]* | -| regexplib/email.js:15:6:15:13 | [\\w-\\.]* | Strings starting with 'a' and with many repetitions of '0' can start matching anywhere after the start of the preceeding \\w+ | -| regexplib/email.js:15:28:15:30 | \\w* | Strings starting with 'a@a' and with many repetitions of 'aa' can start matching anywhere after the start of the preceeding \\w+ | -| regexplib/email.js:20:3:20:6 | \\w+? | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (\\w+?@\\w+?\\x2E.+) | +| regexplib/email.js:15:6:15:13 | [\\w-\\.]* | Strings starting with '0' and with many repetitions of '0' can start matching anywhere after the start of the preceeding \\w+ | +| regexplib/email.js:15:28:15:30 | \\w* | Strings starting with '0@0' and with many repetitions of '00' can start matching anywhere after the start of the preceeding \\w+ | +| regexplib/email.js:20:3:20:6 | \\w+? | Strings with many repetitions of '0' can start matching anywhere after the start of the preceeding (\\w+?@\\w+?\\x2E.+) | | regexplib/email.js:25:67:25:78 | [a-zA-Z0-9]+ | Strings starting with '0' and with many repetitions of '0' can start matching anywhere after the start of the preceeding ([_\\.\\-]?[a-zA-Z0-9]+)* | | regexplib/email.js:25:106:25:117 | [a-zA-Z0-9]+ | Strings starting with '0@0' and with many repetitions of '0' can start matching anywhere after the start of the preceeding [A-Za-z0-9]+ | | regexplib/email.js:25:212:25:223 | [a-zA-Z0-9]+ | Strings with many repetitions of '0' can start matching anywhere after the start of the preceeding ([_\\.\\-]?[a-zA-Z0-9]+)* | | regexplib/email.js:25:251:25:262 | [a-zA-Z0-9]+ | Strings with many repetitions of '0' can start matching anywhere after the start of the preceeding [A-Za-z0-9]+ | -| regexplib/email.js:28:2:28:4 | \\w+ | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding \\w+[\\w-\\.]*\\@\\w+((-\\w+)\|(\\w*))\\.[a-z]{2,3}$ | -| regexplib/email.js:28:5:28:12 | [\\w-\\.]* | Strings starting with 'a' and with many repetitions of '0' can start matching anywhere after the start of the preceeding \\w+ | -| regexplib/email.js:28:27:28:29 | \\w* | Strings starting with 'a@a' and with many repetitions of 'aa' can start matching anywhere after the start of the preceeding \\w+ | +| regexplib/email.js:28:2:28:4 | \\w+ | Strings with many repetitions of '0' can start matching anywhere after the start of the preceeding \\w+[\\w-\\.]*\\@\\w+((-\\w+)\|(\\w*))\\.[a-z]{2,3}$ | +| regexplib/email.js:28:5:28:12 | [\\w-\\.]* | Strings starting with '0' and with many repetitions of '0' can start matching anywhere after the start of the preceeding \\w+ | +| regexplib/email.js:28:27:28:29 | \\w* | Strings starting with '0@0' and with many repetitions of '00' can start matching anywhere after the start of the preceeding \\w+ | | regexplib/email.js:28:73:28:87 | [0-9a-zA-Z'\\.]+ | Strings with many repetitions of ''' can start matching anywhere after the start of the preceeding ([0-9a-zA-Z'\\.]+)@([0-9a-zA-Z']+)\\.([0-9a-zA-Z']+)$ | | regexplib/email.js:28:125:28:139 | [0-9a-zA-Z'\\.]+ | Strings with many repetitions of ''' can start matching anywhere after the start of the preceeding ([0-9a-zA-Z'\\.]+)@([0-9a-zA-Z']+)\\*+$ | | regexplib/email.js:29:2:29:7 | [\\w-]+ | Strings with many repetitions of '-' can start matching anywhere after the start of the preceeding [\\w-]+@([\\w-]+\\.)+[\\w-]+ | @@ -191,11 +191,11 @@ | regexplib/markup.js:1:21:1:22 | .* | Strings starting with '<=' and with many repetitions of '==' can start matching anywhere after the start of the preceeding .* | | regexplib/markup.js:1:40:1:44 | [^<]* | Strings starting with '<=.jpg' and with many repetitions of ';' can start matching anywhere after the start of the preceeding .* | | regexplib/markup.js:2:3:2:7 | [^>]* | Strings starting with '<' and with many repetitions of '<' can start matching anywhere after the start of the preceeding <[^>]*> | -| regexplib/markup.js:3:440:3:456 | (\\s(?.+?))* | Strings starting with '.+?))* | +| regexplib/markup.js:3:440:3:456 | (\\s(?.+?))* | Strings starting with '.+?))* | | regexplib/markup.js:5:1525:5:1527 | \\s* | Strings starting with '?'DateLiteral' ?# Per the VB Spec : DateLiteral ::= '#' DateOrTime '#' # ?'DateOrTime' DateValue ?# TimeValue ::= HourValue : MinuteValue 10 ?# Hour 01 - 24 : 60 ?# Minute 01 - 60 : ?# Optional Minute :01 - :60 ' and with many repetitions of ' ' can start matching anywhere after the start of the preceeding \\s* | -| regexplib/markup.js:6:11:6:25 | [\\w\\*\\)\\(\\,\\s]+ | Strings starting with 'SELECT ' and with many repetitions of 'SELECT\\t' can start matching anywhere after the start of the preceeding (SELECT\\s[\\w\\*\\)\\(\\,\\s]+\\sFROM\\s[\\w]+) | -| regexplib/markup.js:6:99:6:113 | [\\s\\w\\d\\)\\(\\,]* | Strings starting with ' INSERT INTO 0' and with many repetitions of '0' can start matching anywhere after the start of the preceeding [\\d\\w]+ | +| regexplib/markup.js:6:11:6:25 | [\\w\\*\\)\\(\\,\\s]+ | Strings starting with 'SELECT\\t' and with many repetitions of 'SELECT\\t' can start matching anywhere after the start of the preceeding (SELECT\\s[\\w\\*\\)\\(\\,\\s]+\\sFROM\\s[\\w]+) | +| regexplib/markup.js:6:99:6:113 | [\\s\\w\\d\\)\\(\\,]* | Strings starting with ' INSERT\\tINTO\\t0' and with many repetitions of '0' can start matching anywhere after the start of the preceeding [\\d\\w]+ | | regexplib/markup.js:7:15:7:21 | [^\\\\"]* | Strings starting with '"!' and with many repetitions of '\\\\"!!' can start matching anywhere after the start of the preceeding "([^"](?:\\\\.\|[^\\\\"]*)*)" | | regexplib/markup.js:9:6:9:13 | [\\s\\S]*? | Strings starting with ' | @@ -209,44 +209,44 @@ | regexplib/markup.js:14:24:14:25 | .* | Strings starting with '<>' and with many repetitions of '>a' can start matching anywhere after the start of the preceeding .* | | regexplib/markup.js:15:16:15:18 | .*? | Strings starting with ' | | regexplib/markup.js:16:5:16:9 | [^>]* | Strings starting with 'src' and with many repetitions of 'src' can start matching anywhere after the start of the preceeding src[^>]*[^/].(?:jpg\|bmp\|gif)(?:\\"\|\\') | -| regexplib/markup.js:17:8:17:24 | (\\s(\\w*=".*?")?)* | Strings starting with '' and with many repetitions of '">' can start matching anywhere after the start of the preceeding .*? | -| regexplib/markup.js:19:2:19:12 | ([^'("\|')]*)("\|')){1}\|content\\s*=\\s*("\|')(?[^'("\|')]*)("\|')\|scheme\\s*=\\s*("\|')(?[^'("\|')]*)("\|')) | -| regexplib/markup.js:19:8:19:10 | \\s+ | Strings starting with '[^'("\|')]*)("\|')){1}\|content\\s*=\\s*("\|')(?[^'("\|')]*)("\|')\|scheme\\s*=\\s*("\|')(?[^'("\|')]*)("\|')) | +| regexplib/markup.js:17:8:17:24 | (\\s(\\w*=".*?")?)* | Strings starting with '<0' and with many repetitions of '\\t=""' can start matching anywhere after the start of the preceeding .*? | +| regexplib/markup.js:17:12:17:14 | \\w* | Strings starting with '<0\\t' and with many repetitions of '=""\\t0' can start matching anywhere after the start of the preceeding .*? | +| regexplib/markup.js:17:17:17:19 | .*? | Strings starting with '<0\\t="' and with many repetitions of '\\t=""' can start matching anywhere after the start of the preceeding \\w* | +| regexplib/markup.js:17:40:17:42 | .*? | Strings starting with '<0>' and with many repetitions of '">' can start matching anywhere after the start of the preceeding .*? | +| regexplib/markup.js:19:2:19:12 | ([^'("\|')]*)("\|')){1}\|content\\s*=\\s*("\|')(?[^'("\|')]*)("\|')\|scheme\\s*=\\s*("\|')(?[^'("\|')]*)("\|')) | +| regexplib/markup.js:19:8:19:10 | \\s+ | Strings starting with '[^'("\|')]*)("\|')){1}\|content\\s*=\\s*("\|')(?[^'("\|')]*)("\|')\|scheme\\s*=\\s*("\|')(?[^'("\|')]*)("\|')) | | regexplib/markup.js:20:52:20:53 | .* | Strings with many repetitions of '=color' can start matching anywhere after the start of the preceeding [^>]+ | | regexplib/markup.js:20:155:20:156 | '+ | Strings with many repetitions of '''' can start matching anywhere after the start of the preceeding '+ | | regexplib/markup.js:20:197:20:198 | "+ | Strings with many repetitions of '""' can start matching anywhere after the start of the preceeding "+ | | regexplib/markup.js:20:245:20:247 | .*? | Strings with many repetitions of 'color: # IF found THEN move ahead "" # single or double # or no quotes\\t' can start matching anywhere after the start of the preceeding .*? | | regexplib/markup.js:20:274:20:276 | .*? | Strings starting with ']+color.*>) #IF\\/THEN lookahead color in tag (.*?color\\s*?[=\|:]\\s*?) # IF found THEN move ahead ('+\\#*?[\\w\\s]*'+ # CAPTURE ColorName\\/Hex \|"+\\#*?[\\w\\s]*"+ # single or double \|\\#*\\w*\\b) # or no quotes\t.*?> # & move to end of tag \|.*?> # ELSE move to end of Tag ) # Close the If\\/Then lookahead # Use Multiline and IgnoreCase # Replace the matches from RE with MatchEvaluator below: # if m.Groups(1).Value<>"" then # Return "" # else # Return "" # end if | -| regexplib/markup.js:24:39:24:41 | \\s+ | Strings starting with '<A' and with many repetitions of ' - != ' can start matching anywhere after the start of the preceeding \\s* | -| regexplib/markup.js:24:43:24:45 | \\S+ | Strings starting with '<A ' and with many repetitions of '- !=' can start matching anywhere after the start of the preceeding \\s* | -| regexplib/markup.js:24:48:24:50 | \\s* | Strings starting with '<A !' and with many repetitions of ' =- ! ' can start matching anywhere after the start of the preceeding \\s+ | -| regexplib/markup.js:24:52:24:54 | \\s* | Strings starting with '<A !=' and with many repetitions of '- !=' can start matching anywhere after the start of the preceeding \\S+ | +| regexplib/markup.js:24:39:24:41 | \\s+ | Strings starting with '<A' and with many repetitions of '\\t-\\t!=\\t' can start matching anywhere after the start of the preceeding \\s* | +| regexplib/markup.js:24:43:24:45 | \\S+ | Strings starting with '<A\\t' and with many repetitions of '-\\t!=' can start matching anywhere after the start of the preceeding \\s* | +| regexplib/markup.js:24:48:24:50 | \\s* | Strings starting with '<A\\t!' and with many repetitions of '\\t=-\\t!\\t' can start matching anywhere after the start of the preceeding \\s+ | +| regexplib/markup.js:24:52:24:54 | \\s* | Strings starting with '<A\\t!=' and with many repetitions of '-\\t!=' can start matching anywhere after the start of the preceeding \\S+ | | regexplib/markup.js:25:11:25:15 | [^>]* | Strings starting with ']*\\son\\w+=(\\w+\|'[^']*'\|"[^"]*")[^>]*> | -| regexplib/markup.js:25:45:25:49 | [^>]* | Strings starting with ']* | Strings starting with ']* | Strings starting with '<' and with many repetitions of '<' can start matching anywhere after the start of the preceeding <[^>]*name[\\s]*=[\\s]*"?[^\\w_]*"?[^>]*> | | regexplib/markup.js:27:34:27:38 | [^>]* | Strings starting with ']* | Strings starting with '<' and with many repetitions of ']*)(\\s[^<]*)> | -| regexplib/markup.js:37:15:37:19 | [\\w]* | Strings starting with '[a' and with many repetitions of '0' can start matching anywhere after the start of the preceeding \\w+ | -| regexplib/markup.js:40:23:40:25 | \\w+ | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (\\/?(?\\w+))+ | -| regexplib/markup.js:40:59:40:61 | \\s* | Strings starting with 'a[' and with many repetitions of ' ' can start matching anywhere after the start of the preceeding \\s* | +| regexplib/markup.js:37:15:37:19 | [\\w]* | Strings starting with '[0' and with many repetitions of '0' can start matching anywhere after the start of the preceeding \\w+ | +| regexplib/markup.js:40:23:40:25 | \\w+ | Strings with many repetitions of '0' can start matching anywhere after the start of the preceeding (\\/?(?\\w+))+ | +| regexplib/markup.js:40:59:40:61 | \\s* | Strings starting with '0[' and with many repetitions of '\\t' can start matching anywhere after the start of the preceeding \\s* | | regexplib/markup.js:43:11:43:15 | [^>]* | Strings starting with ']*\\son\\w+=(\\w+\|'[^']*'\|"[^"]*")[^>]*> | -| regexplib/markup.js:43:45:43:49 | [^>]* | Strings starting with ']* | Strings starting with ']* | Strings starting with '<' and with many repetitions of '<' can start matching anywhere after the start of the preceeding <[^>]*name[\\s]*=[\\s]*"?[^\\w_]*"?[^>]*> | | regexplib/markup.js:44:34:44:38 | [^>]* | Strings starting with ' | -| regexplib/markup.js:53:15:53:19 | [\\w]* | Strings starting with '[a' and with many repetitions of '0' can start matching anywhere after the start of the preceeding \\w+ | -| regexplib/markup.js:56:23:56:25 | \\w+ | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (\\/?(?\\w+))+ | -| regexplib/markup.js:56:59:56:61 | \\s* | Strings starting with 'a[' and with many repetitions of ' ' can start matching anywhere after the start of the preceeding \\s* | +| regexplib/markup.js:53:15:53:19 | [\\w]* | Strings starting with '[0' and with many repetitions of '0' can start matching anywhere after the start of the preceeding \\w+ | +| regexplib/markup.js:56:23:56:25 | \\w+ | Strings with many repetitions of '0' can start matching anywhere after the start of the preceeding (\\/?(?\\w+))+ | +| regexplib/markup.js:56:59:56:61 | \\s* | Strings starting with '0[' and with many repetitions of '\\t' can start matching anywhere after the start of the preceeding \\s* | | regexplib/markup.js:61:74:61:79 | [0-9]+ | Strings starting with '.+)(\\.)(?[^\\.]*)(\\()(?[^\\)]*)(\\))((\\sin\\s)(?.+)(:line )(?[\\d]*))? | -| regexplib/misc.js:95:71:95:76 | [^\\)]* | Strings starting with 'at a.(' and with many repetitions of '((' can start matching anywhere after the start of the preceeding .+ | -| regexplib/misc.js:95:103:95:104 | .+ | Strings starting with 'at a.() in ' and with many repetitions of '() in -' can start matching anywhere after the start of the preceeding .+ | +| regexplib/misc.js:95:25:95:26 | .+ | Strings starting with 'at\\t' and with many repetitions of 'at\\ta' can start matching anywhere after the start of the preceeding (at\\s)(?.+)(\\.)(?[^\\.]*)(\\()(?[^\\)]*)(\\))((\\sin\\s)(?.+)(:line )(?[\\d]*))? | +| regexplib/misc.js:95:71:95:76 | [^\\)]* | Strings starting with 'at\\ta.(' and with many repetitions of '((' can start matching anywhere after the start of the preceeding .+ | +| regexplib/misc.js:95:103:95:104 | .+ | Strings starting with 'at\\ta.()\\tin\\t' and with many repetitions of '()\\tin\\t-' can start matching anywhere after the start of the preceeding .+ | | regexplib/misc.js:101:52:101:70 | [a-z0-9\\/\\.\\?\\=\\&]* | Strings starting with '".htm' and with many repetitions of '.asp' can start matching anywhere after the start of the preceeding [a-z0-9\\/\\.\\?\\=\\&]* | -| regexplib/misc.js:112:3:112:5 | \\s* | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding (\\s*\\(?0\\d{4}\\)?\\s*\\d{6}\\s*) | -| regexplib/misc.js:112:32:112:34 | \\s* | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding (\\s*\\(?0\\d{3}\\)?\\s*\\d{3}\\s*\\d{4}\\s*) | +| regexplib/misc.js:112:3:112:5 | \\s* | Strings with many repetitions of '\\t' can start matching anywhere after the start of the preceeding (\\s*\\(?0\\d{4}\\)?\\s*\\d{6}\\s*) | +| regexplib/misc.js:112:32:112:34 | \\s* | Strings with many repetitions of '\\t' can start matching anywhere after the start of the preceeding (\\s*\\(?0\\d{3}\\)?\\s*\\d{3}\\s*\\d{4}\\s*) | | regexplib/misc.js:114:6:114:8 | \\\|+ | Strings starting with 'a' and with many repetitions of '\|' can start matching anywhere after the start of the preceeding .+ | | regexplib/misc.js:116:3:116:4 | .* | Strings starting with '{' and with many repetitions of '{' can start matching anywhere after the start of the preceeding {.*} | | regexplib/misc.js:117:25:117:26 | .+ | Strings starting with '{a}' and with many repetitions of 'a)' can start matching anywhere after the start of the preceeding .+ | -| regexplib/misc.js:119:20:119:22 | \\w+ | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (NOT)?(\\s*\\(*)\\s*(\\w+)\\s*(=\|<>\|<\|>\|LIKE\|IN)\\s*(\\(([^\\)]*)\\)\|'([^']*)'\|(-?\\d*\\.?\\d+))(\\s*\\)*\\s*)(AND\|OR)? | +| regexplib/misc.js:119:20:119:22 | \\w+ | Strings with many repetitions of '0' can start matching anywhere after the start of the preceeding (NOT)?(\\s*\\(*)\\s*(\\w+)\\s*(=\|<>\|<\|>\|LIKE\|IN)\\s*(\\(([^\\)]*)\\)\|'([^']*)'\|(-?\\d*\\.?\\d+))(\\s*\\)*\\s*)(AND\|OR)? | +| regexplib/misc.js:119:52:119:57 | [^\\)]* | Strings starting with '0=(' and with many repetitions of '0<((' can start matching anywhere after the start of the preceeding (NOT)?(\\s*\\(*)\\s*(\\w+)\\s*(=\|<>\|<\|>\|LIKE\|IN)\\s*(\\(([^\\)]*)\\)\|'([^']*)'\|(-?\\d*\\.?\\d+))(\\s*\\)*\\s*)(AND\|OR)? | | regexplib/misc.js:123:36:123:38 | .*? | Strings starting with '?se[A' and with many repetitions of '?se[Aa' can start matching anywhere after the start of the preceeding (?s)(?:\\e\\[(?:(\\d+);?)*([A-Za-z])(.*?))(?=\\e\\[\|\\z) | | regexplib/misc.js:126:15:126:20 | [a-z]+ | Strings starting with 'a' and with many repetitions of 'aa' can start matching anywhere after the start of the preceeding [a-z]+ | | regexplib/misc.js:141:15:141:19 | [^;]+ | Strings starting with '{\\\\f\\\\' and with many repetitions of '{\\\\f\\\\:' can start matching anywhere after the start of the preceeding (\\{\\\\f\\d*)\\\\([^;]+;) | | regexplib/misc.js:144:52:144:70 | [a-z0-9\\/\\.\\?\\=\\&]* | Strings starting with '".htm' and with many repetitions of '.asp' can start matching anywhere after the start of the preceeding [a-z0-9\\/\\.\\?\\=\\&]* | | regexplib/misc.js:148:12:148:18 | [^\\s>]+ | Strings starting with '<' and with many repetitions of ']+(\\s+[^"'=]+(=("[^"]*")\|('[^\\']*')\|([^\\s"'>]*))?)*\\s*\\/?> | -| regexplib/misc.js:148:20:148:22 | \\s+ | Strings starting with ']+(\\s+[^"'=]+(=("[^"]*")\|('[^\\']*')\|([^\\s"'>]*))?)*\\s*\\/?> | -| regexplib/misc.js:148:44:148:49 | [^\\']* | Strings starting with ']+(\\s+[^"'=]+(=("[^"]*")\|('[^\\']*')\|([^\\s"'>]*))?)*\\s*\\/?> | -| regexplib/misc.js:148:68:148:70 | \\s* | Strings starting with ']+(\\s+[^"'=]+(=("[^"]*")\|('[^\\']*')\|([^\\s"'>]*))?)*\\s*\\/?> | +| regexplib/misc.js:148:44:148:49 | [^\\']* | Strings starting with ']+(\\s+[^"'=]+(=("[^"]*")\|('[^\\']*')\|([^\\s"'>]*))?)*\\s*\\/?> | +| regexplib/misc.js:148:68:148:70 | \\s* | Strings starting with '\|<\|>\|LIKE\|IN)\\s*(\\(([^\\)]*)\\)\|'([^']*)'\|(-?\\d*\\.?\\d+))(\\s*\\)*\\s*)(AND\|OR)? | +| regexplib/strings.js:54:20:54:22 | \\w+ | Strings with many repetitions of '0' can start matching anywhere after the start of the preceeding (NOT)?(\\s*\\(*)\\s*(\\w+)\\s*(=\|<>\|<\|>\|LIKE\|IN)\\s*(\\(([^\\)]*)\\)\|'([^']*)'\|(-?\\d*\\.?\\d+))(\\s*\\)*\\s*)(AND\|OR)? | +| regexplib/strings.js:54:52:54:57 | [^\\)]* | Strings starting with '0=(' and with many repetitions of '0<((' can start matching anywhere after the start of the preceeding (NOT)?(\\s*\\(*)\\s*(\\w+)\\s*(=\|<>\|<\|>\|LIKE\|IN)\\s*(\\(([^\\)]*)\\)\|'([^']*)'\|(-?\\d*\\.?\\d+))(\\s*\\)*\\s*)(AND\|OR)? | | regexplib/strings.js:56:52:56:53 | .+ | Strings starting with 'PRN.' and with many repetitions of '.' can start matching anywhere after the start of the preceeding .* | | regexplib/strings.js:57:36:57:38 | .*? | Strings starting with '?se[A' and with many repetitions of '?se[Aa' can start matching anywhere after the start of the preceeding (?s)(?:\\e\\[(?:(\\d+);?)*([A-Za-z])(.*?))(?=\\e\\[\|\\z) | -| regexplib/strings.js:64:3:64:5 | \\w+ | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (\\w+)\\s+\\1 | +| regexplib/strings.js:64:3:64:5 | \\w+ | Strings with many repetitions of '0' can start matching anywhere after the start of the preceeding (\\w+)\\s+\\1 | | regexplib/strings.js:70:6:70:17 | [a-zA-Z,\\s]+ | Strings with many repetitions of '\\t' can start matching anywhere after the start of the preceeding \\s* | | regexplib/strings.js:70:18:70:20 | \\s* | Strings starting with '\\t' and with many repetitions of '\\t' can start matching anywhere after the start of the preceeding \\s* | -| regexplib/strings.js:72:35:72:37 | \\w* | Strings starting with 'A' and with many repetitions of 'A' can start matching anywhere after the start of the preceeding \\w* | +| regexplib/strings.js:72:35:72:37 | \\w* | Strings starting with 'A' and with many repetitions of '0' can start matching anywhere after the start of the preceeding \\w* | | regexplib/strings.js:72:61:72:63 | \\w+ | Strings starting with 'AA' and with many repetitions of 'A' can start matching anywhere after the start of the preceeding \\w* | -| regexplib/strings.js:72:119:72:121 | \\w* | Strings with many repetitions of 'aA' can start matching anywhere after the start of the preceeding \\w+ | +| regexplib/strings.js:72:119:72:121 | \\w* | Strings with many repetitions of '00' can start matching anywhere after the start of the preceeding \\w+ | | regexplib/strings.js:73:2:73:3 | .* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding .*\\$AVE | | regexplib/strings.js:74:2:74:3 | .* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding .*[Pp]re[Ss\\$]cr[iI1]pt.* | | regexplib/strings.js:75:2:75:3 | .* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding .*[Vv][Ii1]agr.* | | regexplib/strings.js:76:2:76:3 | .* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding .*[Oo0][Ee][Mm].* | | regexplib/strings.js:81:36:81:38 | .*? | Strings starting with '?se[A' and with many repetitions of '?se[Aa' can start matching anywhere after the start of the preceeding (?s)(?:\\e\\[(?:(\\d+);?)*([A-Za-z])(.*?))(?=\\e\\[\|\\z) | -| regexplib/strings.js:82:20:82:22 | \\w+ | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (NOT)?(\\s*\\(*)\\s*(\\w+)\\s*(=\|<>\|<\|>\|LIKE\|IN)\\s*(\\(([^\\)]*)\\)\|'([^']*)'\|(-?\\d*\\.?\\d+))(\\s*\\)*\\s*)(AND\|OR)? | +| regexplib/strings.js:82:20:82:22 | \\w+ | Strings with many repetitions of '0' can start matching anywhere after the start of the preceeding (NOT)?(\\s*\\(*)\\s*(\\w+)\\s*(=\|<>\|<\|>\|LIKE\|IN)\\s*(\\(([^\\)]*)\\)\|'([^']*)'\|(-?\\d*\\.?\\d+))(\\s*\\)*\\s*)(AND\|OR)? | +| regexplib/strings.js:82:52:82:57 | [^\\)]* | Strings starting with '0=(' and with many repetitions of '0<((' can start matching anywhere after the start of the preceeding (NOT)?(\\s*\\(*)\\s*(\\w+)\\s*(=\|<>\|<\|>\|LIKE\|IN)\\s*(\\(([^\\)]*)\\)\|'([^']*)'\|(-?\\d*\\.?\\d+))(\\s*\\)*\\s*)(AND\|OR)? | | regexplib/strings.js:88:3:88:12 | [^\\.\\?\\!]* | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding ([^\\.\\?\\!]*)[\\.\\?\\!] | | regexplib/strings.js:89:3:89:5 | \\S+ | Strings with many repetitions of '!' can start matching anywhere after the start of the preceeding (\\S+)\\x20{2,}(?=\\S+) | | regexplib/uri.js:3:149:3:151 | .*? | Strings starting with 'ftp:// ' and with many repetitions of '/ /' can start matching anywhere after the start of the preceeding .* | | regexplib/uri.js:3:188:3:190 | \\w+ | Strings starting with 'ftp:// ' and with many repetitions of '00' can start matching anywhere after the start of the preceeding .* | -| regexplib/uri.js:3:193:3:198 | [^\\#]+ | Strings starting with 'ftp:// a=' and with many repetitions of '00=' can start matching anywhere after the start of the preceeding .* | -| regexplib/uri.js:3:206:3:208 | \\w+ | Strings starting with 'ftp:// a="' and with many repetitions of '00' can start matching anywhere after the start of the preceeding .* | -| regexplib/uri.js:3:211:3:213 | \\w+ | Strings starting with 'ftp:// a="a=' and with many repetitions of '00=' can start matching anywhere after the start of the preceeding .* | -| regexplib/uri.js:5:42:5:43 | .* | Strings starting with 'A:\\\\a' and with many repetitions of ' ' can start matching anywhere after the start of the preceeding [\\w ]* | +| regexplib/uri.js:3:193:3:198 | [^\\#]+ | Strings starting with 'ftp:// 0=' and with many repetitions of '00=' can start matching anywhere after the start of the preceeding .* | +| regexplib/uri.js:3:206:3:208 | \\w+ | Strings starting with 'ftp:// 0="' and with many repetitions of '00' can start matching anywhere after the start of the preceeding .* | +| regexplib/uri.js:3:211:3:213 | \\w+ | Strings starting with 'ftp:// 0="0=' and with many repetitions of '00=' can start matching anywhere after the start of the preceeding .* | +| regexplib/uri.js:5:42:5:43 | .* | Strings starting with 'A:\\\\0' and with many repetitions of ' ' can start matching anywhere after the start of the preceeding [\\w ]* | | regexplib/uri.js:14:175:14:213 | [\\d\\w\\.\\/\\%\\+\\-\\=\\&\\?\\:\\\\\\"\\'\\,\\\|\\~\\;]* | Strings with many repetitions of '.ac+' can start matching anywhere after the start of the preceeding [\\d\\w\\.\\/\\+\\-\\?\\:]* | -| regexplib/uri.js:17:42:17:43 | .* | Strings starting with 'A:\\\\a' and with many repetitions of ' ' can start matching anywhere after the start of the preceeding [\\w ]* | +| regexplib/uri.js:17:42:17:43 | .* | Strings starting with 'A:\\\\0' and with many repetitions of ' ' can start matching anywhere after the start of the preceeding [\\w ]* | | regexplib/uri.js:18:4:18:46 | ([A-Za-z0-9'~`!@#$%&^_+=\\(\\){},\\-\\[\\]\\;])+? | Strings starting with 'A' and with many repetitions of 'A' can start matching anywhere after the start of the preceeding \\A([A-Za-z0-9'~`!@#$%&^_+=\\(\\){},\\-\\[\\]\\;])+?([ A-Za-z0-9'~` !@#$%&^_+=\\(\\){},\\-\\[\\];]\|([.]))*?(?(3)(([ A-Za-z0-9'~`!@#$ %&^_+=\\(\\){},\\-\\[\\]\\;]*?)([A-Za-z0-9'~`!@#$%&^_+=\\(\\){},\\-\\[ \\];])+\\z)\|(\\z)) | | regexplib/uri.js:18:47:18:96 | ([ A-Za-z0-9'~` !@#$%&^_+=\\(\\){},\\-\\[\\];]\|([.]))*? | Strings starting with 'A!' and with many repetitions of '!' can start matching anywhere after the start of the preceeding ([A-Za-z0-9'~`!@#$%&^_+=\\(\\){},\\-\\[\\]\\;])+? | | regexplib/uri.js:18:148:18:189 | ([A-Za-z0-9'~`!@#$%&^_+=\\(\\){},\\-\\[ \\];])+ | Strings starting with 'A!?3' and with many repetitions of ' ' can start matching anywhere after the start of the preceeding [ A-Za-z0-9'~`!@#$ %&^_+=\\(\\){},\\-\\[\\]\\;]*? | @@ -387,7 +390,7 @@ | regexplib/uri.js:38:20:38:28 | [a-z0-9]+ | Strings starting with 'a' and with many repetitions of '0' can start matching anywhere after the start of the preceeding [a-z]+ | | regexplib/uri.js:38:35:38:40 | [a-z]+ | Strings starting with 'a.' and with many repetitions of 'aa' can start matching anywhere after the start of the preceeding [a-z0-9]+ | | regexplib/uri.js:38:52:38:60 | [a-z0-9]+ | Strings starting with 'a.a' and with many repetitions of '0' can start matching anywhere after the start of the preceeding [a-z]+ | -| regexplib/uri.js:39:7:39:9 | .*? | Strings starting with 'a' can start matching anywhere after the start of the preceeding .*? | | regexplib/uri.js:41:16:41:31 | [a-zA-Z0-9\\-\\.]+ | Strings starting with '0' and with many repetitions of '00' can start matching anywhere after the start of the preceeding [a-zA-Z0-9]+ | | regexplib/uri.js:44:2:44:4 | .*? | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding .*?$(?a]+ | Strings with many repetitions of '=' can start matching anywhere after the start of the preceeding ([^>a]+)* | | tst.js:188:17:188:19 | \\s* | Strings starting with '\\n' and with many repetitions of '\\n' can start matching anywhere after the start of the preceeding (\\n\\s*)+$ | -| tst.js:191:18:191:20 | \\s+ | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding .* | +| tst.js:191:18:191:20 | \\s+ | Strings with many repetitions of '\\t' can start matching anywhere after the start of the preceeding .* | | tst.js:191:31:191:35 | [^)]* | Strings starting with '(?#' and with many repetitions of '(?#' can start matching anywhere after the start of the preceeding .* | | tst.js:194:53:194:61 | [a-zA-Z]+ | Strings starting with '{[A(A)' and with many repetitions of 'AA' can start matching anywhere after the start of the preceeding [ a-zA-Z{}]+ | | tst.js:194:68:194:79 | [ a-zA-Z{}]+ | Strings starting with '{[A(A)A:' and with many repetitions of ' A: ' can start matching anywhere after the start of the preceeding \\s* | @@ -475,23 +478,23 @@ | tst.js:227:15:227:22 | ([^X]b)+ | Strings with many repetitions of 'Wb' can start matching anywhere after the start of the preceeding (([^X]b)+)* | | tst.js:239:15:239:19 | (ab)+ | Strings with many repetitions of 'ab' can start matching anywhere after the start of the preceeding ((ab)+)* | | tst.js:248:18:248:19 | A* | Strings with many repetitions of 'A' can start matching anywhere after the start of the preceeding A* | -| tst.js:254:15:254:17 | \\w* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding \\d* | +| tst.js:254:15:254:17 | \\w* | Strings with many repetitions of '0' can start matching anywhere after the start of the preceeding \\d* | | tst.js:254:27:254:29 | \\w* | Strings starting with 'foobarbaz' and with many repetitions of 'foobarbaz' can start matching anywhere after the start of the preceeding \\d* | | tst.js:254:39:254:41 | \\w* | Strings starting with 'foobarbazfoobarbaz' and with many repetitions of 'foobarbaz' can start matching anywhere after the start of the preceeding \\d* | | tst.js:254:51:254:53 | \\w* | Strings starting with 'foobarbazfoobarbazfoobarbaz' and with many repetitions of 'foobarbaz' can start matching anywhere after the start of the preceeding \\d* | | tst.js:254:63:254:65 | \\s* | Strings starting with 'foobarbazfoobarbazfoobarbazfoobarbaz' and with many repetitions of 'foobarbazfoobarbazfoobarbazfoobarbazfoobarbazfoobarbaz' can start matching anywhere after the start of the preceeding \\d* | | tst.js:254:75:254:77 | \\d* | Strings starting with 'foobarbazfoobarbazfoobarbazfoobarbazfoobarbaz' and with many repetitions of 'foobarbazfoobarbazfoobarbazfoobarbazfoobarbazfoobarbaz' can start matching anywhere after the start of the preceeding \\s* | -| tst.js:257:14:257:116 | (.thisisagoddamnlongstringforstresstestingthequery\|\\sthisisagoddamnlongstringforstresstestingthequery)* | Strings with many repetitions of ' thisisagoddamnlongstringforstresstestingthequery' can start matching anywhere after the start of the preceeding (.thisisagoddamnlongstringforstresstestingthequery\|\\sthisisagoddamnlongstringforstresstestingthequery)*- | -| tst.js:260:14:260:77 | (thisisagoddamnlongstringforstresstestingthequery\|this\\w+query)* | Strings with many repetitions of 'thisaquery' can start matching anywhere after the start of the preceeding \\w+ | +| tst.js:257:14:257:116 | (.thisisagoddamnlongstringforstresstestingthequery\|\\sthisisagoddamnlongstringforstresstestingthequery)* | Strings with many repetitions of '\\tthisisagoddamnlongstringforstresstestingthequery' can start matching anywhere after the start of the preceeding (.thisisagoddamnlongstringforstresstestingthequery\|\\sthisisagoddamnlongstringforstresstestingthequery)*- | +| tst.js:260:14:260:77 | (thisisagoddamnlongstringforstresstestingthequery\|this\\w+query)* | Strings with many repetitions of 'this0query' can start matching anywhere after the start of the preceeding \\w+ | | tst.js:260:68:260:70 | \\w+ | Strings starting with 'this' and with many repetitions of 'this' can start matching anywhere after the start of the preceeding (thisisagoddamnlongstringforstresstestingthequery\|this\\w+query)* | | tst.js:263:15:263:117 | (thisisagoddamnlongstringforstresstestingthequery\|imanotherbutunrelatedstringcomparedtotheotherstring)* | Strings with many repetitions of 'thisisagoddamnlongstringforstresstestingthequery' can start matching anywhere after the start of the preceeding (thisisagoddamnlongstringforstresstestingthequery\|imanotherbutunrelatedstringcomparedtotheotherstring)*- | | tst.js:272:21:272:22 | b+ | Strings with many repetitions of 'b' can start matching anywhere after the start of the preceeding (b+)+ | -| tst.js:275:25:275:27 | \\s+ | Strings starting with '/) | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:38:2:38:8 | tainted | This $@ that depends on $@ may run slow on strings starting with '/) | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:75:2:75:8 | tainted | This $@ that depends on $@ may run slow on strings starting with '<' and with many repetitions of '<'. | polynomial-redos.js:75:18:75:19 | .* | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value | | polynomial-redos.js:75:2:75:39 | tainted ... )".*>/) | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:75:2:75:8 | tainted | This $@ that depends on $@ may run slow on strings starting with '\\. ])\|([^\\\\/:\\*\\?"\\\|<>]*[^\\\\/:\\*\\?"\\\|<>\\. ]))? | This part of the regular expression may cause exponential backtracking on strings starting with '!' and containing many repetitions of '!\\\\!'. | | regexplib/misc.js:24:56:24:118 | (([^\\\\/:\\*\\?"\\\|<>\\. ])\|([^\\\\/:\\*\\?"\\\|<>]*[^\\\\/:\\*\\?"\\\|<>\\. ]))? | This part of the regular expression may cause exponential backtracking on strings starting with '!' and containing many repetitions of '!\\\\!'. | | regexplib/misc.js:79:3:79:25 | (\\/w\|\\/W\|[^<>+?$%{}&])+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '/W'. | | regexplib/misc.js:90:4:90:11 | ([a-z])+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'aa'. | -| regexplib/misc.js:123:17:123:19 | \\d+ | This part of the regular expression may cause exponential backtracking on strings starting with '?se[' and containing many repetitions of '9'. | +| regexplib/misc.js:123:17:123:19 | \\d+ | This part of the regular expression may cause exponential backtracking on strings starting with '?se[' and containing many repetitions of '0'. | | regexplib/misc.js:142:3:142:25 | (\\/w\|\\/W\|[^<>+?$%{}&])+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '/W'. | -| regexplib/misc.js:148:20:148:22 | \\s+ | This part of the regular expression may cause exponential backtracking on strings starting with 'a]+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '='. | | tst.js:188:17:188:19 | \\s* | This part of the regular expression may cause exponential backtracking on strings starting with '\\n' and containing many repetitions of '\\n'. | -| tst.js:191:18:191:20 | \\s+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of ' '. | +| tst.js:191:18:191:20 | \\s+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '\\t'. | | tst.js:194:68:194:79 | [ a-zA-Z{}]+ | This part of the regular expression may cause exponential backtracking on strings starting with '{[A(A)A:' and containing many repetitions of ' A:'. | | tst.js:194:81:194:82 | ,? | This part of the regular expression may cause exponential backtracking on strings starting with '{[A(A)A: ' and containing many repetitions of ',A: '. | | tst.js:197:15:197:16 | a+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. | @@ -152,18 +152,18 @@ | tst.js:254:27:254:29 | \\w* | This part of the regular expression may cause exponential backtracking on strings starting with 'foobarbaz' and containing many repetitions of 'foobarbazfoobarbazfoobarbazfoobarbazfoobarbazfoobarbaz'. | | tst.js:254:39:254:41 | \\w* | This part of the regular expression may cause exponential backtracking on strings starting with 'foobarbazfoobarbaz' and containing many repetitions of 'foobarbazfoobarbazfoobarbazfoobarbazfoobarbazfoobarbaz'. | | tst.js:254:51:254:53 | \\w* | This part of the regular expression may cause exponential backtracking on strings starting with 'foobarbazfoobarbazfoobarbaz' and containing many repetitions of 'foobarbazfoobarbazfoobarbazfoobarbazfoobarbazfoobarbaz'. | -| tst.js:257:14:257:116 | (.thisisagoddamnlongstringforstresstestingthequery\|\\sthisisagoddamnlongstringforstresstestingthequery)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of ' thisisagoddamnlongstringforstresstestingthequery'. | +| tst.js:257:14:257:116 | (.thisisagoddamnlongstringforstresstestingthequery\|\\sthisisagoddamnlongstringforstresstestingthequery)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '\\tthisisagoddamnlongstringforstresstestingthequery'. | | tst.js:260:14:260:77 | (thisisagoddamnlongstringforstresstestingthequery\|this\\w+query)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'thisisagoddamnlongstringforstresstestingthequery'. | -| tst.js:260:68:260:70 | \\w+ | This part of the regular expression may cause exponential backtracking on strings starting with 'this' and containing many repetitions of 'aquerythis'. | +| tst.js:260:68:260:70 | \\w+ | This part of the regular expression may cause exponential backtracking on strings starting with 'this' and containing many repetitions of '0querythis'. | | tst.js:272:21:272:22 | b+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'b'. | -| tst.js:275:38:275:40 | \\s* | This part of the regular expression may cause exponential backtracking on strings starting with 'a]+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '='. | | redos.py:190:27:190:29 | \\s* | This part of the regular expression may cause exponential backtracking on strings starting with '\\n' and containing many repetitions of '\\n'. | -| redos.py:193:28:193:30 | \\s+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of ' '. | +| redos.py:193:28:193:30 | \\s+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '\\t'. | | redos.py:196:78:196:89 | [ a-zA-Z{}]+ | This part of the regular expression may cause exponential backtracking on strings starting with '{[A(A)A:' and containing many repetitions of ' A:'. | | redos.py:196:91:196:92 | ,? | This part of the regular expression may cause exponential backtracking on strings starting with '{[A(A)A: ' and containing many repetitions of ',A: '. | | redos.py:199:25:199:26 | a+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. | @@ -65,20 +65,20 @@ | redos.py:256:37:256:39 | \\w* | This part of the regular expression may cause exponential backtracking on strings starting with 'foobarbaz' and containing many repetitions of 'foobarbazfoobarbazfoobarbazfoobarbazfoobarbazfoobarbaz'. | | redos.py:256:49:256:51 | \\w* | This part of the regular expression may cause exponential backtracking on strings starting with 'foobarbazfoobarbaz' and containing many repetitions of 'foobarbazfoobarbazfoobarbazfoobarbazfoobarbazfoobarbaz'. | | redos.py:256:61:256:63 | \\w* | This part of the regular expression may cause exponential backtracking on strings starting with 'foobarbazfoobarbazfoobarbaz' and containing many repetitions of 'foobarbazfoobarbazfoobarbazfoobarbazfoobarbazfoobarbaz'. | -| redos.py:259:24:259:126 | (.thisisagoddamnlongstringforstresstestingthequery\|\\sthisisagoddamnlongstringforstresstestingthequery)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of ' thisisagoddamnlongstringforstresstestingthequery'. | +| redos.py:259:24:259:126 | (.thisisagoddamnlongstringforstresstestingthequery\|\\sthisisagoddamnlongstringforstresstestingthequery)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '\\tthisisagoddamnlongstringforstresstestingthequery'. | | redos.py:262:24:262:87 | (thisisagoddamnlongstringforstresstestingthequery\|this\\w+query)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'thisisagoddamnlongstringforstresstestingthequery'. | -| redos.py:262:78:262:80 | \\w+ | This part of the regular expression may cause exponential backtracking on strings starting with 'this' and containing many repetitions of 'aquerythis'. | +| redos.py:262:78:262:80 | \\w+ | This part of the regular expression may cause exponential backtracking on strings starting with 'this' and containing many repetitions of '0querythis'. | | redos.py:268:28:268:39 | ([\ufffd\ufffd]\|[\ufffd\ufffd])* | This part of the regular expression may cause exponential backtracking on strings starting with 'foo' and containing many repetitions of '\ufffd'. | | redos.py:271:28:271:41 | ((\ufffd\|\ufffd)\|(\ufffd\|\ufffd))* | This part of the regular expression may cause exponential backtracking on strings starting with 'foo' and containing many repetitions of '\ufffd'. | | redos.py:274:31:274:32 | b+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'b'. | -| redos.py:277:48:277:50 | \\s* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '"" a='. | +| redos.py:277:48:277:50 | \\s* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '""\\t0='. | | redos.py:283:26:283:27 | a+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. | | redos.py:286:26:286:27 | a+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. | | redos.py:292:26:292:27 | a+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. | | redos.py:295:35:295:36 | a+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. | | redos.py:301:100:301:101 | e+ | This part of the regular expression may cause exponential backtracking on strings starting with ';00000000000000' and containing many repetitions of 'e'. | | redos.py:304:28:304:29 | c+ | This part of the regular expression may cause exponential backtracking on strings starting with 'ab' and containing many repetitions of 'c'. | -| redos.py:307:28:307:30 | \\s+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of ' '. | +| redos.py:307:28:307:30 | \\s+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '\\t'. | | redos.py:310:26:310:34 | ([^/]\|X)+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'X'. | | redos.py:313:30:313:34 | [^Y]+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'Xx'. | | redos.py:316:25:316:26 | a* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. | diff --git a/ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll b/ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll index 35f8ffc0e65..58900594158 100644 --- a/ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll +++ b/ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll @@ -199,7 +199,7 @@ CharClass getCanonicalCharClass(RegExpTerm term) { /** * Holds if `a` and `b` are input symbols from the same regexp. */ -private predicate sharesRoot(TInputSymbol a, TInputSymbol b) { +private predicate sharesRoot(InputSymbol a, InputSymbol b) { exists(RegExpRoot root | belongsTo(a, root) and belongsTo(b, root) @@ -209,7 +209,7 @@ private predicate sharesRoot(TInputSymbol a, TInputSymbol b) { /** * Holds if the `a` is an input symbol from a regexp that has root `root`. */ -private predicate belongsTo(TInputSymbol a, RegExpRoot root) { +private predicate belongsTo(InputSymbol a, RegExpRoot root) { exists(State s | getRoot(s.getRepr()) = root | delta(s, a, _) or @@ -378,6 +378,13 @@ private module CharacterClasses { ) } + bindingset[char, cc] + private string caseNormalize(string char, RegExpTerm cc) { + if RegExpFlags::isIgnoreCase(cc.getRootTerm()) + then result = char.toLowerCase() + else result = char + } + /** * An implementation of `CharacterClass` for positive (non inverted) character classes. */ @@ -386,7 +393,7 @@ private module CharacterClasses { PositiveCharacterClass() { this = getCanonicalCharClass(cc) and not cc.isInverted() } - override string getARelevantChar() { result = getAMentionedChar(cc) } + override string getARelevantChar() { result = caseNormalize(getAMentionedChar(cc), cc) } override predicate matches(string char) { hasChildThatMatches(cc, char) } } @@ -400,8 +407,8 @@ private module CharacterClasses { InvertedCharacterClass() { this = getCanonicalCharClass(cc) and cc.isInverted() } override string getARelevantChar() { - result = nextChar(getAMentionedChar(cc)) or - nextChar(result) = getAMentionedChar(cc) + result = nextChar(caseNormalize(getAMentionedChar(cc), cc)) or + nextChar(result) = caseNormalize(getAMentionedChar(cc), cc) } bindingset[char] @@ -428,13 +435,12 @@ private module CharacterClasses { */ private class PositiveCharacterClassEscape extends CharacterClass { string charClass; + RegExpTerm cc; PositiveCharacterClassEscape() { - exists(RegExpTerm cc | - isEscapeClass(cc, charClass) and - this = getCanonicalCharClass(cc) and - charClass = ["d", "s", "w"] - ) + isEscapeClass(cc, charClass) and + this = getCanonicalCharClass(cc) and + charClass = ["d", "s", "w"] } override string getARelevantChar() { @@ -445,7 +451,9 @@ private module CharacterClasses { result = " " or charClass = "w" and - result = ["a", "Z", "_", "0", "9"] + if RegExpFlags::isIgnoreCase(cc.getRootTerm()) + then result = ["a", "z", "_", "0", "9"] + else result = ["a", "Z", "_", "0", "9"] } override predicate matches(string char) { classEscapeMatches(charClass, char) } @@ -492,6 +500,34 @@ private module CharacterClasses { not classEscapeMatches(charClass.toLowerCase(), char) } } + + /** Gets a representative for all char classes that match the same chars as `c`. */ + CharacterClass normalize(CharacterClass c) { + exists(string normalization | + normalization = getMormalizationString(c) and + result = + min(CharacterClass cc, string raw | + getMormalizationString(cc) = normalization and cc = CharClass(raw) + | + cc order by raw + ) + ) + } + + /** Gets a string representing all the chars matched by `c` */ + private string getMormalizationString(CharacterClass c) { + (c instanceof PositiveCharacterClass or c instanceof PositiveCharacterClassEscape) and + result = concat(string char | c.matches(char) and char = CharacterClasses::getARelevantChar()) + or + (c instanceof InvertedCharacterClass or c instanceof NegativeCharacterClassEscape) and + // the string produced by the concat can not contain repeated chars + // so by starting the below with "nn" we can guarantee that + // it will not overlap with the above case. + // and a negative char class can never match the same chars as a positive one, so we don't miss any results from this. + result = + "nn:" + + concat(string char | not c.matches(char) and char = CharacterClasses::getARelevantChar()) + } } private class EdgeLabel extends TInputSymbol { @@ -620,13 +656,17 @@ predicate delta(State q1, EdgeLabel lbl, State q2) { cc.isUniversalClass() and q1 = before(cc) and lbl = Any() and q2 = after(cc) or q1 = before(cc) and - lbl = CharClass(cc.getRawValue() + "|" + getCanonicalizationFlags(cc.getRootTerm())) and + lbl = + CharacterClasses::normalize(CharClass(cc.getRawValue() + "|" + + getCanonicalizationFlags(cc.getRootTerm()))) and q2 = after(cc) ) or exists(RegExpTerm cc | isEscapeClass(cc, _) | q1 = before(cc) and - lbl = CharClass(cc.getRawValue() + "|" + getCanonicalizationFlags(cc.getRootTerm())) and + lbl = + CharacterClasses::normalize(CharClass(cc.getRawValue() + "|" + + getCanonicalizationFlags(cc.getRootTerm()))) and q2 = after(cc) ) or diff --git a/ruby/ql/test/query-tests/security/cwe-1333-exponential-redos/ReDoS.expected b/ruby/ql/test/query-tests/security/cwe-1333-exponential-redos/ReDoS.expected index 198b362184c..11212e3d806 100644 --- a/ruby/ql/test/query-tests/security/cwe-1333-exponential-redos/ReDoS.expected +++ b/ruby/ql/test/query-tests/security/cwe-1333-exponential-redos/ReDoS.expected @@ -29,7 +29,7 @@ | tst.rb:125:11:125:24 | ([a-z]\|[d-h])* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'd'. | | tst.rb:128:11:128:26 | ([^a-z]\|[^0-9])* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '/'. | | tst.rb:131:11:131:21 | (\\d\|[0-9])* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '0'. | -| tst.rb:134:11:134:18 | (\\s\|\\s)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of ' '. | +| tst.rb:134:11:134:18 | (\\s\|\\s)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '\\t'. | | tst.rb:137:11:137:17 | (\\w\|G)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'G'. | | tst.rb:143:11:143:18 | (\\d\|\\w)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '0'. | | tst.rb:146:11:146:17 | (\\d\|5)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '5'. | @@ -44,7 +44,7 @@ | tst.rb:173:12:173:16 | [\\d]+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '0'. | | tst.rb:185:12:185:17 | [^>a]+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '='. | | tst.rb:188:13:188:15 | \\s* | This part of the regular expression may cause exponential backtracking on strings starting with '\\n' and containing many repetitions of '\\n'. | -| tst.rb:191:14:191:16 | \\s+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of ' '. | +| tst.rb:191:14:191:16 | \\s+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '\\t'. | | tst.rb:194:64:194:75 | [ a-zA-Z{}]+ | This part of the regular expression may cause exponential backtracking on strings starting with '{[A(A)A:' and containing many repetitions of ' A:'. | | tst.rb:194:77:194:78 | ,? | This part of the regular expression may cause exponential backtracking on strings starting with '{[A(A)A: ' and containing many repetitions of ',A: '. | | tst.rb:197:11:197:12 | a+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. | @@ -63,18 +63,18 @@ | tst.rb:254:23:254:25 | \\w* | This part of the regular expression may cause exponential backtracking on strings starting with 'foobarbaz' and containing many repetitions of 'foobarbazfoobarbazfoobarbazfoobarbazfoobarbazfoobarbaz'. | | tst.rb:254:35:254:37 | \\w* | This part of the regular expression may cause exponential backtracking on strings starting with 'foobarbazfoobarbaz' and containing many repetitions of 'foobarbazfoobarbazfoobarbazfoobarbazfoobarbazfoobarbaz'. | | tst.rb:254:47:254:49 | \\w* | This part of the regular expression may cause exponential backtracking on strings starting with 'foobarbazfoobarbazfoobarbaz' and containing many repetitions of 'foobarbazfoobarbazfoobarbazfoobarbazfoobarbazfoobarbaz'. | -| tst.rb:257:10:257:112 | (.thisisagoddamnlongstringforstresstestingthequery\|\\sthisisagoddamnlongstringforstresstestingthequery)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of ' thisisagoddamnlongstringforstresstestingthequery'. | +| tst.rb:257:10:257:112 | (.thisisagoddamnlongstringforstresstestingthequery\|\\sthisisagoddamnlongstringforstresstestingthequery)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '\\tthisisagoddamnlongstringforstresstestingthequery'. | | tst.rb:260:10:260:73 | (thisisagoddamnlongstringforstresstestingthequery\|this\\w+query)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'thisisagoddamnlongstringforstresstestingthequery'. | -| tst.rb:260:64:260:66 | \\w+ | This part of the regular expression may cause exponential backtracking on strings starting with 'this' and containing many repetitions of 'aquerythis'. | +| tst.rb:260:64:260:66 | \\w+ | This part of the regular expression may cause exponential backtracking on strings starting with 'this' and containing many repetitions of '0querythis'. | | tst.rb:272:17:272:18 | b+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'b'. | -| tst.rb:275:34:275:36 | \\s* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '"" a='. | +| tst.rb:275:34:275:36 | \\s* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '""\\t0='. | | tst.rb:281:12:281:13 | a+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. | | tst.rb:284:12:284:13 | a+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. | | tst.rb:290:12:290:13 | a+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. | | tst.rb:293:21:293:22 | a+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. | | tst.rb:299:86:299:87 | e+ | This part of the regular expression may cause exponential backtracking on strings starting with ';00000000000000' and containing many repetitions of 'e'. | | tst.rb:302:14:302:15 | c+ | This part of the regular expression may cause exponential backtracking on strings starting with 'ab' and containing many repetitions of 'c'. | -| tst.rb:305:14:305:16 | \\s+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of ' '. | +| tst.rb:305:14:305:16 | \\s+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '\\t'. | | tst.rb:308:12:308:21 | ([^\\/]\|X)+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'X'. | | tst.rb:311:16:311:20 | [^Y]+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'Xx'. | | tst.rb:314:11:314:12 | a* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. |