forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTargetBlank.ql
More file actions
56 lines (53 loc) · 2.19 KB
/
TargetBlank.ql
File metadata and controls
56 lines (53 loc) · 2.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/**
* @name Potentially unsafe external link
* @description External links that open in a new tab or window but do not specify
* link type 'noopener' or 'noreferrer' are a potential security risk.
* @kind problem
* @problem.severity warning
* @id js/unsafe-external-link
* @tags maintainability
* security
* external/cwe/cwe-200
* @precision very-high
*/
import javascript
import semmle.javascript.frameworks.Templating
/**
* Holds if the href attribute contains a host that we cannot determine statically.
*/
predicate hasDynamicHrefHostAttributeValue(DOM::ElementDefinition elem) {
exists (DOM::AttributeDefinition attr |
attr = elem.getAnAttribute() and
attr.getName().matches("%href%") |
// unknown string
not exists(attr.getStringValue()) or
exists (string url | url = attr.getStringValue() |
// fixed string with templating
url.regexpMatch(Templating::getDelimiterMatchingRegexp())
and
// ... that does not start with a fixed host or a relative path (common formats)
not url.regexpMatch("(?i)((https?:)?//)?[-a-z0-9.]*/.*")
)
)
}
from DOM::ElementDefinition e
where // `e` is a link that opens in a new browsing context (that is, it has `target="_blank"`)
e.getName() = "a" and
// and the host in the href is not hard-coded
hasDynamicHrefHostAttributeValue(e) and
e.getAttributeByName("target").getStringValue() = "_blank" and
// there is no `rel` attribute specifying link type `noopener`/`noreferrer`;
// `rel` attributes with non-constant value are handled conservatively
forall (DOM::AttributeDefinition relAttr | relAttr = e.getAttributeByName("rel") |
exists (string rel | rel = relAttr.getStringValue() |
not exists (string linkType | linkType = rel.splitAt(" ") |
linkType = "noopener" or
linkType = "noreferrer"
)
)
) and
// exclude elements with spread attributes or dynamically computed attribute names
not exists (DOM::AttributeDefinition attr | attr = e.getAnAttribute() |
not exists(attr.getName())
)
select e, "External links without noopener/noreferrer are a potential security risk."