mirror of
https://github.com/github/codeql.git
synced 2026-04-27 17:55:19 +02:00
Swift: Copy MissingRegexAnchor query from JS.
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
|
||||
Sanitizing untrusted input with regular expressions is a
|
||||
common technique. However, it is error-prone to match untrusted input
|
||||
against regular expressions without anchors such as <code>^</code> or
|
||||
<code>$</code>. Malicious input can bypass such security checks by
|
||||
embedding one of the allowed patterns in an unexpected location.
|
||||
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
Even if the matching is not done in a security-critical
|
||||
context, it may still cause undesirable behavior when the regular
|
||||
expression accidentally matches.
|
||||
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
|
||||
Use anchors to ensure that regular expressions match at
|
||||
the expected locations.
|
||||
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
|
||||
<p>
|
||||
|
||||
The following example code checks that a URL redirection
|
||||
will reach the <code>example.com</code> domain, or one of its
|
||||
subdomains, and not some malicious site.
|
||||
|
||||
</p>
|
||||
|
||||
<sample src="examples/MissingRegExpAnchor_BAD.js"/>
|
||||
|
||||
<p>
|
||||
|
||||
The check with the regular expression match is, however, easy to bypass. For example
|
||||
by embedding <code>http://example.com/</code> in the query
|
||||
string component: <code>http://evil-example.net/?x=http://example.com/</code>.
|
||||
|
||||
Address these shortcomings by using anchors in the regular expression instead:
|
||||
|
||||
</p>
|
||||
|
||||
<sample src="examples/MissingRegExpAnchor_GOOD.js"/>
|
||||
|
||||
<p>
|
||||
|
||||
A related mistake is to write a regular expression with
|
||||
multiple alternatives, but to only include an anchor for one of the
|
||||
alternatives. As an example, the regular expression
|
||||
<code>/^www\.example\.com|beta\.example\.com/</code> will match the host
|
||||
<code>evil.beta.example.com</code> because the regular expression is parsed
|
||||
as <code>/(^www\.example\.com)|(beta\.example\.com)/</code>
|
||||
|
||||
</p>
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions">Regular Expressions</a></li>
|
||||
<li>OWASP: <a href="https://www.owasp.org/index.php/Server_Side_Request_Forgery">SSRF</a></li>
|
||||
<li>OWASP: <a href="https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html">XSS Unvalidated Redirects and Forwards Cheat Sheet</a>.</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
56
swift/ql/src/queries/Security/CWE-020/MissingRegexAnchor.ql
Normal file
56
swift/ql/src/queries/Security/CWE-020/MissingRegexAnchor.ql
Normal file
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @name Missing regular expression anchor
|
||||
* @description Regular expressions without anchors can be vulnerable to bypassing.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 7.8
|
||||
* @precision medium
|
||||
* @id js/regex/missing-regexp-anchor
|
||||
* @tags correctness
|
||||
* security
|
||||
* external/cwe/cwe-020
|
||||
*/
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.security.regexp.HostnameRegexp as HostnameRegexp
|
||||
private import codeql.regex.MissingRegExpAnchor as MissingRegExpAnchor
|
||||
private import semmle.javascript.security.regexp.RegExpTreeView::RegExpTreeView as TreeImpl
|
||||
|
||||
private module Impl implements
|
||||
MissingRegExpAnchor::MissingRegExpAnchorSig<TreeImpl, HostnameRegexp::Impl>
|
||||
{
|
||||
predicate isUsedAsReplace(RegExpPatternSource pattern) {
|
||||
// is used for capture or replace
|
||||
exists(DataFlow::MethodCallNode mcn, string name | name = mcn.getMethodName() |
|
||||
name = "exec" and
|
||||
mcn = pattern.getARegExpObject().getAMethodCall() and
|
||||
exists(mcn.getAPropertyRead())
|
||||
or
|
||||
exists(DataFlow::Node arg |
|
||||
arg = mcn.getArgument(0) and
|
||||
(
|
||||
pattern.getARegExpObject().flowsTo(arg) or
|
||||
pattern.getAParse() = arg
|
||||
)
|
||||
|
|
||||
name = "replace"
|
||||
or
|
||||
name = "match" and exists(mcn.getAPropertyRead())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
string getEndAnchorText() { result = "$" }
|
||||
}
|
||||
|
||||
import MissingRegExpAnchor::Make<TreeImpl, HostnameRegexp::Impl, Impl>
|
||||
|
||||
from DataFlow::Node nd, string msg
|
||||
where
|
||||
isUnanchoredHostnameRegExp(nd, msg)
|
||||
or
|
||||
isSemiAnchoredHostnameRegExp(nd, msg)
|
||||
or
|
||||
hasMisleadingAnchorPrecedence(nd, msg)
|
||||
// isLineAnchoredHostnameRegExp is not used here, as it is not relevant to JS.
|
||||
select nd, msg
|
||||
@@ -0,0 +1,7 @@
|
||||
app.get("/some/path", function(req, res) {
|
||||
let url = req.param("url");
|
||||
// BAD: the host of `url` may be controlled by an attacker
|
||||
if (url.match(/https?:\/\/www\.example\.com\//)) {
|
||||
res.redirect(url);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
app.get("/some/path", function(req, res) {
|
||||
let url = req.param("url");
|
||||
// GOOD: the host of `url` can not be controlled by an attacker
|
||||
if (url.match(/^https?:\/\/www\.example\.com\//)) {
|
||||
res.redirect(url);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
| tst-SemiAnchoredRegExp.js:3:2:3:7 | /^a\|b/ | Misleading operator precedence. The subexpression '^a' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:6:2:6:9 | /^a\|b\|c/ | Misleading operator precedence. The subexpression '^a' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:12:2:12:9 | /^a\|(b)/ | Misleading operator precedence. The subexpression '^a' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:14:2:14:11 | /^(a)\|(b)/ | Misleading operator precedence. The subexpression '^(a)' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:17:2:17:7 | /a\|b$/ | Misleading operator precedence. The subexpression 'b$' is anchored at the end, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:20:2:20:9 | /a\|b\|c$/ | Misleading operator precedence. The subexpression 'c$' is anchored at the end, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:26:2:26:9 | /(a)\|b$/ | Misleading operator precedence. The subexpression 'b$' is anchored at the end, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:28:2:28:11 | /(a)\|(b)$/ | Misleading operator precedence. The subexpression '(b)$' is anchored at the end, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:30:2:30:23 | /^good. ... er.com/ | Misleading operator precedence. The subexpression '^good.com' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:31:2:31:25 | /^good\\ ... r\\.com/ | Misleading operator precedence. The subexpression '^good\\.com' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:32:2:32:27 | /^good\\ ... \\\\.com/ | Misleading operator precedence. The subexpression '^good\\\\.com' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:33:2:33:29 | /^good\\ ... \\\\.com/ | Misleading operator precedence. The subexpression '^good\\\\\\.com' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:34:2:34:31 | /^good\\ ... \\\\.com/ | Misleading operator precedence. The subexpression '^good\\\\\\\\.com' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:36:2:36:16 | /^foo\|bar\|baz$/ | Misleading operator precedence. The subexpression '^foo' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:36:2:36:16 | /^foo\|bar\|baz$/ | Misleading operator precedence. The subexpression 'baz$' is anchored at the end, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:42:13:42:18 | "^a\|b" | Misleading operator precedence. The subexpression '^a' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:45:13:45:20 | "^a\|b\|c" | Misleading operator precedence. The subexpression '^a' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:51:13:51:20 | "^a\|(b)" | Misleading operator precedence. The subexpression '^a' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:53:13:53:22 | "^(a)\|(b)" | Misleading operator precedence. The subexpression '^(a)' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:56:13:56:18 | "a\|b$" | Misleading operator precedence. The subexpression 'b$' is anchored at the end, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:59:13:59:20 | "a\|b\|c$" | Misleading operator precedence. The subexpression 'c$' is anchored at the end, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:65:13:65:20 | "(a)\|b$" | Misleading operator precedence. The subexpression 'b$' is anchored at the end, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:67:13:67:22 | "(a)\|(b)$" | Misleading operator precedence. The subexpression '(b)$' is anchored at the end, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:69:13:69:34 | '^good. ... er.com' | Misleading operator precedence. The subexpression '^good.com' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:70:13:70:36 | '^good\\ ... r\\.com' | Misleading operator precedence. The subexpression '^good.com' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:71:13:71:38 | '^good\\ ... \\\\.com' | Misleading operator precedence. The subexpression '^good\\.com' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:72:13:72:40 | '^good\\ ... \\\\.com' | Misleading operator precedence. The subexpression '^good\\.com' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:73:13:73:42 | '^good\\ ... \\\\.com' | Misleading operator precedence. The subexpression '^good\\\\.com' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:82:2:82:27 | /(\\.xxx ... .zzz)$/ | Misleading operator precedence. The subexpression '(\\.zzz)$' is anchored at the end, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:84:2:84:23 | /\\.xxx\| ... zzz$/ig | Misleading operator precedence. The subexpression '\\.zzz$' is anchored at the end, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:85:2:85:19 | /\\.xxx\|\\.yyy\|zzz$/ | Misleading operator precedence. The subexpression 'zzz$' is anchored at the end, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:87:2:87:28 | /^(xxx ... yyy)/i | Misleading operator precedence. The subexpression '^(xxx yyy zzz)' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:88:2:88:53 | /^(xxx ... x\|1st/i | Misleading operator precedence. The subexpression '^(xxx yyy zzz)' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:89:2:89:24 | /^(xxx: ... (zzz:)/ | Misleading operator precedence. The subexpression '^(xxx:)' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:90:2:90:23 | /^(xxx? ... zzz\\/)/ | Misleading operator precedence. The subexpression '^(xxx?:)' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:91:2:91:16 | /^@media\|@page/ | Misleading operator precedence. The subexpression '^@media' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:92:2:92:32 | /^\\s*(x ... :yyy\\// | Misleading operator precedence. The subexpression '^\\s*(xxx?\|yyy\|zzz):' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:93:2:93:21 | /^click\|mouse\|touch/ | Misleading operator precedence. The subexpression '^click' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:94:2:94:43 | /^http: ... r\\.com/ | Misleading operator precedence. The subexpression '^http:\\/\\/good\\.com' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:95:2:95:47 | /^https ... r\\.com/ | Misleading operator precedence. The subexpression '^https?:\\/\\/good\\.com' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:96:2:96:55 | /^mouse ... ragend/ | Misleading operator precedence. The subexpression '^mouse' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:97:2:97:14 | /^xxx:\|yyy:/i | Misleading operator precedence. The subexpression '^xxx:' is anchored at the beginning, but the other parts of this regular expression are not |
|
||||
| tst-SemiAnchoredRegExp.js:98:2:98:18 | /_xxx\|_yyy\|_zzz$/ | Misleading operator precedence. The subexpression '_zzz$' is anchored at the end, but the other parts of this regular expression are not |
|
||||
| tst-UnanchoredUrlRegExp.js:3:47:3:65 | "https?://good.com" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |
|
||||
| tst-UnanchoredUrlRegExp.js:4:58:4:76 | "https?://good.com" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |
|
||||
| tst-UnanchoredUrlRegExp.js:5:47:5:66 | "^https?://good.com" | This hostname pattern may match any domain name, as it is missing a '$' or '/' at the end. |
|
||||
| tst-UnanchoredUrlRegExp.js:6:47:6:68 | /^https ... od.com/ | This hostname pattern may match any domain name, as it is missing a '$' or '/' at the end. |
|
||||
| tst-UnanchoredUrlRegExp.js:7:47:7:91 | "(^http ... 2.com)" | This hostname pattern may match any domain name, as it is missing a '$' or '/' at the end. |
|
||||
| tst-UnanchoredUrlRegExp.js:8:47:8:90 | "(https ... e.com)" | This hostname pattern may match any domain name, as it is missing a '$' or '/' at the end. |
|
||||
| tst-UnanchoredUrlRegExp.js:10:2:10:22 | /https? ... od.com/ | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |
|
||||
| tst-UnanchoredUrlRegExp.js:11:13:11:31 | "https?://good.com" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |
|
||||
| tst-UnanchoredUrlRegExp.js:13:48:13:66 | "https?://good.com" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |
|
||||
| tst-UnanchoredUrlRegExp.js:15:13:15:31 | "https?://good.com" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |
|
||||
| tst-UnanchoredUrlRegExp.js:19:47:19:65 | "https?://good.com" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |
|
||||
| tst-UnanchoredUrlRegExp.js:20:47:20:70 | "https? ... m:8080" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |
|
||||
| tst-UnanchoredUrlRegExp.js:23:3:23:21 | "https?://good.com" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |
|
||||
| tst-UnanchoredUrlRegExp.js:24:3:24:23 | /https? ... od.com/ | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |
|
||||
| tst-UnanchoredUrlRegExp.js:25:14:25:32 | "https?://good.com" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |
|
||||
| tst-UnanchoredUrlRegExp.js:26:3:26:22 | "^https?://good.com" | This hostname pattern may match any domain name, as it is missing a '$' or '/' at the end. |
|
||||
| tst-UnanchoredUrlRegExp.js:35:2:35:32 | /https? ... 0-9]+)/ | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |
|
||||
| tst-UnanchoredUrlRegExp.js:77:11:77:32 | /vimeo\\ ... 0-9]+)/ | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE-020/MissingRegExpAnchor.ql
|
||||
@@ -0,0 +1,133 @@
|
||||
(function coreRegExp() {
|
||||
/^a|/;
|
||||
/^a|b/; // NOT OK
|
||||
/a|^b/;
|
||||
/^a|^b/;
|
||||
/^a|b|c/; // NOT OK
|
||||
/a|^b|c/;
|
||||
/a|b|^c/;
|
||||
/^a|^b|c/;
|
||||
|
||||
/(^a)|b/;
|
||||
/^a|(b)/; // NOT OK
|
||||
/^a|(^b)/;
|
||||
/^(a)|(b)/; // NOT OK
|
||||
|
||||
|
||||
/a|b$/; // NOT OK
|
||||
/a$|b/;
|
||||
/a$|b$/;
|
||||
/a|b|c$/; // NOT OK
|
||||
/a|b$|c/;
|
||||
/a$|b|c/;
|
||||
/a|b$|c$/;
|
||||
|
||||
/a|(b$)/;
|
||||
/(a)|b$/; // NOT OK
|
||||
/(a$)|b$/;
|
||||
/(a)|(b)$/; // NOT OK
|
||||
|
||||
/^good.com|better.com/; // NOT OK
|
||||
/^good\.com|better\.com/; // NOT OK
|
||||
/^good\\.com|better\\.com/; // NOT OK
|
||||
/^good\\\.com|better\\\.com/; // NOT OK
|
||||
/^good\\\\.com|better\\\\.com/; // NOT OK
|
||||
|
||||
/^foo|bar|baz$/; // NOT OK
|
||||
/^foo|%/; // OK
|
||||
});
|
||||
|
||||
(function coreString() {
|
||||
new RegExp("^a|");
|
||||
new RegExp("^a|b"); // NOT OK
|
||||
new RegExp("a|^b");
|
||||
new RegExp("^a|^b");
|
||||
new RegExp("^a|b|c"); // NOT OK
|
||||
new RegExp("a|^b|c");
|
||||
new RegExp("a|b|^c");
|
||||
new RegExp("^a|^b|c");
|
||||
|
||||
new RegExp("(^a)|b");
|
||||
new RegExp("^a|(b)"); // NOT OK
|
||||
new RegExp("^a|(^b)");
|
||||
new RegExp("^(a)|(b)"); // NOT OK
|
||||
|
||||
|
||||
new RegExp("a|b$"); // NOT OK
|
||||
new RegExp("a$|b");
|
||||
new RegExp("a$|b$");
|
||||
new RegExp("a|b|c$"); // NOT OK
|
||||
new RegExp("a|b$|c");
|
||||
new RegExp("a$|b|c");
|
||||
new RegExp("a|b$|c$");
|
||||
|
||||
new RegExp("a|(b$)");
|
||||
new RegExp("(a)|b$"); // NOT OK
|
||||
new RegExp("(a$)|b$");
|
||||
new RegExp("(a)|(b)$"); // NOT OK
|
||||
|
||||
new RegExp('^good.com|better.com'); // NOT OK
|
||||
new RegExp('^good\.com|better\.com'); // NOT OK
|
||||
new RegExp('^good\\.com|better\\.com'); // NOT OK
|
||||
new RegExp('^good\\\.com|better\\\.com'); // NOT OK
|
||||
new RegExp('^good\\\\.com|better\\\\.com'); // NOT OK
|
||||
});
|
||||
|
||||
(function realWorld() {
|
||||
// real-world examples that have been anonymized a bit
|
||||
|
||||
/*
|
||||
* NOT OK: flagged
|
||||
*/
|
||||
/(\.xxx)|(\.yyy)|(\.zzz)$/;
|
||||
/(^left|right|center)\sbottom$/; // not flagged at the moment due to interior anchors
|
||||
/\.xxx|\.yyy|\.zzz$/ig;
|
||||
/\.xxx|\.yyy|zzz$/;
|
||||
/^([A-Z]|xxx[XY]$)/; // not flagged at the moment due to interior anchors
|
||||
/^(xxx yyy zzz)|(xxx yyy)/i;
|
||||
/^(xxx yyy zzz)|(xxx yyy)|(1st( xxx)? yyy)|xxx|1st/i;
|
||||
/^(xxx:)|(yyy:)|(zzz:)/;
|
||||
/^(xxx?:)|(yyy:zzz\/)/;
|
||||
/^@media|@page/;
|
||||
/^\s*(xxx?|yyy|zzz):|xxx:yyy\//;
|
||||
/^click|mouse|touch/;
|
||||
/^http:\/\/good\.com|http:\/\/better\.com/;
|
||||
/^https?:\/\/good\.com|https?:\/\/better\.com/;
|
||||
/^mouse|touch|click|contextmenu|drop|dragover|dragend/;
|
||||
/^xxx:|yyy:/i;
|
||||
/_xxx|_yyy|_zzz$/;
|
||||
/em|%$/; // not flagged at the moment due to the anchor not being for letters
|
||||
|
||||
/*
|
||||
* MAYBE OK due to apparent complexity: not flagged
|
||||
*/
|
||||
/(?:^[#?]?|&)([^=&]+)(?:=([^&]*))?/g;
|
||||
/(^\s*|;\s*)\*.*;/m;
|
||||
/(^\s*|\[)(?:xxx|yyy_(?:xxx|yyy)|xxx|yyy(?:xxx|yyy)?|xxx|yyy)\b/m;
|
||||
/\s\S| \t|\t |\s$/;
|
||||
/\{[^}{]*\{|\}[^}{]*\}|\{[^}]*$/g;
|
||||
/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/;
|
||||
/^(\/\/)|([a-z]+:(\/\/)?)/;
|
||||
/^[=?!#%@$]|!(?=[:}])/;
|
||||
/^[\[\]!:]|[<>]/;
|
||||
/^for\b|\b(?:xxx|yyy)\b/i;
|
||||
/^if\b|\b(?:xxx|yyy|zzz)\b/i;
|
||||
|
||||
/*
|
||||
* OK: not flagged
|
||||
*/
|
||||
/$^|only-match/g;
|
||||
/(#.+)|#$/;
|
||||
/(NaN| {2}|^$)/;
|
||||
/[^\n]*(?:\n|[^\n]$)/g;
|
||||
/^$|\/(?:xxx|yyy)zzz/i;
|
||||
/^(\/|(xxx|yyy|zzz)$)/;
|
||||
/^9$|27/;
|
||||
/^\+|\s*/g;
|
||||
/xxx_yyy=\w+|^$/;
|
||||
/^(?:mouse|contextmenu)|click/;
|
||||
});
|
||||
|
||||
function replaceTest(x) {
|
||||
return x.replace(/^a|b/, ''); // OK - possibly replacing too much, but not obviously a problem
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
(function(x){
|
||||
|
||||
if ("http://evil.com/?http://good.com".match("https?://good.com")) {} // NOT OK
|
||||
if ("http://evil.com/?http://good.com".match(new RegExp("https?://good.com"))) {} // NOT OK
|
||||
if ("http://evil.com/?http://good.com".match("^https?://good.com")) {} // NOT OK - missing post-anchor
|
||||
if ("http://evil.com/?http://good.com".match(/^https?:\/\/good.com/)) {} // NOT OK - missing post-anchor
|
||||
if ("http://evil.com/?http://good.com".match("(^https?://good1.com)|(^https?://good2.com)")) {} // NOT OK - missing post-anchor
|
||||
if ("http://evil.com/?http://good.com".match("(https?://good.com)|(^https?://goodie.com)")) {} // NOT OK - missing post-anchor
|
||||
|
||||
/https?:\/\/good.com/.exec("http://evil.com/?http://good.com"); // NOT OK
|
||||
new RegExp("https?://good.com").exec("http://evil.com/?http://good.com"); // NOT OK
|
||||
|
||||
if ("http://evil.com/?http://good.com".search("https?://good.com") > -1) {} // NOT OK
|
||||
|
||||
new RegExp("https?://good.com").test("http://evil.com/?http://good.com"); // NOT OK
|
||||
|
||||
if ("something".match("other")) {} // OK
|
||||
if ("something".match("x.commissary")) {} // OK
|
||||
if ("http://evil.com/?http://good.com".match("https?://good.com")) {} // NOT OK
|
||||
if ("http://evil.com/?http://good.com".match("https?://good.com:8080")) {} // NOT OK
|
||||
|
||||
let trustedUrls = [
|
||||
"https?://good.com", // NOT OK, referenced below
|
||||
/https?:\/\/good.com/, // NOT OK, referenced below
|
||||
new RegExp("https?://good.com"), // NOT OK, referenced below
|
||||
"^https?://good.com" // NOT OK - missing post-anchor
|
||||
];
|
||||
function isTrustedUrl(url) {
|
||||
for (let trustedUrl of trustedUrls) {
|
||||
if (url.match(trustedUrl)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/https?:\/\/good.com\/([0-9]+)/.exec(url); // NOT OK
|
||||
"https://verygood.com/?id=" + /https?:\/\/good.com\/([0-9]+)/.exec(url)[0]; // OK
|
||||
"http" + (secure? "s": "") + "://" + "verygood.com/?id=" + /https?:\/\/good.com\/([0-9]+)/.exec(url)[0]; // OK
|
||||
"http" + (secure? "s": "") + "://" + ("verygood.com/?id=" + /https?:\/\/good.com\/([0-9]+)/.exec(url)[0]); // OK
|
||||
|
||||
// g or .replace?
|
||||
file = file.replace(
|
||||
/https:\/\/cdn\.ampproject\.org\/v0\/amp-story-0\.1\.js/g,
|
||||
hostName + '/dist/v0/amp-story-1.0.max.js'
|
||||
);
|
||||
|
||||
// missing context of use
|
||||
const urlPatterns = [
|
||||
{
|
||||
regex: /youtube.com\/embed\/([a-z0-9\?&=\-_]+)/i, // OK
|
||||
type: 'iframe', w: 560, h: 314,
|
||||
url: '//www.youtube.com/embed/$1',
|
||||
allowFullscreen: true
|
||||
}];
|
||||
|
||||
// ditto
|
||||
F.helpers.media = {
|
||||
defaults : {
|
||||
youtube : {
|
||||
matcher : /(youtube\.com|youtu\.be)\/(watch\?v=|v\/|u\/|embed\/?)?(videoseries\?list=(.*)|[\w-]{11}|\?listType=(.*)&list=(.*)).*/i,
|
||||
params : {
|
||||
autoplay : 1,
|
||||
autohide : 1,
|
||||
fs : 1,
|
||||
rel : 0,
|
||||
hd : 1,
|
||||
wmode : 'opaque',
|
||||
enablejsapi : 1
|
||||
},
|
||||
type : 'iframe',
|
||||
url : '//www.youtube.com/embed/$3'
|
||||
}}}
|
||||
|
||||
// ditto
|
||||
var urlPatterns = [
|
||||
{regex: /youtu\.be\/([\w\-.]+)/, type: 'iframe', w: 425, h: 350, url: '//www.youtube.com/embed/$1'},
|
||||
{regex: /youtube\.com(.+)v=([^&]+)/, type: 'iframe', w: 425, h: 350, url: '//www.youtube.com/embed/$2'},
|
||||
{regex: /vimeo\.com\/([0-9]+)/, type: 'iframe', w: 425, h: 350, url: '//player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc'},
|
||||
];
|
||||
|
||||
// check optional successsor to TLD
|
||||
new RegExp("(Pingdom.com_bot_version_)(\\d+)\\.(\\d+)")
|
||||
|
||||
// replace and spaces
|
||||
error.replace(/See https:\/\/github\.com\/Squirrel\/Squirrel\.Mac\/issues\/182 for more information/, 'See [this link](https://github.com/Microsoft/vscode/issues/7426#issuecomment-425093469) for more information');
|
||||
|
||||
// not a url
|
||||
var sharedScript = /<script\s.*src="(app:\/\/.+\.gaiamobile\.org)?\/?(shared\/.+)".*>/;
|
||||
|
||||
// replace
|
||||
const repo = repoURL.replace(/http(s)?:\/\/(\d+\.)?github.com\//gi, '')
|
||||
|
||||
// replace and space
|
||||
cmp.replace(/<option value="http:\/\/codemirror.net\/">HEAD<\/option>/,
|
||||
"<option value=\"http://codemirror.net/\">HEAD</option>\n <option value=\"http://marijnhaverbeke.nl/git/codemirror?a=blob_plain;hb=" + number + ";f=\">" + number + "</option>");
|
||||
|
||||
// replace and space
|
||||
const helpMsg = /For help see https:\/\/nodejs.org\/en\/docs\/inspector\s*/;
|
||||
msg = msg.replace(helpMsg, '');
|
||||
|
||||
// not a url
|
||||
pkg.source.match(/<a:skin.*?\s+xmlns:a="http:\/\/ajax.org\/2005\/aml"/m)
|
||||
|
||||
// replace
|
||||
path.replace(/engine.io/, "$&-client");
|
||||
|
||||
/\.com|\.org/; // OK, has no domain name
|
||||
/example\.com|whatever/; // OK, the other disjunction doesn't match a hostname
|
||||
});
|
||||
Reference in New Issue
Block a user