Merge branch 'main' into js/shared-dataflow-merge-main

This commit is contained in:
Asger F
2024-08-02 13:18:38 +02:00
1505 changed files with 135513 additions and 35699 deletions

View File

@@ -1,15 +1,14 @@
{
"timestamp": "2023-03-23T12:04:41.317+00:00",
"source": {
"id": "js/internal-error",
"name": "Internal error",
"extractorName": "javascript"
},
"markdownMessage": "Internal error: com.semmle.util.exception.CatastrophicError: The TypeScript parser wrapper crashed with exit code 1",
"severity": "unknown",
"visibility": {
"cliSummaryTable": true,
"statusPage": false,
"telemetry": true
}
}
"markdownMessage": "Internal error: com.semmle.util.exception.CatastrophicError: The TypeScript parser wrapper crashed with exit code 1",
"severity": "unknown",
"source": {
"extractorName": "javascript",
"id": "js/internal-error",
"name": "Internal error"
},
"visibility": {
"cliSummaryTable": true,
"statusPage": false,
"telemetry": true
}
}

View File

@@ -1,7 +1,2 @@
import os
from create_database_utils import *
from diagnostics_test_utils import *
run_codeql_database_create([], lang="javascript", runFunction = runUnsuccessfully, db = None)
check_diagnostics()
def test(codeql, javascript):
codeql.database.create(_assert_failure=True)

View File

@@ -1,7 +1,2 @@
import os
from create_database_utils import *
from diagnostics_test_utils import *
run_codeql_database_create([], lang="javascript", runFunction = runSuccessfully, db = None)
check_diagnostics()
def test(codeql, javascript):
codeql.database.create()

View File

@@ -1,3 +1,2 @@
from create_database_utils import *
run_codeql_database_create([], lang="javascript", extra_args=["-Oskip_types=true"])
def test(codeql, javascript):
codeql.database.create(extractor_option="skip_types=true")

View File

@@ -1,4 +0,0 @@
dependencies:
codeql/javascript-all: '*'
codeql/javascript-queries: '*'
warnOnImplicitThis: true

View File

@@ -1 +0,0 @@
These tests are still run with the legacy test runner

View File

@@ -1,3 +1,22 @@
## 1.1.1
No user-facing changes.
## 1.1.0
### Major Analysis Improvements
* Added support for TypeScript 5.5.
### Minor Analysis Improvements
* Enabled type-tracking to follow content through array methods
* Improved modeling of `Array.prototype.splice` for when it is called with more than two arguments
## 1.0.2
No user-facing changes.
## 1.0.1
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.2
No user-facing changes.

View File

@@ -1,5 +1,10 @@
---
category: minorAnalysis
---
## 1.1.0
### Major Analysis Improvements
* Added support for TypeScript 5.5.
### Minor Analysis Improvements
* Enabled type-tracking to follow content through array methods
* Improved modeling of `Array.prototype.splice` for when it is called with more than two arguments

View File

@@ -0,0 +1,3 @@
## 1.1.1
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.1
lastReleaseVersion: 1.1.1

View File

@@ -1,5 +1,5 @@
name: codeql/javascript-all
version: 1.0.2-dev
version: 1.1.2-dev
groups: javascript
dbscheme: semmlecode.javascript.dbscheme
extractor: javascript
@@ -16,4 +16,5 @@ dependencies:
dataExtensions:
- semmle/javascript/frameworks/**/model.yml
- semmle/javascript/frameworks/**/*.model.yml
- semmle/javascript/security/domains/**/*.model.yml
warnOnImplicitThis: true

View File

@@ -0,0 +1,7 @@
extensions:
- addsTo:
pack: codeql/javascript-queries
extensible: requiredHelmetSecuritySetting
data:
- ["frameguard"]
- ["contentSecurityPolicy"]

View File

@@ -0,0 +1,208 @@
/**
* Provides classes for finding functionality that is loaded from untrusted sources and used in script or frame elements.
*/
import javascript
/** A location that adds a reference to an untrusted source. */
abstract class AddsUntrustedUrl extends Locatable {
/** Gets an explanation why this source is untrusted. */
abstract string getProblem();
/** Gets the URL of the untrusted source. */
abstract string getUrl();
}
/** Looks for static creation of an element and source. */
module StaticCreation {
/** Holds if `host` is an alias of localhost. */
bindingset[host]
predicate isLocalhostPrefix(string host) {
host.toLowerCase()
.regexpMatch([
"(?i)localhost(:[0-9]+)?/.*", "127.0.0.1(:[0-9]+)?/.*", "::1/.*", "\\[::1\\]:[0-9]+/.*"
])
}
/** Holds if `url` is a url that is vulnerable to a MITM attack. */
bindingset[url]
predicate isUntrustedSourceUrl(string url) {
exists(string hostPath | hostPath = url.regexpCapture("(?i)http://(.*)", 1) |
not isLocalhostPrefix(hostPath)
)
}
/** Holds if `url` refers to a CDN that needs an integrity check - even with https. */
bindingset[url]
predicate isCdnUrlWithCheckingRequired(string url) {
// Some CDN URLs are required to have an integrity attribute. We only add CDNs to that list
// that recommend integrity-checking.
exists(string hostname, string requiredCheckingHostname |
hostname = url.regexpCapture("(?i)^(?:https?:)?//([^/]+)/.*\\.js$", 1) and
isCdnDomainWithCheckingRequired(requiredCheckingHostname) and
hostname = requiredCheckingHostname
)
}
/** A script element that refers to untrusted content. */
class ScriptElementWithUntrustedContent extends AddsUntrustedUrl instanceof HTML::ScriptElement {
ScriptElementWithUntrustedContent() {
not exists(string digest | not digest = "" | super.getIntegrityDigest() = digest) and
isUntrustedSourceUrl(super.getSourcePath())
}
override string getUrl() { result = super.getSourcePath() }
override string getProblem() { result = "Script loaded using unencrypted connection." }
}
/** A script element that refers to untrusted content. */
class CdnScriptElementWithUntrustedContent extends AddsUntrustedUrl, HTML::ScriptElement {
CdnScriptElementWithUntrustedContent() {
not exists(string digest | not digest = "" | this.getIntegrityDigest() = digest) and
(
isCdnUrlWithCheckingRequired(this.getSourcePath())
or
isUrlWithUntrustedDomain(super.getSourcePath())
)
}
override string getUrl() { result = this.getSourcePath() }
override string getProblem() {
result = "Script loaded from content delivery network with no integrity check."
}
}
/** An iframe element that includes untrusted content. */
class IframeElementWithUntrustedContent extends AddsUntrustedUrl instanceof HTML::IframeElement {
IframeElementWithUntrustedContent() { isUntrustedSourceUrl(super.getSourcePath()) }
override string getUrl() { result = super.getSourcePath() }
override string getProblem() { result = "Iframe loaded using unencrypted connection." }
}
}
/** Holds if `url` refers to an URL that uses an untrusted domain. */
bindingset[url]
predicate isUrlWithUntrustedDomain(string url) {
exists(string hostname |
hostname = url.regexpCapture("(?i)^(?:https?:)?//([^/]+)/.*", 1) and
isUntrustedHostname(hostname)
)
}
/** Holds if `hostname` refers to a domain or subdomain that is untrusted. */
bindingset[hostname]
predicate isUntrustedHostname(string hostname) {
exists(string domain |
(hostname = domain or hostname.matches("%." + domain)) and
isUntrustedDomain(domain)
)
}
// The following predicates are extended in data extensions under javascript/ql/lib/semmle/javascript/security/domains/
// and can be extended with custom model packs as necessary.
/** Holds for hostnames defined in data extensions */
extensible predicate isCdnDomainWithCheckingRequired(string hostname);
/** Holds for domains defined in data extensions */
extensible predicate isUntrustedDomain(string domain);
/** Looks for dyanmic creation of an element and source. */
module DynamicCreation {
/** Holds if `call` creates a tag of kind `name`. */
predicate isCreateElementNode(DataFlow::CallNode call, string name) {
call = DataFlow::globalVarRef("document").getAMethodCall("createElement") and
call.getArgument(0).getStringValue().toLowerCase() = name
}
/** Get the right-hand side of an assignment to a named attribute. */
DataFlow::Node getAttributeAssignmentRhs(DataFlow::CallNode createCall, string name) {
result = createCall.getAPropertyWrite(name).getRhs()
or
exists(DataFlow::InvokeNode inv | inv = createCall.getAMemberInvocation("setAttribute") |
inv.getArgument(0).getStringValue() = name and
result = inv.getArgument(1)
)
}
/**
* Holds if `createCall` creates a `<script ../>` element which never
* has its `integrity` attribute set locally.
*/
predicate isCreateScriptNodeWoIntegrityCheck(DataFlow::CallNode createCall) {
isCreateElementNode(createCall, "script") and
not exists(getAttributeAssignmentRhs(createCall, "integrity"))
}
/** Holds if `t` tracks a URL that is loaded from an untrusted source. */
DataFlow::Node urlTrackedFromUnsafeSourceLiteral(DataFlow::TypeTracker t) {
t.start() and result.getStringValue().regexpMatch("(?i)http:.*")
or
exists(DataFlow::TypeTracker t2, DataFlow::Node prev |
prev = urlTrackedFromUnsafeSourceLiteral(t2)
|
not exists(string httpsUrl | httpsUrl.toLowerCase() = "https:" + any(string rest) |
// when the result may have a string value starting with https,
// we're most likely with an assignment like:
// e.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'
// these assignments, we don't want to fix - once the browser is using http,
// MITM attacks are possible anyway.
result.mayHaveStringValue(httpsUrl)
) and
(
t2 = t.smallstep(prev, result)
or
TaintTracking::sharedTaintStep(prev, result) and
t = t2
)
)
}
/** Holds a dataflow node is traked from an untrusted source. */
DataFlow::Node urlTrackedFromUnsafeSourceLiteral() {
result = urlTrackedFromUnsafeSourceLiteral(DataFlow::TypeTracker::end())
}
/** Holds if `sink` is assigned to the attribute `name` of any HTML element. */
predicate isAssignedToSrcAttribute(string name, DataFlow::Node sink) {
exists(DataFlow::CallNode createElementCall |
sink = getAttributeAssignmentRhs(createElementCall, "src") and
(
name = "script" and
isCreateScriptNodeWoIntegrityCheck(createElementCall)
or
name = "iframe" and
isCreateElementNode(createElementCall, "iframe")
)
)
}
/** A script or iframe element that refers to untrusted content. */
class IframeOrScriptSrcAssignment extends AddsUntrustedUrl {
string name;
IframeOrScriptSrcAssignment() {
name = ["script", "iframe"] and
exists(DataFlow::Node n | n.asExpr() = this |
isAssignedToSrcAttribute(name, n) and
n = urlTrackedFromUnsafeSourceLiteral()
)
}
override string getUrl() {
exists(DataFlow::Node n | n.asExpr() = this |
isAssignedToSrcAttribute(name, n) and
result = n.getStringValue()
)
}
override string getProblem() {
name = "script" and result = "Script loaded using unencrypted connection."
or
name = "iframe" and result = "Iframe loaded using unencrypted connection."
}
}
}

View File

@@ -0,0 +1,8 @@
extensions:
- addsTo:
pack: codeql/javascript-all
extensible: isCdnDomainWithCheckingRequired
data:
- ["code.jquery.com"]
- ["cdnjs.cloudflare.com"]
- ["cdnjs.com"]

View File

@@ -0,0 +1,6 @@
extensions:
- addsTo:
pack: codeql/javascript-all
extensible: isUntrustedDomain
data:
- ["polyfill.io"]

View File

@@ -0,0 +1,14 @@
extensions:
- addsTo:
pack: codeql/javascript-all
extensible: isUntrustedDomain
data:
# new location of the polyfill.io CDN, which was used to serve malware. See: https://www.cside.dev/blog/the-polyfill-attack-explained
- ["polyfill.com"]
- ["polyfillcache.com"]
# domains operated by the same owner as polyfill.io, which was used to serve malware. See: https://www.cside.dev/blog/the-polyfill-attack-explained
- ["bootcdn.net"]
- ["bootcss.com"]
- ["staticfile.net"]
- ["staticfile.org"]

View File

@@ -1,3 +1,27 @@
## 1.1.0
### New Queries
* Added a new query, `js/insecure-helmet-configuration`, to detect instances where Helmet middleware is configured with important security features disabled.
### Minor Analysis Improvements
* Added a new query, `js/functionality-from-untrusted-domain`, which detects uses in HTML and JavaScript scripts from untrusted domains, including the `polyfill.io` content delivery network
* it can be extended to detect other compromised scripts using user-provided data extensions of the `untrustedDomain` predicate, which takes one string argument with the domain to warn on (and will warn on any subdomains too).
* Modified existing query, `js/functionality-from-untrusted-source`, to allow adding this new query, but reusing the same logic
* Added the ability to use data extensions to require SRI on CDN hostnames using the `isCdnDomainWithCheckingRequired` predicate, which takes one string argument of the full hostname to require SRI for.
* Created a new library, `semmle.javascript.security.FunctionalityFromUntrustedSource`, to support both queries.
## 1.0.3
### Minor Analysis Improvements
* Added a new experimental query, `js/cors-misconfiguration`, which detects misconfigured CORS HTTP headers in the `cors` and `apollo` libraries.
## 1.0.2
No user-facing changes.
## 1.0.1
No user-facing changes.

View File

@@ -0,0 +1,36 @@
# Insecure Helmet Configuration - customizations
You can extend the required [Helmet security settings](https://helmetjs.github.io/) using [data extensions](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-javascript/) in a [CodeQL model pack](https://docs.github.com/en/code-security/codeql-cli/using-the-advanced-functionality-of-the-codeql-cli/creating-and-working-with-codeql-packs#creating-a-codeql-model-pack).
They are defaulted to just `frameguard` and `contentSecurityPolicy`, but you can add more using this method, to require them not to be set to `false` (which explicitly disables them) in the Helmet configuration.
For example, this YAML model can be used inside a CodeQL model pack to require `frameguard` and `contentSecurityPolicy`:
```yaml
extensions:
- addsTo:
pack: codeql/javascript-all
extensible: requiredHelmetSecuritySetting
data:
- ["frameguard"]
- ["contentSecurityPolicy"]
```
Note: Using `frameguard` and `contentSecurityPolicy` is an example: the query already enforces these, so it is not necessary to add it with your own data extension.
A suitable [model pack](https://docs.github.com/en/code-security/codeql-cli/using-the-advanced-functionality-of-the-codeql-cli/creating-and-working-with-codeql-packs#creating-a-codeql-model-pack) might be:
```yaml
name: my-org/javascript-helmet-insecure-config-model-pack
version: 1.0.0
extensionTargets:
codeql/java-all: '*'
dataExtensions:
- models/**/*.yml
```
## References
- [Helmet security settings](https://helmetjs.github.io/)
- [Customizing library models for javascript](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-javascript/)
- [Creating and working with CodeQL packs](https://docs.github.com/en/code-security/codeql-cli/using-the-advanced-functionality-of-the-codeql-cli/creating-and-working-with-codeql-packs#creating-a-codeql-model-pack)

View File

@@ -0,0 +1,71 @@
<!DOCTYPE qhelp SYSTEM "qhelp.dtd">
<qhelp>
<overview>
<p>
<a href="https://helmetjs.github.io/">Helmet</a> is a collection of middleware functions for securing Express apps. It sets various HTTP headers to guard against common web vulnerabilities.
This query detects Helmet misconfigurations that can lead to security vulnerabilities, specifically:
</p>
<ul>
<li>Disabling frame protection</li>
<li>Disabling Content Security Policy</li>
</ul>
<p>
Content Security Policy (CSP) helps spot and prevent injection attacks such as Cross-Site Scripting (XSS).
Removing frame protections exposes an application to attacks such as clickjacking, where an attacker can trick a user into clicking on a button or link on a targeted page when they intended to click on the page carrying out the attack.
</p>
<p>
Users of the query can extend the set of required Helmet features by adding additional checks for them, using CodeQL <a href="https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-javascript/">data extensions</a> in a <a href="https://docs.github.com/en/code-security/codeql-cli/using-the-advanced-functionality-of-the-codeql-cli/creating-and-working-with-codeql-packs#creating-a-codeql-model-pack">CodeQL model pack</a>. See <code>CUSTOMIZING.md</code> in the query source for more information.
</p>
</overview>
<recommendation>
<p>
To help mitigate these vulnerabilities, ensure that the following Helmet functions are not disabled, and are configured appropriately to your application:
</p>
<ul>
<li><code>frameguard</code></li>
<li><code>contentSecurityPolicy</code></li>
</ul>
</recommendation>
<example>
<p>
The following code snippet demonstrates Helmet configured in an insecure manner:
</p>
<sample src="examples/helmet_insecure.js" />
<p>
In this example, the defaults are used, which enables frame protection and a default Content Security Policy.
</p>
<sample src="examples/helmet_default.js" />
<p>
You can also enable a custom Content Security Policy by passing an object to the <code>contentSecurityPolicy</code> key. For example, taken from the <a href="https://helmetjs.github.io/#content-security-policy">Helmet docs</a>:
</p>
<sample src="examples/helmet_custom.js" />
</example>
<references>
<li>
<a href="https://helmetjs.github.io/">helmet.js website</a>
</li>
<li>
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy">Content Security Policy (CSP) | MDN</a>
</li>
<li>
<a href="https://infosec.mozilla.org/guidelines/web_security">Mozilla Web Security Guidelines</a>
</li>
<li>
<a href="https://developer.mozilla.org/en-US/docs/Web/Security#protect_against_clickjacking">Protect against clickjacking | MDN</a>
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,47 @@
/**
* @name Insecure configuration of Helmet security middleware
* @description The Helmet middleware is used to set security-related HTTP headers in Express applications. This query finds instances where the middleware is configured with important security features disabled.
* @kind problem
* @problem.severity error
* @security-severity 7.0
* @precision high
* @id js/insecure-helmet-configuration
* @tags security
* external/cwe/cwe-693
* external/cwe/cwe-1021
*/
import javascript
import DataFlow
import semmle.javascript.frameworks.ExpressModules
class HelmetProperty extends DataFlow::Node instanceof DataFlow::PropWrite {
ExpressLibraries::HelmetRouteHandler helmet;
HelmetProperty() {
this = helmet.(DataFlow::CallNode).getAnArgument().getALocalSource().getAPropertyWrite()
}
ExpressLibraries::HelmetRouteHandler getHelmet() { result = helmet }
predicate isFalse() { DataFlow::PropWrite.super.getRhs().mayHaveBooleanValue(false) }
string getName() { result = DataFlow::PropWrite.super.getPropertyName() }
predicate isImportantSecuritySetting() {
// read from data extensions to allow enforcing custom settings
// defaults are located in javascript/ql/lib/semmle/frameworks/helmet/Helmet.Required.Setting.model.yml
requiredHelmetSecuritySetting(this.getName())
}
}
extensible predicate requiredHelmetSecuritySetting(string name);
from HelmetProperty helmetProperty, ExpressLibraries::HelmetRouteHandler helmet
where
helmetProperty.isFalse() and
helmetProperty.isImportantSecuritySetting() and
helmetProperty.getHelmet() = helmet
select helmet,
"Helmet security middleware, configured with security setting $@ set to 'false', which disables enforcing that feature.",
helmetProperty, helmetProperty.getName()

View File

@@ -0,0 +1,10 @@
app.use(
helmet({
contentSecurityPolicy: {
directives: {
"script-src": ["'self'", "example.com"],
"style-src": null,
},
},
})
);

View File

@@ -0,0 +1 @@
app.use(helmet());

View File

@@ -0,0 +1,6 @@
const helmet = require('helmet');
app.use(helmet({
frameguard: false,
contentSecurityPolicy: false
}));

View File

@@ -0,0 +1,43 @@
# Extending the library list of untrusted sources and domains
You can expand the list of untrusted domains in the CodeQL library used by the `js/functionality-from-untrusted-source` and `js/functionality-from-untrusted-domain` queries using [CodeQL data extensions](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-javascript/).
This allows you to add additional domains to warn users about and to require Subresource Integrity (SRI) checks on specific content delivery network (CDN) hostnames.
For example, this YAML model can be used inside a CodeQL model pack to alert on uses of `example.com` in imported functionality, extending the `js/functionality-from-untrusted-domain` query:
```yaml
extensions:
- addsTo:
pack: codeql/javascript-all
extensible: untrustedDomain
data:
- ["example.com"]
```
To add new hostnames that always require SRI checking, this YAML model can be used to require SRI on `cdn.example.com`, extending the `js/functionality-from-untrusted-source` query:
```yaml
extensions:
- addsTo:
pack: codeql/javascript-all
extensible: isCdnDomainWithCheckingRequired
data:
- ["cdn.example.com"]
```
You would create a model pack with this information using metadata similar to that in the example below:
```yaml
name: my-org/javascript-untrusted-functionality-model-pack
version: 1.0.0
extensionTargets:
codeql/java-all: '*'
dataExtensions:
- models/**/*.yml
```
## References
- [Customizing library models for javascript](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-javascript/)
- [Creating and working with CodeQL packs](https://docs.github.com/en/code-security/codeql-cli/using-the-advanced-functionality-of-the-codeql-cli/creating-and-working-with-codeql-packs#creating-a-codeql-model-pack)

View File

@@ -0,0 +1,102 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Content Delivery Networks (CDNs) are used to deliver content to users quickly and efficiently.
However, they can change hands or be operated by untrustworthy owners, risking the security of the sites that use them.
Some CDN domains are operated by entities that have used CDNs to deliver malware, which this query identifies.
</p>
<p>
For example, <code>polyfill.io</code> was a popular JavaScript CDN,
used to support new web browser standards on older browsers.
In February 2024 the domain was sold, and in June 2024 it was publicised that the domain
had been used to serve malicious scripts. It was taken down later in that month, leaving a window
where sites that used the service could have been compromised.
The same operator runs several other CDNs, undermining trust in those too.
</p>
<p>
Including a resource from an untrusted source or using an untrusted channel may
allow an attacker to include arbitrary code in the response.
When including an external resource (for example, a <code>script</code> element) on a page,
it is important to ensure that the received data is not malicious.
</p>
<p>
Even when <code>https</code> is used, an untrustworthy operator might deliver malware.
</p>
<p>
See the [`CUSTOMIZING.md`](https://github.com/github/codeql/blob/main/javascript/ql/src/Security/CWE-830/CUSTOMIZING.md) file in the source code for this query for information on how to extend the list of untrusted domains used by this query.
</p>
</overview>
<recommendation>
<p>
Carefully research the ownership of a Content Delivery Network (CDN) before using it in your application.
</p>
<p>
If you find code that originated from an untrusted domain in your application, you should review your logs to check for compromise.
</p>
<p>
To help mitigate the risk of including a script that could be compromised in the future, consider whether you need to
use polyfill or another library at all. Modern browsers do not require a polyfill, and other popular libraries were made redundant by enhancements to HTML 5.
</p>
<p>
If you do need a polyfill service or library, move to using a CDN that you trust.
</p>
<p>
When you use a <code>script</code> or <code>link</code> element,
you should check for <a href="https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity">subresource integrity (SRI)</a>,
and pin to a hash of a version of the service that you can trust (for example, because you have audited it for security and unwanted features).
A dynamic service cannot be easily used with SRI. Nevertheless,
it is possible to list multiple acceptable SHA hashes in the <code>integrity</code> attribute,
such as hashes for the content required for the major browsers used by your users.
</p>
<p>
You can also choose to self-host an uncompromised version of the service or library.
</p>
</recommendation>
<example>
<p>
The following example loads the Polyfill.io library from the <code>polyfill.io</code> CDN. This use was open to malicious scripts being served by the CDN.
</p>
<sample src="polyfill-compromised.html" />
<p>
Instead, load the Polyfill library from a trusted CDN, as in the next example:
</p>
<sample src="polyfill-trusted.html" />
<p>
If you know which browsers are used by the majority of your users, you can list the hashes of the polyfills for those browsers:
</p>
<sample src="polyfill-sri.html" />
</example>
<references>
<li>Sansec: <a href="https://sansec.io/research/polyfill-supply-chain-attack">Polyfill supply chain attack hits 100K+ sites</a></li>
<li>Cloudflare: <a href="https://cdnjs.cloudflare.com/polyfill">Upgrade the web. Automatically. Delivers only the polyfills required by the user's web browser.</a></li>
<li>Fastly: <a href="https://community.fastly.com/t/new-options-for-polyfill-io-users/2540">New options for Polyfill.io users</a></li>
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Polyfill_(programming)">Polyfill (programming)</a></li>
<li>MDN Web Docs: <a href="https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity">Subresource Integrity</a></li>
</references>
</qhelp>

View File

@@ -0,0 +1,18 @@
/**
* @name Untrusted domain used in script or other content
* @description Using a resource from an untrusted or compromised domain makes your code vulnerable to receiving malicious code.
* @kind problem
* @security-severity 7.2
* @problem.severity error
* @id js/functionality-from-untrusted-domain
* @precision high
* @tags security
* external/cwe/cwe-830
*/
import javascript
import semmle.javascript.security.FunctionalityFromUntrustedSource
from AddsUntrustedUrl s
where isUrlWithUntrustedDomain(s.getUrl())
select s, "Content loaded from untrusted domain with no integrity check."

View File

@@ -28,11 +28,21 @@
</p>
<p>
Subresource integrity checking is commonly recommended when importing a fixed version of
Subresource integrity (SRI) checking is commonly recommended when importing a fixed version of
a library - for example, from a CDN (content-delivery network). Then, the fixed digest
of that version of the library can easily be added to the <code>script</code> element's
<code>integrity</code> attribute.
</p>
<p>
A dynamic service cannot be easily used with SRI. Nevertheless,
it is possible to list multiple acceptable SHA hashes in the <code>integrity</code> attribute,
such as those for the content generated for major browers used by your users.
</p>
<p>
See the [`CUSTOMIZING.md`](https://github.com/github/codeql/blob/main/javascript/ql/src/Security/CWE-830/CUSTOMIZING.md) file in the source code for this query for information on how to extend the list of hostnames required to use SRI by this query.
</p>
</overview>
<recommendation>

View File

@@ -12,158 +12,10 @@
*/
import javascript
/** A location that adds a reference to an untrusted source. */
abstract class AddsUntrustedUrl extends Locatable {
/** Gets an explanation why this source is untrusted. */
abstract string getProblem();
}
module StaticCreation {
/** Holds if `host` is an alias of localhost. */
bindingset[host]
predicate isLocalhostPrefix(string host) {
host.toLowerCase()
.regexpMatch([
"(?i)localhost(:[0-9]+)?/.*", "127.0.0.1(:[0-9]+)?/.*", "::1/.*", "\\[::1\\]:[0-9]+/.*"
])
}
/** Holds if `url` is a url that is vulnerable to a MITM attack. */
bindingset[url]
predicate isUntrustedSourceUrl(string url) {
exists(string hostPath | hostPath = url.regexpCapture("(?i)http://(.*)", 1) |
not isLocalhostPrefix(hostPath)
)
}
/** Holds if `url` refers to a CDN that needs an integrity check - even with https. */
bindingset[url]
predicate isCdnUrlWithCheckingRequired(string url) {
// Some CDN URLs are required to have an integrity attribute. We only add CDNs to that list
// that recommend integrity-checking.
url.regexpMatch("(?i)^https?://" +
[
"code\\.jquery\\.com", //
"cdnjs\\.cloudflare\\.com", //
"cdnjs\\.com" //
] + "/.*\\.js$")
}
/** A script element that refers to untrusted content. */
class ScriptElementWithUntrustedContent extends AddsUntrustedUrl instanceof HTML::ScriptElement {
ScriptElementWithUntrustedContent() {
not exists(string digest | not digest = "" | super.getIntegrityDigest() = digest) and
isUntrustedSourceUrl(super.getSourcePath())
}
override string getProblem() { result = "Script loaded using unencrypted connection." }
}
/** A script element that refers to untrusted content. */
class CdnScriptElementWithUntrustedContent extends AddsUntrustedUrl, HTML::ScriptElement {
CdnScriptElementWithUntrustedContent() {
not exists(string digest | not digest = "" | this.getIntegrityDigest() = digest) and
isCdnUrlWithCheckingRequired(this.getSourcePath())
}
override string getProblem() {
result = "Script loaded from content delivery network with no integrity check."
}
}
/** An iframe element that includes untrusted content. */
class IframeElementWithUntrustedContent extends AddsUntrustedUrl instanceof HTML::IframeElement {
IframeElementWithUntrustedContent() { isUntrustedSourceUrl(super.getSourcePath()) }
override string getProblem() { result = "Iframe loaded using unencrypted connection." }
}
}
module DynamicCreation {
/** Holds if `call` creates a tag of kind `name`. */
predicate isCreateElementNode(DataFlow::CallNode call, string name) {
call = DataFlow::globalVarRef("document").getAMethodCall("createElement") and
call.getArgument(0).getStringValue().toLowerCase() = name
}
DataFlow::Node getAttributeAssignmentRhs(DataFlow::CallNode createCall, string name) {
result = createCall.getAPropertyWrite(name).getRhs()
or
exists(DataFlow::InvokeNode inv | inv = createCall.getAMemberInvocation("setAttribute") |
inv.getArgument(0).getStringValue() = name and
result = inv.getArgument(1)
)
}
/**
* Holds if `createCall` creates a `<script ../>` element which never
* has its `integrity` attribute set locally.
*/
predicate isCreateScriptNodeWoIntegrityCheck(DataFlow::CallNode createCall) {
isCreateElementNode(createCall, "script") and
not exists(getAttributeAssignmentRhs(createCall, "integrity"))
}
DataFlow::Node urlTrackedFromUnsafeSourceLiteral(DataFlow::TypeTracker t) {
t.start() and result.getStringValue().regexpMatch("(?i)http:.*")
or
exists(DataFlow::TypeTracker t2, DataFlow::Node prev |
prev = urlTrackedFromUnsafeSourceLiteral(t2)
|
not exists(string httpsUrl | httpsUrl.toLowerCase() = "https:" + any(string rest) |
// when the result may have a string value starting with https,
// we're most likely with an assignment like:
// e.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'
// these assignments, we don't want to fix - once the browser is using http,
// MITM attacks are possible anyway.
result.mayHaveStringValue(httpsUrl)
) and
(
t2 = t.smallstep(prev, result)
or
TaintTracking::sharedTaintStep(prev, result) and
t = t2
)
)
}
DataFlow::Node urlTrackedFromUnsafeSourceLiteral() {
result = urlTrackedFromUnsafeSourceLiteral(DataFlow::TypeTracker::end())
}
/** Holds if `sink` is assigned to the attribute `name` of any HTML element. */
predicate isAssignedToSrcAttribute(string name, DataFlow::Node sink) {
exists(DataFlow::CallNode createElementCall |
sink = getAttributeAssignmentRhs(createElementCall, "src") and
(
name = "script" and
isCreateScriptNodeWoIntegrityCheck(createElementCall)
or
name = "iframe" and
isCreateElementNode(createElementCall, "iframe")
)
)
}
class IframeOrScriptSrcAssignment extends AddsUntrustedUrl {
string name;
IframeOrScriptSrcAssignment() {
name = ["script", "iframe"] and
exists(DataFlow::Node n | n.asExpr() = this |
isAssignedToSrcAttribute(name, n) and
n = urlTrackedFromUnsafeSourceLiteral()
)
}
override string getProblem() {
name = "script" and result = "Script loaded using unencrypted connection."
or
name = "iframe" and result = "Iframe loaded using unencrypted connection."
}
}
}
import semmle.javascript.security.FunctionalityFromUntrustedSource
from AddsUntrustedUrl s
// do not alert on explicitly untrusted domains
// another query can alert on these, js/functionality-from-untrusted-domain
where not isUrlWithUntrustedDomain(s.getUrl())
select s, s.getProblem()

View File

@@ -0,0 +1,9 @@
<html>
<head>
<title>Polyfill.io demo</title>
<script src="https://cdn.polyfill.io/v2/polyfill.min.js" crossorigin="anonymous"></script>
</head>
<body>
...
</body>
</html>

View File

@@ -0,0 +1,9 @@
<html>
<head>
<title>Polyfill demo - Cloudflare hosted with pinned version (with integrity checking for a *very limited* browser set - just an example!)</title>
<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?version=4.8.0" integrity="sha384-i0IGVuZBkKZqwXTD4CH4kcksIbFx7WKFMdxN8zUhLFHpLdELF0ym0jxa6UvLhW8/ sha384-3d4jRKquKl90C9aFG+eH4lPJmtbPHgACWHrp+VomFOxF8lzx2jxqeYkhpRg18UWC" crossorigin="anonymous"></script>
</head>
<body>
...
</body>
</html>

View File

@@ -0,0 +1,9 @@
<html>
<head>
<title>Polyfill demo - Cloudflare hosted with pinned version (but no integrity checking, since it is dynamically generated)</title>
<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?version=4.8.0" crossorigin="anonymous"></script>
</head>
<body>
...
</body>
</html>

View File

@@ -0,0 +1,3 @@
## 1.0.2
No user-facing changes.

View File

@@ -0,0 +1,5 @@
## 1.0.3
### Minor Analysis Improvements
* Added a new experimental query, `js/cors-misconfiguration`, which detects misconfigured CORS HTTP headers in the `cors` and `apollo` libraries.

View File

@@ -0,0 +1,13 @@
## 1.1.0
### New Queries
* Added a new query, `js/insecure-helmet-configuration`, to detect instances where Helmet middleware is configured with important security features disabled.
### Minor Analysis Improvements
* Added a new query, `js/functionality-from-untrusted-domain`, which detects uses in HTML and JavaScript scripts from untrusted domains, including the `polyfill.io` content delivery network
* it can be extended to detect other compromised scripts using user-provided data extensions of the `untrustedDomain` predicate, which takes one string argument with the domain to warn on (and will warn on any subdomains too).
* Modified existing query, `js/functionality-from-untrusted-source`, to allow adding this new query, but reusing the same logic
* Added the ability to use data extensions to require SRI on CDN hostnames using the `isCdnDomainWithCheckingRequired` predicate, which takes one string argument of the full hostname to require SRI for.
* Created a new library, `semmle.javascript.security.FunctionalityFromUntrustedSource`, to support both queries.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.1
lastReleaseVersion: 1.1.0

View File

@@ -0,0 +1,36 @@
/**
* Provides classes for working with Apollo GraphQL connectors.
*/
import javascript
/** Provides classes modeling the apollo packages [@apollo/server](https://npmjs.com/package/@apollo/server`) */
module Apollo {
/** Get a reference to the `ApolloServer` class. */
private API::Node apollo() {
result =
API::moduleImport([
"@apollo/server", "@apollo/apollo-server-express", "@apollo/apollo-server-core",
"apollo-server", "apollo-server-express"
]).getMember("ApolloServer")
}
/** Gets a reference to the `gql` function that parses GraphQL strings. */
private API::Node gql() {
result =
API::moduleImport([
"@apollo/server", "@apollo/apollo-server-express", "@apollo/apollo-server-core",
"apollo-server", "apollo-server-express"
]).getMember("gql")
}
/** An instantiation of an `ApolloServer`. */
class ApolloServer extends API::NewNode {
ApolloServer() { this = apollo().getAnInstantiation() }
}
/** A string that is interpreted as a GraphQL query by a `apollo` package. */
private class ApolloGraphQLString extends GraphQL::GraphQLString {
ApolloGraphQLString() { this = gql().getACall().getArgument(0) }
}
}

View File

@@ -0,0 +1,24 @@
/**
* Provides classes for working with Cors connectors.
*/
import javascript
/** Provides classes modeling the [cors](https://npmjs.com/package/cors) library. */
module Cors {
/**
* An expression that creates a new CORS configuration.
*/
class Cors extends DataFlow::CallNode {
Cors() { this = DataFlow::moduleImport("cors").getAnInvocation() }
/** Get the options used to configure Cors */
DataFlow::Node getOptionsArgument() { result = this.getArgument(0) }
/** Holds if cors is using default configuration */
predicate isDefault() { this.getNumArgument() = 0 }
/** Gets the value of the `origin` option used to configure this Cors instance. */
DataFlow::Node getOrigin() { result = this.getOptionArgument(0, "origin") }
}
}

View File

@@ -0,0 +1,71 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
A server can use <code>CORS</code> (Cross-Origin Resource Sharing) to relax the
restrictions imposed by the <code>SOP</code> (Same-Origin Policy), allowing controlled, secure
cross-origin requests when necessary.
A server with an overly permissive <code>CORS</code> configuration may inadvertently
expose sensitive data or lead to <code>CSRF</code> which is an attack that allows attackers to trick
users into performing unwanted operations in websites they're authenticated to.
</p>
</overview>
<recommendation>
<p>
When the <code>origin</code> is set to <code>true</code>, it signifies that the server
is accepting requests from <code>any</code> origin, potentially exposing the system to
CSRF attacks. This can be fixed using <code>false</code> as origin value or using a whitelist.
</p>
<p>
On the other hand, if the <code>origin</code> is
set to <code>null</code>, it can be exploited by an attacker to deceive a user into making
requests from a <code>null</code> origin form, often hosted within a sandboxed iframe.
</p>
<p>
If the <code>origin</code> value is user controlled, make sure that the data
is properly sanitized.
</p>
</recommendation>
<example>
<p>
In the example below, the <code>server_1</code> accepts requests from any origin
since the value of <code>origin</code> is set to <code>true</code>.
And <code>server_2</code>'s origin is user-controlled.
</p>
<sample src="examples/CorsPermissiveConfigurationBad.js"/>
<p>
In the example below, the <code>server_1</code> CORS is restrictive so it's not
vulnerable to CSRF attacks. And <code>server_2</code>'s is using properly sanitized
user-controlled data.
</p>
<sample src="examples/CorsPermissiveConfigurationGood.js"/>
</example>
<references>
<li>Mozilla Developer Network: <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin">CORS, Access-Control-Allow-Origin</a>.</li>
<li>W3C: <a href="https://w3c.github.io/webappsec-cors-for-developers/#resources">CORS for developers, Advice for Resource Owners</a></li>
</references>
</qhelp>

View File

@@ -0,0 +1,20 @@
/**
* @name overly CORS configuration
* @description Misconfiguration of CORS HTTP headers allows CSRF attacks.
* @kind path-problem
* @problem.severity error
* @security-severity 7.5
* @precision high
* @id js/cors-misconfiguration
* @tags security
* external/cwe/cwe-942
*/
import javascript
import CorsPermissiveConfigurationQuery
import DataFlow::PathGraph
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "CORS Origin misconfiguration due to a $@.", source.getNode(),
"too permissive or user controlled value"

View File

@@ -0,0 +1,95 @@
/**
* Provides default sources, sinks and sanitizers for reasoning about
* overly permissive CORS configurations, as well as
* extension points for adding your own.
*/
import javascript
import Cors::Cors
import Apollo::Apollo
/** Module containing sources, sinks, and sanitizers for overly permissive CORS configurations. */
module CorsPermissiveConfiguration {
/**
* A data flow source for permissive CORS configuration.
*/
abstract class Source extends DataFlow::Node { }
/**
* A data flow sink for permissive CORS configuration.
*/
abstract class Sink extends DataFlow::Node { }
/**
* A sanitizer for permissive CORS configuration.
*/
abstract class Sanitizer extends DataFlow::Node { }
/** A source of remote user input, considered as a flow source for CORS misconfiguration. */
class RemoteFlowSourceAsSource extends Source instanceof RemoteFlowSource {
RemoteFlowSourceAsSource() { not this instanceof ClientSideRemoteFlowSource }
}
/** A flow label representing `true` and `null` values. */
abstract class TrueAndNull extends DataFlow::FlowLabel {
TrueAndNull() { this = "TrueAndNull" }
}
TrueAndNull truenullLabel() { any() }
/** A flow label representing `*` value. */
abstract class Wildcard extends DataFlow::FlowLabel {
Wildcard() { this = "Wildcard" }
}
Wildcard wildcardLabel() { any() }
/** An overly permissive value for `origin` (Apollo) */
class TrueNullValue extends Source {
TrueNullValue() { this.mayHaveBooleanValue(true) or this.asExpr() instanceof NullLiteral }
}
/** An overly permissive value for `origin` (Express) */
class WildcardValue extends Source {
WildcardValue() { this.mayHaveStringValue("*") }
}
/**
* The value of cors origin when initializing the application.
*/
class CorsApolloServer extends Sink, DataFlow::ValueNode {
CorsApolloServer() {
exists(ApolloServer agql |
this =
agql.getOptionArgument(0, "cors").getALocalSource().getAPropertyWrite("origin").getRhs()
)
}
}
/**
* The value of cors origin when initializing the application.
*/
class ExpressCors extends Sink, DataFlow::ValueNode {
ExpressCors() {
exists(CorsConfiguration config | this = config.getCorsConfiguration().getOrigin())
}
}
/**
* An express route setup configured with the `cors` package.
*/
class CorsConfiguration extends DataFlow::MethodCallNode {
Cors corsConfig;
CorsConfiguration() {
exists(Express::RouteSetup setup | this = setup |
if setup.isUseCall()
then corsConfig = setup.getArgument(0)
else corsConfig = setup.getArgument(any(int i | i > 0))
)
}
/** Gets the expression that configures `cors` on this route setup. */
Cors getCorsConfiguration() { result = corsConfig }
}
}

View File

@@ -0,0 +1,46 @@
/**
* Provides a dataflow taint tracking configuration for reasoning
* about overly permissive CORS configurations.
*
* Note, for performance reasons: only import this file if
* `CorsPermissiveConfiguration::Configuration` is needed,
* otherwise `CorsPermissiveConfigurationCustomizations` should
* be imported instead.
*/
import javascript
import CorsPermissiveConfigurationCustomizations::CorsPermissiveConfiguration
/**
* A data flow configuration for overly permissive CORS configuration.
*/
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "CorsPermissiveConfiguration" }
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
source instanceof TrueNullValue and label = truenullLabel()
or
source instanceof WildcardValue and label = wildcardLabel()
or
source instanceof RemoteFlowSource and label = DataFlow::FlowLabel::taint()
}
override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) {
sink instanceof CorsApolloServer and label = [DataFlow::FlowLabel::taint(), truenullLabel()]
or
sink instanceof ExpressCors and label = [DataFlow::FlowLabel::taint(), wildcardLabel()]
}
override predicate isSanitizer(DataFlow::Node node) {
super.isSanitizer(node) or
node instanceof Sanitizer
}
}
private class WildcardActivated extends DataFlow::FlowLabel, Wildcard {
WildcardActivated() { this = this }
}
private class TrueAndNullActivated extends DataFlow::FlowLabel, TrueAndNull {
TrueAndNullActivated() { this = this }
}

View File

@@ -0,0 +1,18 @@
import { ApolloServer } from 'apollo-server';
var https = require('https'),
url = require('url');
var server = https.createServer(function () { });
server.on('request', function (req, res) {
// BAD: origin is too permissive
const server_1 = new ApolloServer({
cors: { origin: true }
});
let user_origin = url.parse(req.url, true).query.origin;
// BAD: CORS is controlled by user
const server_2 = new ApolloServer({
cors: { origin: user_origin }
});
});

View File

@@ -0,0 +1,18 @@
import { ApolloServer } from 'apollo-server';
var https = require('https'),
url = require('url');
var server = https.createServer(function () { });
server.on('request', function (req, res) {
// GOOD: origin is restrictive
const server_1 = new ApolloServer({
cors: { origin: false }
});
let user_origin = url.parse(req.url, true).query.origin;
// GOOD: user data is properly sanitized
const server_2 = new ApolloServer({
cors: { origin: (user_origin === "https://allowed1.com" || user_origin === "https://allowed2.com") ? user_origin : false }
});
});

View File

@@ -1,5 +1,5 @@
name: codeql/javascript-queries
version: 1.0.2-dev
version: 1.1.1-dev
groups:
- javascript
- queries

View File

@@ -0,0 +1,50 @@
nodes
| apollo-test.js:8:9:8:59 | user_origin |
| apollo-test.js:8:23:8:46 | url.par ... , true) |
| apollo-test.js:8:23:8:52 | url.par ... ).query |
| apollo-test.js:8:23:8:59 | url.par ... .origin |
| apollo-test.js:8:33:8:39 | req.url |
| apollo-test.js:8:33:8:39 | req.url |
| apollo-test.js:11:25:11:28 | true |
| apollo-test.js:11:25:11:28 | true |
| apollo-test.js:11:25:11:28 | true |
| apollo-test.js:21:25:21:28 | null |
| apollo-test.js:21:25:21:28 | null |
| apollo-test.js:21:25:21:28 | null |
| apollo-test.js:26:25:26:35 | user_origin |
| apollo-test.js:26:25:26:35 | user_origin |
| express-test.js:10:9:10:59 | user_origin |
| express-test.js:10:23:10:46 | url.par ... , true) |
| express-test.js:10:23:10:52 | url.par ... ).query |
| express-test.js:10:23:10:59 | url.par ... .origin |
| express-test.js:10:33:10:39 | req.url |
| express-test.js:10:33:10:39 | req.url |
| express-test.js:26:17:26:19 | '*' |
| express-test.js:26:17:26:19 | '*' |
| express-test.js:26:17:26:19 | '*' |
| express-test.js:33:17:33:27 | user_origin |
| express-test.js:33:17:33:27 | user_origin |
edges
| apollo-test.js:8:9:8:59 | user_origin | apollo-test.js:26:25:26:35 | user_origin |
| apollo-test.js:8:9:8:59 | user_origin | apollo-test.js:26:25:26:35 | user_origin |
| apollo-test.js:8:23:8:46 | url.par ... , true) | apollo-test.js:8:23:8:52 | url.par ... ).query |
| apollo-test.js:8:23:8:52 | url.par ... ).query | apollo-test.js:8:23:8:59 | url.par ... .origin |
| apollo-test.js:8:23:8:59 | url.par ... .origin | apollo-test.js:8:9:8:59 | user_origin |
| apollo-test.js:8:33:8:39 | req.url | apollo-test.js:8:23:8:46 | url.par ... , true) |
| apollo-test.js:8:33:8:39 | req.url | apollo-test.js:8:23:8:46 | url.par ... , true) |
| apollo-test.js:11:25:11:28 | true | apollo-test.js:11:25:11:28 | true |
| apollo-test.js:21:25:21:28 | null | apollo-test.js:21:25:21:28 | null |
| express-test.js:10:9:10:59 | user_origin | express-test.js:33:17:33:27 | user_origin |
| express-test.js:10:9:10:59 | user_origin | express-test.js:33:17:33:27 | user_origin |
| express-test.js:10:23:10:46 | url.par ... , true) | express-test.js:10:23:10:52 | url.par ... ).query |
| express-test.js:10:23:10:52 | url.par ... ).query | express-test.js:10:23:10:59 | url.par ... .origin |
| express-test.js:10:23:10:59 | url.par ... .origin | express-test.js:10:9:10:59 | user_origin |
| express-test.js:10:33:10:39 | req.url | express-test.js:10:23:10:46 | url.par ... , true) |
| express-test.js:10:33:10:39 | req.url | express-test.js:10:23:10:46 | url.par ... , true) |
| express-test.js:26:17:26:19 | '*' | express-test.js:26:17:26:19 | '*' |
#select
| apollo-test.js:11:25:11:28 | true | apollo-test.js:11:25:11:28 | true | apollo-test.js:11:25:11:28 | true | CORS Origin misconfiguration due to a $@. | apollo-test.js:11:25:11:28 | true | too permissive or user controlled value |
| apollo-test.js:21:25:21:28 | null | apollo-test.js:21:25:21:28 | null | apollo-test.js:21:25:21:28 | null | CORS Origin misconfiguration due to a $@. | apollo-test.js:21:25:21:28 | null | too permissive or user controlled value |
| apollo-test.js:26:25:26:35 | user_origin | apollo-test.js:8:33:8:39 | req.url | apollo-test.js:26:25:26:35 | user_origin | CORS Origin misconfiguration due to a $@. | apollo-test.js:8:33:8:39 | req.url | too permissive or user controlled value |
| express-test.js:26:17:26:19 | '*' | express-test.js:26:17:26:19 | '*' | express-test.js:26:17:26:19 | '*' | CORS Origin misconfiguration due to a $@. | express-test.js:26:17:26:19 | '*' | too permissive or user controlled value |
| express-test.js:33:17:33:27 | user_origin | express-test.js:10:33:10:39 | req.url | express-test.js:33:17:33:27 | user_origin | CORS Origin misconfiguration due to a $@. | express-test.js:10:33:10:39 | req.url | too permissive or user controlled value |

View File

@@ -0,0 +1 @@
./experimental/Security/CWE-942/CorsPermissiveConfiguration.ql

View File

@@ -0,0 +1,28 @@
import { ApolloServer } from 'apollo-server';
var https = require('https'),
url = require('url');
var server = https.createServer(function () { });
server.on('request', function (req, res) {
let user_origin = url.parse(req.url, true).query.origin;
// BAD: CORS too permissive
const server_1 = new ApolloServer({
cors: { origin: true }
});
// GOOD: restrictive CORS
const server_2 = new ApolloServer({
cors: false
});
// BAD: CORS too permissive
const server_3 = new ApolloServer({
cors: { origin: null }
});
// BAD: CORS is controlled by user
const server_4 = new ApolloServer({
cors: { origin: user_origin }
});
});

View File

@@ -0,0 +1,36 @@
const cors = require('cors');
var express = require('express');
var https = require('https'),
url = require('url');
var server = https.createServer(function () { });
server.on('request', function (req, res) {
let user_origin = url.parse(req.url, true).query.origin;
// BAD: CORS too permissive, default value is *
var app1 = express();
app1.use(cors());
// GOOD: restrictive CORS
var app2 = express();
var corsOptions2 = {
origin: ["https://example1.com", "https://example2.com"],
};
app2.use(cors(corsOptions2));
// BAD: CORS too permissive
var app3 = express();
var corsOption3 = {
origin: '*'
};
app3.use(cors(corsOption3));
// BAD: CORS is controlled by user
var app4 = express();
var corsOption4 = {
origin: user_origin
};
app4.use(cors(corsOption4));
});

View File

@@ -126,6 +126,9 @@ nodes
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
@@ -1817,8 +1820,65 @@ nodes
| tst.ts:494:24:494:24 | [Literal] 0 | semmle.label | [Literal] 0 |
| tst.ts:494:28:494:33 | [Literal] "even" | semmle.label | [Literal] "even" |
| tst.ts:494:36:494:40 | [Literal] "odd" | semmle.label | [Literal] "odd" |
| tst.ts:498:1:511:1 | [NamespaceDeclaration] module ... } } } | semmle.label | [NamespaceDeclaration] module ... } } } |
| tst.ts:498:1:511:1 | [NamespaceDeclaration] module ... } } } | semmle.order | 91 |
| tst.ts:498:8:498:11 | [VarDecl] TS55 | semmle.label | [VarDecl] TS55 |
| tst.ts:499:3:500:40 | [DeclStmt] const strings = ... | semmle.label | [DeclStmt] const strings = ... |
| tst.ts:499:9:499:15 | [VarDecl] strings | semmle.label | [VarDecl] strings |
| tst.ts:499:9:500:39 | [VariableDeclarator] strings ... tring") | semmle.label | [VariableDeclarator] strings ... tring") |
| tst.ts:499:19:499:32 | [ParExpr] (["foo", 123]) | semmle.label | [ParExpr] (["foo", 123]) |
| tst.ts:499:19:500:11 | [DotExpr] (["foo" ... .filter | semmle.label | [DotExpr] (["foo" ... .filter |
| tst.ts:499:19:500:39 | [MethodCallExpr] (["foo" ... tring") | semmle.label | [MethodCallExpr] (["foo" ... tring") |
| tst.ts:499:20:499:31 | [ArrayExpr] ["foo", 123] | semmle.label | [ArrayExpr] ["foo", 123] |
| tst.ts:499:21:499:25 | [Literal] "foo" | semmle.label | [Literal] "foo" |
| tst.ts:499:28:499:30 | [Literal] 123 | semmle.label | [Literal] 123 |
| tst.ts:500:6:500:11 | [Label] filter | semmle.label | [Label] filter |
| tst.ts:500:13:500:13 | [SimpleParameter] s | semmle.label | [SimpleParameter] s |
| tst.ts:500:13:500:38 | [ArrowFunctionExpr] s => ty ... string" | semmle.label | [ArrowFunctionExpr] s => ty ... string" |
| tst.ts:500:18:500:25 | [UnaryExpr] typeof s | semmle.label | [UnaryExpr] typeof s |
| tst.ts:500:18:500:38 | [BinaryExpr] typeof ... string" | semmle.label | [BinaryExpr] typeof ... string" |
| tst.ts:500:25:500:25 | [VarRef] s | semmle.label | [VarRef] s |
| tst.ts:500:31:500:38 | [Literal] "string" | semmle.label | [Literal] "string" |
| tst.ts:502:3:504:3 | [ForOfStmt] for (co ... 5.4 } | semmle.label | [ForOfStmt] for (co ... 5.4 } |
| tst.ts:502:8:502:16 | [DeclStmt] const str = ... | semmle.label | [DeclStmt] const str = ... |
| tst.ts:502:14:502:16 | [VarDecl] str | semmle.label | [VarDecl] str |
| tst.ts:502:14:502:16 | [VariableDeclarator] str | semmle.label | [VariableDeclarator] str |
| tst.ts:502:21:502:27 | [VarRef] strings | semmle.label | [VarRef] strings |
| tst.ts:502:30:504:3 | [BlockStmt] { s ... 5.4 } | semmle.label | [BlockStmt] { s ... 5.4 } |
| tst.ts:503:5:503:7 | [VarRef] str | semmle.label | [VarRef] str |
| tst.ts:503:5:503:19 | [DotExpr] str.toLowerCase | semmle.label | [DotExpr] str.toLowerCase |
| tst.ts:503:5:503:21 | [MethodCallExpr] str.toLowerCase() | semmle.label | [MethodCallExpr] str.toLowerCase() |
| tst.ts:503:5:503:22 | [ExprStmt] str.toLowerCase(); | semmle.label | [ExprStmt] str.toLowerCase(); |
| tst.ts:503:9:503:19 | [Label] toLowerCase | semmle.label | [Label] toLowerCase |
| tst.ts:506:3:510:3 | [FunctionDeclStmt] functio ... } } | semmle.label | [FunctionDeclStmt] functio ... } } |
| tst.ts:506:12:506:13 | [VarDecl] f1 | semmle.label | [VarDecl] f1 |
| tst.ts:506:15:506:17 | [SimpleParameter] obj | semmle.label | [SimpleParameter] obj |
| tst.ts:506:20:506:25 | [LocalTypeAccess] Record | semmle.label | [LocalTypeAccess] Record |
| tst.ts:506:20:506:42 | [GenericTypeExpr] Record< ... nknown> | semmle.label | [GenericTypeExpr] Record< ... nknown> |
| tst.ts:506:27:506:32 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string |
| tst.ts:506:35:506:41 | [KeywordTypeExpr] unknown | semmle.label | [KeywordTypeExpr] unknown |
| tst.ts:506:45:506:47 | [SimpleParameter] key | semmle.label | [SimpleParameter] key |
| tst.ts:506:50:506:55 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string |
| tst.ts:506:58:510:3 | [BlockStmt] { i ... } } | semmle.label | [BlockStmt] { i ... } } |
| tst.ts:507:5:509:5 | [IfStmt] if (typ ... r } | semmle.label | [IfStmt] if (typ ... r } |
| tst.ts:507:9:507:23 | [UnaryExpr] typeof obj[key] | semmle.label | [UnaryExpr] typeof obj[key] |
| tst.ts:507:9:507:36 | [BinaryExpr] typeof ... string" | semmle.label | [BinaryExpr] typeof ... string" |
| tst.ts:507:16:507:18 | [VarRef] obj | semmle.label | [VarRef] obj |
| tst.ts:507:16:507:23 | [IndexExpr] obj[key] | semmle.label | [IndexExpr] obj[key] |
| tst.ts:507:20:507:22 | [VarRef] key | semmle.label | [VarRef] key |
| tst.ts:507:29:507:36 | [Literal] "string" | semmle.label | [Literal] "string" |
| tst.ts:507:39:509:5 | [BlockStmt] { ... r } | semmle.label | [BlockStmt] { ... r } |
| tst.ts:508:7:508:39 | [DeclStmt] var str = ... | semmle.label | [DeclStmt] var str = ... |
| tst.ts:508:11:508:13 | [VarDecl] str | semmle.label | [VarDecl] str |
| tst.ts:508:11:508:38 | [VariableDeclarator] str = o ... rCase() | semmle.label | [VariableDeclarator] str = o ... rCase() |
| tst.ts:508:17:508:19 | [VarRef] obj | semmle.label | [VarRef] obj |
| tst.ts:508:17:508:24 | [IndexExpr] obj[key] | semmle.label | [IndexExpr] obj[key] |
| tst.ts:508:17:508:36 | [DotExpr] obj[key].toUpperCase | semmle.label | [DotExpr] obj[key].toUpperCase |
| tst.ts:508:17:508:38 | [MethodCallExpr] obj[key ... rCase() | semmle.label | [MethodCallExpr] obj[key ... rCase() |
| tst.ts:508:21:508:23 | [VarRef] key | semmle.label | [VarRef] key |
| tst.ts:508:26:508:36 | [Label] toUpperCase | semmle.label | [Label] toUpperCase |
| tstModuleCJS.cts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.label | [ExportDeclaration] export ... 'b'; } |
| tstModuleCJS.cts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.order | 91 |
| tstModuleCJS.cts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.order | 92 |
| tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | semmle.label | [FunctionDeclStmt] functio ... 'b'; } |
| tstModuleCJS.cts:1:17:1:28 | [VarDecl] tstModuleCJS | semmle.label | [VarDecl] tstModuleCJS |
| tstModuleCJS.cts:1:33:1:35 | [LiteralTypeExpr] 'a' | semmle.label | [LiteralTypeExpr] 'a' |
@@ -1836,7 +1896,7 @@ nodes
| tstModuleCJS.cts:2:34:2:36 | [Literal] 'a' | semmle.label | [Literal] 'a' |
| tstModuleCJS.cts:2:40:2:42 | [Literal] 'b' | semmle.label | [Literal] 'b' |
| tstModuleES.mts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.label | [ExportDeclaration] export ... 'b'; } |
| tstModuleES.mts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.order | 92 |
| tstModuleES.mts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.order | 93 |
| tstModuleES.mts:1:16:3:1 | [FunctionDeclStmt] functio ... 'b'; } | semmle.label | [FunctionDeclStmt] functio ... 'b'; } |
| tstModuleES.mts:1:25:1:35 | [VarDecl] tstModuleES | semmle.label | [VarDecl] tstModuleES |
| tstModuleES.mts:1:40:1:42 | [LiteralTypeExpr] 'a' | semmle.label | [LiteralTypeExpr] 'a' |
@@ -1854,7 +1914,7 @@ nodes
| tstModuleES.mts:2:34:2:36 | [Literal] 'a' | semmle.label | [Literal] 'a' |
| tstModuleES.mts:2:40:2:42 | [Literal] 'b' | semmle.label | [Literal] 'b' |
| tstSuffixA.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.label | [ExportDeclaration] export ... .ts'; } |
| tstSuffixA.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 93 |
| tstSuffixA.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 94 |
| tstSuffixA.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | semmle.label | [FunctionDeclStmt] functio ... .ts'; } |
| tstSuffixA.ts:1:17:1:28 | [VarDecl] resolvedFile | semmle.label | [VarDecl] resolvedFile |
| tstSuffixA.ts:1:33:1:47 | [LiteralTypeExpr] 'tstSuffixA.ts' | semmle.label | [LiteralTypeExpr] 'tstSuffixA.ts' |
@@ -1862,7 +1922,7 @@ nodes
| tstSuffixA.ts:2:5:2:27 | [ReturnStmt] return ... xA.ts'; | semmle.label | [ReturnStmt] return ... xA.ts'; |
| tstSuffixA.ts:2:12:2:26 | [Literal] 'tstSuffixA.ts' | semmle.label | [Literal] 'tstSuffixA.ts' |
| tstSuffixB.ios.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.label | [ExportDeclaration] export ... .ts'; } |
| tstSuffixB.ios.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 94 |
| tstSuffixB.ios.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 95 |
| tstSuffixB.ios.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | semmle.label | [FunctionDeclStmt] functio ... .ts'; } |
| tstSuffixB.ios.ts:1:17:1:28 | [VarDecl] resolvedFile | semmle.label | [VarDecl] resolvedFile |
| tstSuffixB.ios.ts:1:33:1:51 | [LiteralTypeExpr] 'tstSuffixB.ios.ts' | semmle.label | [LiteralTypeExpr] 'tstSuffixB.ios.ts' |
@@ -1870,7 +1930,7 @@ nodes
| tstSuffixB.ios.ts:2:5:2:31 | [ReturnStmt] return ... os.ts'; | semmle.label | [ReturnStmt] return ... os.ts'; |
| tstSuffixB.ios.ts:2:12:2:30 | [Literal] 'tstSuffixB.ios.ts' | semmle.label | [Literal] 'tstSuffixB.ios.ts' |
| tstSuffixB.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.label | [ExportDeclaration] export ... .ts'; } |
| tstSuffixB.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 95 |
| tstSuffixB.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 96 |
| tstSuffixB.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | semmle.label | [FunctionDeclStmt] functio ... .ts'; } |
| tstSuffixB.ts:1:17:1:28 | [VarDecl] resolvedFile | semmle.label | [VarDecl] resolvedFile |
| tstSuffixB.ts:1:33:1:47 | [LiteralTypeExpr] 'tstSuffixB.ts' | semmle.label | [LiteralTypeExpr] 'tstSuffixB.ts' |
@@ -1878,16 +1938,16 @@ nodes
| tstSuffixB.ts:2:5:2:27 | [ReturnStmt] return ... xB.ts'; | semmle.label | [ReturnStmt] return ... xB.ts'; |
| tstSuffixB.ts:2:12:2:26 | [Literal] 'tstSuffixB.ts' | semmle.label | [Literal] 'tstSuffixB.ts' |
| type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type B = boolean; |
| type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.order | 96 |
| type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.order | 97 |
| type_alias.ts:1:6:1:6 | [Identifier] B | semmle.label | [Identifier] B |
| type_alias.ts:1:10:1:16 | [KeywordTypeExpr] boolean | semmle.label | [KeywordTypeExpr] boolean |
| type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.label | [DeclStmt] var b = ... |
| type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.order | 97 |
| type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.order | 98 |
| type_alias.ts:3:5:3:5 | [VarDecl] b | semmle.label | [VarDecl] b |
| type_alias.ts:3:5:3:8 | [VariableDeclarator] b: B | semmle.label | [VariableDeclarator] b: B |
| type_alias.ts:3:8:3:8 | [LocalTypeAccess] B | semmle.label | [LocalTypeAccess] B |
| type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay<T>>; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Va ... ay<T>>; |
| type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay<T>>; | semmle.order | 98 |
| type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay<T>>; | semmle.order | 99 |
| type_alias.ts:5:6:5:17 | [Identifier] ValueOrArray | semmle.label | [Identifier] ValueOrArray |
| type_alias.ts:5:19:5:19 | [Identifier] T | semmle.label | [Identifier] T |
| type_alias.ts:5:19:5:19 | [TypeParameter] T | semmle.label | [TypeParameter] T |
@@ -1899,14 +1959,14 @@ nodes
| type_alias.ts:5:34:5:48 | [GenericTypeExpr] ValueOrArray<T> | semmle.label | [GenericTypeExpr] ValueOrArray<T> |
| type_alias.ts:5:47:5:47 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T |
| type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.label | [DeclStmt] var c = ... |
| type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.order | 99 |
| type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.order | 100 |
| type_alias.ts:7:5:7:5 | [VarDecl] c | semmle.label | [VarDecl] c |
| type_alias.ts:7:5:7:27 | [VariableDeclarator] c: Valu ... number> | semmle.label | [VariableDeclarator] c: Valu ... number> |
| type_alias.ts:7:8:7:19 | [LocalTypeAccess] ValueOrArray | semmle.label | [LocalTypeAccess] ValueOrArray |
| type_alias.ts:7:8:7:27 | [GenericTypeExpr] ValueOrArray<number> | semmle.label | [GenericTypeExpr] ValueOrArray<number> |
| type_alias.ts:7:21:7:26 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number |
| type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; |
| type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.order | 100 |
| type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.order | 101 |
| type_alias.ts:9:6:9:9 | [Identifier] Json | semmle.label | [Identifier] Json |
| type_alias.ts:10:5:15:12 | [UnionTypeExpr] \| strin ... Json[] | semmle.label | [UnionTypeExpr] \| strin ... Json[] |
| type_alias.ts:10:7:10:12 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string |
@@ -1922,12 +1982,12 @@ nodes
| type_alias.ts:15:7:15:10 | [LocalTypeAccess] Json | semmle.label | [LocalTypeAccess] Json |
| type_alias.ts:15:7:15:12 | [ArrayTypeExpr] Json[] | semmle.label | [ArrayTypeExpr] Json[] |
| type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.label | [DeclStmt] var json = ... |
| type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.order | 101 |
| type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.order | 102 |
| type_alias.ts:17:5:17:8 | [VarDecl] json | semmle.label | [VarDecl] json |
| type_alias.ts:17:5:17:14 | [VariableDeclarator] json: Json | semmle.label | [VariableDeclarator] json: Json |
| type_alias.ts:17:11:17:14 | [LocalTypeAccess] Json | semmle.label | [LocalTypeAccess] Json |
| type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; |
| type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.order | 102 |
| type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.order | 103 |
| type_alias.ts:19:6:19:16 | [Identifier] VirtualNode | semmle.label | [Identifier] VirtualNode |
| type_alias.ts:20:5:21:56 | [UnionTypeExpr] \| strin ... Node[]] | semmle.label | [UnionTypeExpr] \| strin ... Node[]] |
| type_alias.ts:20:7:20:12 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string |
@@ -1943,7 +2003,7 @@ nodes
| type_alias.ts:21:43:21:53 | [LocalTypeAccess] VirtualNode | semmle.label | [LocalTypeAccess] VirtualNode |
| type_alias.ts:21:43:21:55 | [ArrayTypeExpr] VirtualNode[] | semmle.label | [ArrayTypeExpr] VirtualNode[] |
| type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.label | [DeclStmt] const myNode = ... |
| type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.order | 103 |
| type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.order | 104 |
| type_alias.ts:23:7:23:12 | [VarDecl] myNode | semmle.label | [VarDecl] myNode |
| type_alias.ts:23:7:27:5 | [VariableDeclarator] myNode: ... ] ] | semmle.label | [VariableDeclarator] myNode: ... ] ] |
| type_alias.ts:23:15:23:25 | [LocalTypeAccess] VirtualNode | semmle.label | [LocalTypeAccess] VirtualNode |
@@ -1968,12 +2028,12 @@ nodes
| type_alias.ts:26:23:26:36 | [Literal] "second-child" | semmle.label | [Literal] "second-child" |
| type_alias.ts:26:41:26:62 | [Literal] "I'm the second child" | semmle.label | [Literal] "I'm the second child" |
| type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.label | [ImportDeclaration] import ... dummy"; |
| type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 104 |
| type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 105 |
| type_definition_objects.ts:1:8:1:17 | [ImportSpecifier] * as dummy | semmle.label | [ImportSpecifier] * as dummy |
| type_definition_objects.ts:1:13:1:17 | [VarDecl] dummy | semmle.label | [VarDecl] dummy |
| type_definition_objects.ts:1:24:1:32 | [Literal] "./dummy" | semmle.label | [Literal] "./dummy" |
| type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.label | [ExportDeclaration] export class C {} |
| type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.order | 105 |
| type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.order | 106 |
| type_definition_objects.ts:3:8:3:17 | [ClassDefinition,TypeDefinition] class C {} | semmle.label | [ClassDefinition,TypeDefinition] class C {} |
| type_definition_objects.ts:3:14:3:14 | [VarDecl] C | semmle.label | [VarDecl] C |
| type_definition_objects.ts:3:16:3:15 | [BlockStmt] {} | semmle.label | [BlockStmt] {} |
@@ -1981,36 +2041,36 @@ nodes
| type_definition_objects.ts:3:16:3:15 | [FunctionExpr] () {} | semmle.label | [FunctionExpr] () {} |
| type_definition_objects.ts:3:16:3:15 | [Label] constructor | semmle.label | [Label] constructor |
| type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.label | [DeclStmt] let classObj = ... |
| type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.order | 106 |
| type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.order | 107 |
| type_definition_objects.ts:4:5:4:12 | [VarDecl] classObj | semmle.label | [VarDecl] classObj |
| type_definition_objects.ts:4:5:4:16 | [VariableDeclarator] classObj = C | semmle.label | [VariableDeclarator] classObj = C |
| type_definition_objects.ts:4:16:4:16 | [VarRef] C | semmle.label | [VarRef] C |
| type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.label | [ExportDeclaration] export enum E {} |
| type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.order | 107 |
| type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.order | 108 |
| type_definition_objects.ts:6:8:6:16 | [EnumDeclaration,TypeDefinition] enum E {} | semmle.label | [EnumDeclaration,TypeDefinition] enum E {} |
| type_definition_objects.ts:6:13:6:13 | [VarDecl] E | semmle.label | [VarDecl] E |
| type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.label | [DeclStmt] let enumObj = ... |
| type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.order | 108 |
| type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.order | 109 |
| type_definition_objects.ts:7:5:7:11 | [VarDecl] enumObj | semmle.label | [VarDecl] enumObj |
| type_definition_objects.ts:7:5:7:15 | [VariableDeclarator] enumObj = E | semmle.label | [VariableDeclarator] enumObj = E |
| type_definition_objects.ts:7:15:7:15 | [VarRef] E | semmle.label | [VarRef] E |
| type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.label | [ExportDeclaration] export ... e N {;} |
| type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.order | 109 |
| type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.order | 110 |
| type_definition_objects.ts:9:8:9:22 | [NamespaceDeclaration] namespace N {;} | semmle.label | [NamespaceDeclaration] namespace N {;} |
| type_definition_objects.ts:9:18:9:18 | [VarDecl] N | semmle.label | [VarDecl] N |
| type_definition_objects.ts:9:21:9:21 | [EmptyStmt] ; | semmle.label | [EmptyStmt] ; |
| type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.label | [DeclStmt] let namespaceObj = ... |
| type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.order | 110 |
| type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.order | 111 |
| type_definition_objects.ts:10:5:10:16 | [VarDecl] namespaceObj | semmle.label | [VarDecl] namespaceObj |
| type_definition_objects.ts:10:5:10:20 | [VariableDeclarator] namespaceObj = N | semmle.label | [VariableDeclarator] namespaceObj = N |
| type_definition_objects.ts:10:20:10:20 | [VarRef] N | semmle.label | [VarRef] N |
| type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.label | [ImportDeclaration] import ... dummy"; |
| type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 111 |
| type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 112 |
| type_definitions.ts:1:8:1:17 | [ImportSpecifier] * as dummy | semmle.label | [ImportSpecifier] * as dummy |
| type_definitions.ts:1:13:1:17 | [VarDecl] dummy | semmle.label | [VarDecl] dummy |
| type_definitions.ts:1:24:1:32 | [Literal] "./dummy" | semmle.label | [Literal] "./dummy" |
| type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.label | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } |
| type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.order | 112 |
| type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.order | 113 |
| type_definitions.ts:3:11:3:11 | [Identifier] I | semmle.label | [Identifier] I |
| type_definitions.ts:3:13:3:13 | [Identifier] S | semmle.label | [Identifier] S |
| type_definitions.ts:3:13:3:13 | [TypeParameter] S | semmle.label | [TypeParameter] S |
@@ -2018,14 +2078,14 @@ nodes
| type_definitions.ts:4:3:4:7 | [FieldDeclaration] x: S; | semmle.label | [FieldDeclaration] x: S; |
| type_definitions.ts:4:6:4:6 | [LocalTypeAccess] S | semmle.label | [LocalTypeAccess] S |
| type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.label | [DeclStmt] let i = ... |
| type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.order | 113 |
| type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.order | 114 |
| type_definitions.ts:6:5:6:5 | [VarDecl] i | semmle.label | [VarDecl] i |
| type_definitions.ts:6:5:6:16 | [VariableDeclarator] i: I<number> | semmle.label | [VariableDeclarator] i: I<number> |
| type_definitions.ts:6:8:6:8 | [LocalTypeAccess] I | semmle.label | [LocalTypeAccess] I |
| type_definitions.ts:6:8:6:16 | [GenericTypeExpr] I<number> | semmle.label | [GenericTypeExpr] I<number> |
| type_definitions.ts:6:10:6:15 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number |
| type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.label | [ClassDefinition,TypeDefinition] class C ... x: T } |
| type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.order | 114 |
| type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.order | 115 |
| type_definitions.ts:8:7:8:7 | [VarDecl] C | semmle.label | [VarDecl] C |
| type_definitions.ts:8:8:8:7 | [BlockStmt] {} | semmle.label | [BlockStmt] {} |
| type_definitions.ts:8:8:8:7 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | semmle.label | [ClassInitializedMember,ConstructorDefinition] constructor() {} |
@@ -2037,14 +2097,14 @@ nodes
| type_definitions.ts:9:3:9:6 | [FieldDeclaration] x: T | semmle.label | [FieldDeclaration] x: T |
| type_definitions.ts:9:6:9:6 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T |
| type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.label | [DeclStmt] let c = ... |
| type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.order | 115 |
| type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.order | 116 |
| type_definitions.ts:11:5:11:5 | [VarDecl] c | semmle.label | [VarDecl] c |
| type_definitions.ts:11:5:11:16 | [VariableDeclarator] c: C<number> | semmle.label | [VariableDeclarator] c: C<number> |
| type_definitions.ts:11:8:11:8 | [LocalTypeAccess] C | semmle.label | [LocalTypeAccess] C |
| type_definitions.ts:11:8:11:16 | [GenericTypeExpr] C<number> | semmle.label | [GenericTypeExpr] C<number> |
| type_definitions.ts:11:10:11:15 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number |
| type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.label | [EnumDeclaration,TypeDefinition] enum Co ... blue } |
| type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.order | 116 |
| type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.order | 117 |
| type_definitions.ts:13:6:13:10 | [VarDecl] Color | semmle.label | [VarDecl] Color |
| type_definitions.ts:14:3:14:5 | [EnumMember,TypeDefinition] red | semmle.label | [EnumMember,TypeDefinition] red |
| type_definitions.ts:14:3:14:5 | [VarDecl] red | semmle.label | [VarDecl] red |
@@ -2053,29 +2113,29 @@ nodes
| type_definitions.ts:14:15:14:18 | [EnumMember,TypeDefinition] blue | semmle.label | [EnumMember,TypeDefinition] blue |
| type_definitions.ts:14:15:14:18 | [VarDecl] blue | semmle.label | [VarDecl] blue |
| type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.label | [DeclStmt] let color = ... |
| type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.order | 117 |
| type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.order | 118 |
| type_definitions.ts:16:5:16:9 | [VarDecl] color | semmle.label | [VarDecl] color |
| type_definitions.ts:16:5:16:16 | [VariableDeclarator] color: Color | semmle.label | [VariableDeclarator] color: Color |
| type_definitions.ts:16:12:16:16 | [LocalTypeAccess] Color | semmle.label | [LocalTypeAccess] Color |
| type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.label | [EnumDeclaration,TypeDefinition] enum En ... ember } |
| type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.order | 118 |
| type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.order | 119 |
| type_definitions.ts:18:6:18:22 | [VarDecl] EnumWithOneMember | semmle.label | [VarDecl] EnumWithOneMember |
| type_definitions.ts:18:26:18:31 | [EnumMember,TypeDefinition] member | semmle.label | [EnumMember,TypeDefinition] member |
| type_definitions.ts:18:26:18:31 | [VarDecl] member | semmle.label | [VarDecl] member |
| type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.label | [DeclStmt] let e = ... |
| type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.order | 119 |
| type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.order | 120 |
| type_definitions.ts:19:5:19:5 | [VarDecl] e | semmle.label | [VarDecl] e |
| type_definitions.ts:19:5:19:24 | [VariableDeclarator] e: EnumWithOneMember | semmle.label | [VariableDeclarator] e: EnumWithOneMember |
| type_definitions.ts:19:8:19:24 | [LocalTypeAccess] EnumWithOneMember | semmle.label | [LocalTypeAccess] EnumWithOneMember |
| type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias<T> = T[]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Alias<T> = T[]; |
| type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias<T> = T[]; | semmle.order | 120 |
| type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias<T> = T[]; | semmle.order | 121 |
| type_definitions.ts:21:6:21:10 | [Identifier] Alias | semmle.label | [Identifier] Alias |
| type_definitions.ts:21:12:21:12 | [Identifier] T | semmle.label | [Identifier] T |
| type_definitions.ts:21:12:21:12 | [TypeParameter] T | semmle.label | [TypeParameter] T |
| type_definitions.ts:21:17:21:17 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T |
| type_definitions.ts:21:17:21:19 | [ArrayTypeExpr] T[] | semmle.label | [ArrayTypeExpr] T[] |
| type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.label | [DeclStmt] let aliasForNumberArray = ... |
| type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.order | 121 |
| type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.order | 122 |
| type_definitions.ts:22:5:22:23 | [VarDecl] aliasForNumberArray | semmle.label | [VarDecl] aliasForNumberArray |
| type_definitions.ts:22:5:22:38 | [VariableDeclarator] aliasFo ... number> | semmle.label | [VariableDeclarator] aliasFo ... number> |
| type_definitions.ts:22:26:22:30 | [LocalTypeAccess] Alias | semmle.label | [LocalTypeAccess] Alias |
@@ -2284,6 +2344,8 @@ edges
| file://:0:0:0:0 | (Arguments) | tst.ts:493:32:493:49 | [ArrayExpr] [0, 1, 2, 3, 4, 5] | semmle.order | 0 |
| file://:0:0:0:0 | (Arguments) | tst.ts:493:52:495:3 | [ArrowFunctionExpr] (num, i ... d"; } | semmle.label | 1 |
| file://:0:0:0:0 | (Arguments) | tst.ts:493:52:495:3 | [ArrowFunctionExpr] (num, i ... d"; } | semmle.order | 1 |
| file://:0:0:0:0 | (Arguments) | tst.ts:500:13:500:38 | [ArrowFunctionExpr] s => ty ... string" | semmle.label | 0 |
| file://:0:0:0:0 | (Arguments) | tst.ts:500:13:500:38 | [ArrowFunctionExpr] s => ty ... string" | semmle.order | 0 |
| file://:0:0:0:0 | (Parameters) | tst.ts:14:17:14:17 | [SimpleParameter] x | semmle.label | 0 |
| file://:0:0:0:0 | (Parameters) | tst.ts:14:17:14:17 | [SimpleParameter] x | semmle.order | 0 |
| file://:0:0:0:0 | (Parameters) | tst.ts:14:28:14:28 | [SimpleParameter] y | semmle.label | 1 |
@@ -2390,6 +2452,12 @@ edges
| file://:0:0:0:0 | (Parameters) | tst.ts:493:53:493:55 | [SimpleParameter] num | semmle.order | 0 |
| file://:0:0:0:0 | (Parameters) | tst.ts:493:58:493:62 | [SimpleParameter] index | semmle.label | 1 |
| file://:0:0:0:0 | (Parameters) | tst.ts:493:58:493:62 | [SimpleParameter] index | semmle.order | 1 |
| file://:0:0:0:0 | (Parameters) | tst.ts:500:13:500:13 | [SimpleParameter] s | semmle.label | 0 |
| file://:0:0:0:0 | (Parameters) | tst.ts:500:13:500:13 | [SimpleParameter] s | semmle.order | 0 |
| file://:0:0:0:0 | (Parameters) | tst.ts:506:15:506:17 | [SimpleParameter] obj | semmle.label | 0 |
| file://:0:0:0:0 | (Parameters) | tst.ts:506:15:506:17 | [SimpleParameter] obj | semmle.order | 0 |
| file://:0:0:0:0 | (Parameters) | tst.ts:506:45:506:47 | [SimpleParameter] key | semmle.label | 1 |
| file://:0:0:0:0 | (Parameters) | tst.ts:506:45:506:47 | [SimpleParameter] key | semmle.order | 1 |
| file://:0:0:0:0 | (Parameters) | type_alias.ts:14:10:14:17 | [SimpleParameter] property | semmle.label | 0 |
| file://:0:0:0:0 | (Parameters) | type_alias.ts:14:10:14:17 | [SimpleParameter] property | semmle.order | 0 |
| file://:0:0:0:0 | (Parameters) | type_alias.ts:21:19:21:21 | [SimpleParameter] key | semmle.label | 0 |
@@ -5358,6 +5426,114 @@ edges
| tst.ts:494:12:494:40 | [ConditionalExpr] num % 2 ... : "odd" | tst.ts:494:28:494:33 | [Literal] "even" | semmle.order | 2 |
| tst.ts:494:12:494:40 | [ConditionalExpr] num % 2 ... : "odd" | tst.ts:494:36:494:40 | [Literal] "odd" | semmle.label | 3 |
| tst.ts:494:12:494:40 | [ConditionalExpr] num % 2 ... : "odd" | tst.ts:494:36:494:40 | [Literal] "odd" | semmle.order | 3 |
| tst.ts:498:1:511:1 | [NamespaceDeclaration] module ... } } } | tst.ts:498:8:498:11 | [VarDecl] TS55 | semmle.label | 1 |
| tst.ts:498:1:511:1 | [NamespaceDeclaration] module ... } } } | tst.ts:498:8:498:11 | [VarDecl] TS55 | semmle.order | 1 |
| tst.ts:498:1:511:1 | [NamespaceDeclaration] module ... } } } | tst.ts:499:3:500:40 | [DeclStmt] const strings = ... | semmle.label | 2 |
| tst.ts:498:1:511:1 | [NamespaceDeclaration] module ... } } } | tst.ts:499:3:500:40 | [DeclStmt] const strings = ... | semmle.order | 2 |
| tst.ts:498:1:511:1 | [NamespaceDeclaration] module ... } } } | tst.ts:502:3:504:3 | [ForOfStmt] for (co ... 5.4 } | semmle.label | 3 |
| tst.ts:498:1:511:1 | [NamespaceDeclaration] module ... } } } | tst.ts:502:3:504:3 | [ForOfStmt] for (co ... 5.4 } | semmle.order | 3 |
| tst.ts:498:1:511:1 | [NamespaceDeclaration] module ... } } } | tst.ts:506:3:510:3 | [FunctionDeclStmt] functio ... } } | semmle.label | 4 |
| tst.ts:498:1:511:1 | [NamespaceDeclaration] module ... } } } | tst.ts:506:3:510:3 | [FunctionDeclStmt] functio ... } } | semmle.order | 4 |
| tst.ts:499:3:500:40 | [DeclStmt] const strings = ... | tst.ts:499:9:500:39 | [VariableDeclarator] strings ... tring") | semmle.label | 1 |
| tst.ts:499:3:500:40 | [DeclStmt] const strings = ... | tst.ts:499:9:500:39 | [VariableDeclarator] strings ... tring") | semmle.order | 1 |
| tst.ts:499:9:500:39 | [VariableDeclarator] strings ... tring") | tst.ts:499:9:499:15 | [VarDecl] strings | semmle.label | 1 |
| tst.ts:499:9:500:39 | [VariableDeclarator] strings ... tring") | tst.ts:499:9:499:15 | [VarDecl] strings | semmle.order | 1 |
| tst.ts:499:9:500:39 | [VariableDeclarator] strings ... tring") | tst.ts:499:19:500:39 | [MethodCallExpr] (["foo" ... tring") | semmle.label | 2 |
| tst.ts:499:9:500:39 | [VariableDeclarator] strings ... tring") | tst.ts:499:19:500:39 | [MethodCallExpr] (["foo" ... tring") | semmle.order | 2 |
| tst.ts:499:19:499:32 | [ParExpr] (["foo", 123]) | tst.ts:499:20:499:31 | [ArrayExpr] ["foo", 123] | semmle.label | 1 |
| tst.ts:499:19:499:32 | [ParExpr] (["foo", 123]) | tst.ts:499:20:499:31 | [ArrayExpr] ["foo", 123] | semmle.order | 1 |
| tst.ts:499:19:500:11 | [DotExpr] (["foo" ... .filter | tst.ts:499:19:499:32 | [ParExpr] (["foo", 123]) | semmle.label | 1 |
| tst.ts:499:19:500:11 | [DotExpr] (["foo" ... .filter | tst.ts:499:19:499:32 | [ParExpr] (["foo", 123]) | semmle.order | 1 |
| tst.ts:499:19:500:11 | [DotExpr] (["foo" ... .filter | tst.ts:500:6:500:11 | [Label] filter | semmle.label | 2 |
| tst.ts:499:19:500:11 | [DotExpr] (["foo" ... .filter | tst.ts:500:6:500:11 | [Label] filter | semmle.order | 2 |
| tst.ts:499:19:500:39 | [MethodCallExpr] (["foo" ... tring") | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
| tst.ts:499:19:500:39 | [MethodCallExpr] (["foo" ... tring") | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
| tst.ts:499:19:500:39 | [MethodCallExpr] (["foo" ... tring") | tst.ts:499:19:500:11 | [DotExpr] (["foo" ... .filter | semmle.label | 0 |
| tst.ts:499:19:500:39 | [MethodCallExpr] (["foo" ... tring") | tst.ts:499:19:500:11 | [DotExpr] (["foo" ... .filter | semmle.order | 0 |
| tst.ts:499:20:499:31 | [ArrayExpr] ["foo", 123] | tst.ts:499:21:499:25 | [Literal] "foo" | semmle.label | 1 |
| tst.ts:499:20:499:31 | [ArrayExpr] ["foo", 123] | tst.ts:499:21:499:25 | [Literal] "foo" | semmle.order | 1 |
| tst.ts:499:20:499:31 | [ArrayExpr] ["foo", 123] | tst.ts:499:28:499:30 | [Literal] 123 | semmle.label | 2 |
| tst.ts:499:20:499:31 | [ArrayExpr] ["foo", 123] | tst.ts:499:28:499:30 | [Literal] 123 | semmle.order | 2 |
| tst.ts:500:13:500:38 | [ArrowFunctionExpr] s => ty ... string" | file://:0:0:0:0 | (Parameters) | semmle.label | 1 |
| tst.ts:500:13:500:38 | [ArrowFunctionExpr] s => ty ... string" | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
| tst.ts:500:13:500:38 | [ArrowFunctionExpr] s => ty ... string" | tst.ts:500:18:500:38 | [BinaryExpr] typeof ... string" | semmle.label | 5 |
| tst.ts:500:13:500:38 | [ArrowFunctionExpr] s => ty ... string" | tst.ts:500:18:500:38 | [BinaryExpr] typeof ... string" | semmle.order | 5 |
| tst.ts:500:18:500:25 | [UnaryExpr] typeof s | tst.ts:500:25:500:25 | [VarRef] s | semmle.label | 1 |
| tst.ts:500:18:500:25 | [UnaryExpr] typeof s | tst.ts:500:25:500:25 | [VarRef] s | semmle.order | 1 |
| tst.ts:500:18:500:38 | [BinaryExpr] typeof ... string" | tst.ts:500:18:500:25 | [UnaryExpr] typeof s | semmle.label | 1 |
| tst.ts:500:18:500:38 | [BinaryExpr] typeof ... string" | tst.ts:500:18:500:25 | [UnaryExpr] typeof s | semmle.order | 1 |
| tst.ts:500:18:500:38 | [BinaryExpr] typeof ... string" | tst.ts:500:31:500:38 | [Literal] "string" | semmle.label | 2 |
| tst.ts:500:18:500:38 | [BinaryExpr] typeof ... string" | tst.ts:500:31:500:38 | [Literal] "string" | semmle.order | 2 |
| tst.ts:502:3:504:3 | [ForOfStmt] for (co ... 5.4 } | tst.ts:502:8:502:16 | [DeclStmt] const str = ... | semmle.label | 1 |
| tst.ts:502:3:504:3 | [ForOfStmt] for (co ... 5.4 } | tst.ts:502:8:502:16 | [DeclStmt] const str = ... | semmle.order | 1 |
| tst.ts:502:3:504:3 | [ForOfStmt] for (co ... 5.4 } | tst.ts:502:21:502:27 | [VarRef] strings | semmle.label | 2 |
| tst.ts:502:3:504:3 | [ForOfStmt] for (co ... 5.4 } | tst.ts:502:21:502:27 | [VarRef] strings | semmle.order | 2 |
| tst.ts:502:3:504:3 | [ForOfStmt] for (co ... 5.4 } | tst.ts:502:30:504:3 | [BlockStmt] { s ... 5.4 } | semmle.label | 3 |
| tst.ts:502:3:504:3 | [ForOfStmt] for (co ... 5.4 } | tst.ts:502:30:504:3 | [BlockStmt] { s ... 5.4 } | semmle.order | 3 |
| tst.ts:502:8:502:16 | [DeclStmt] const str = ... | tst.ts:502:14:502:16 | [VariableDeclarator] str | semmle.label | 1 |
| tst.ts:502:8:502:16 | [DeclStmt] const str = ... | tst.ts:502:14:502:16 | [VariableDeclarator] str | semmle.order | 1 |
| tst.ts:502:14:502:16 | [VariableDeclarator] str | tst.ts:502:14:502:16 | [VarDecl] str | semmle.label | 1 |
| tst.ts:502:14:502:16 | [VariableDeclarator] str | tst.ts:502:14:502:16 | [VarDecl] str | semmle.order | 1 |
| tst.ts:502:30:504:3 | [BlockStmt] { s ... 5.4 } | tst.ts:503:5:503:22 | [ExprStmt] str.toLowerCase(); | semmle.label | 1 |
| tst.ts:502:30:504:3 | [BlockStmt] { s ... 5.4 } | tst.ts:503:5:503:22 | [ExprStmt] str.toLowerCase(); | semmle.order | 1 |
| tst.ts:503:5:503:19 | [DotExpr] str.toLowerCase | tst.ts:503:5:503:7 | [VarRef] str | semmle.label | 1 |
| tst.ts:503:5:503:19 | [DotExpr] str.toLowerCase | tst.ts:503:5:503:7 | [VarRef] str | semmle.order | 1 |
| tst.ts:503:5:503:19 | [DotExpr] str.toLowerCase | tst.ts:503:9:503:19 | [Label] toLowerCase | semmle.label | 2 |
| tst.ts:503:5:503:19 | [DotExpr] str.toLowerCase | tst.ts:503:9:503:19 | [Label] toLowerCase | semmle.order | 2 |
| tst.ts:503:5:503:21 | [MethodCallExpr] str.toLowerCase() | tst.ts:503:5:503:19 | [DotExpr] str.toLowerCase | semmle.label | 0 |
| tst.ts:503:5:503:21 | [MethodCallExpr] str.toLowerCase() | tst.ts:503:5:503:19 | [DotExpr] str.toLowerCase | semmle.order | 0 |
| tst.ts:503:5:503:22 | [ExprStmt] str.toLowerCase(); | tst.ts:503:5:503:21 | [MethodCallExpr] str.toLowerCase() | semmle.label | 1 |
| tst.ts:503:5:503:22 | [ExprStmt] str.toLowerCase(); | tst.ts:503:5:503:21 | [MethodCallExpr] str.toLowerCase() | semmle.order | 1 |
| tst.ts:506:3:510:3 | [FunctionDeclStmt] functio ... } } | file://:0:0:0:0 | (Parameters) | semmle.label | 1 |
| tst.ts:506:3:510:3 | [FunctionDeclStmt] functio ... } } | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
| tst.ts:506:3:510:3 | [FunctionDeclStmt] functio ... } } | tst.ts:506:12:506:13 | [VarDecl] f1 | semmle.label | 0 |
| tst.ts:506:3:510:3 | [FunctionDeclStmt] functio ... } } | tst.ts:506:12:506:13 | [VarDecl] f1 | semmle.order | 0 |
| tst.ts:506:3:510:3 | [FunctionDeclStmt] functio ... } } | tst.ts:506:58:510:3 | [BlockStmt] { i ... } } | semmle.label | 5 |
| tst.ts:506:3:510:3 | [FunctionDeclStmt] functio ... } } | tst.ts:506:58:510:3 | [BlockStmt] { i ... } } | semmle.order | 5 |
| tst.ts:506:15:506:17 | [SimpleParameter] obj | tst.ts:506:20:506:42 | [GenericTypeExpr] Record< ... nknown> | semmle.label | -2 |
| tst.ts:506:15:506:17 | [SimpleParameter] obj | tst.ts:506:20:506:42 | [GenericTypeExpr] Record< ... nknown> | semmle.order | -2 |
| tst.ts:506:20:506:42 | [GenericTypeExpr] Record< ... nknown> | tst.ts:506:20:506:25 | [LocalTypeAccess] Record | semmle.label | 1 |
| tst.ts:506:20:506:42 | [GenericTypeExpr] Record< ... nknown> | tst.ts:506:20:506:25 | [LocalTypeAccess] Record | semmle.order | 1 |
| tst.ts:506:20:506:42 | [GenericTypeExpr] Record< ... nknown> | tst.ts:506:27:506:32 | [KeywordTypeExpr] string | semmle.label | 2 |
| tst.ts:506:20:506:42 | [GenericTypeExpr] Record< ... nknown> | tst.ts:506:27:506:32 | [KeywordTypeExpr] string | semmle.order | 2 |
| tst.ts:506:20:506:42 | [GenericTypeExpr] Record< ... nknown> | tst.ts:506:35:506:41 | [KeywordTypeExpr] unknown | semmle.label | 3 |
| tst.ts:506:20:506:42 | [GenericTypeExpr] Record< ... nknown> | tst.ts:506:35:506:41 | [KeywordTypeExpr] unknown | semmle.order | 3 |
| tst.ts:506:45:506:47 | [SimpleParameter] key | tst.ts:506:50:506:55 | [KeywordTypeExpr] string | semmle.label | -2 |
| tst.ts:506:45:506:47 | [SimpleParameter] key | tst.ts:506:50:506:55 | [KeywordTypeExpr] string | semmle.order | -2 |
| tst.ts:506:58:510:3 | [BlockStmt] { i ... } } | tst.ts:507:5:509:5 | [IfStmt] if (typ ... r } | semmle.label | 1 |
| tst.ts:506:58:510:3 | [BlockStmt] { i ... } } | tst.ts:507:5:509:5 | [IfStmt] if (typ ... r } | semmle.order | 1 |
| tst.ts:507:5:509:5 | [IfStmt] if (typ ... r } | tst.ts:507:9:507:36 | [BinaryExpr] typeof ... string" | semmle.label | 1 |
| tst.ts:507:5:509:5 | [IfStmt] if (typ ... r } | tst.ts:507:9:507:36 | [BinaryExpr] typeof ... string" | semmle.order | 1 |
| tst.ts:507:5:509:5 | [IfStmt] if (typ ... r } | tst.ts:507:39:509:5 | [BlockStmt] { ... r } | semmle.label | 2 |
| tst.ts:507:5:509:5 | [IfStmt] if (typ ... r } | tst.ts:507:39:509:5 | [BlockStmt] { ... r } | semmle.order | 2 |
| tst.ts:507:9:507:23 | [UnaryExpr] typeof obj[key] | tst.ts:507:16:507:23 | [IndexExpr] obj[key] | semmle.label | 1 |
| tst.ts:507:9:507:23 | [UnaryExpr] typeof obj[key] | tst.ts:507:16:507:23 | [IndexExpr] obj[key] | semmle.order | 1 |
| tst.ts:507:9:507:36 | [BinaryExpr] typeof ... string" | tst.ts:507:9:507:23 | [UnaryExpr] typeof obj[key] | semmle.label | 1 |
| tst.ts:507:9:507:36 | [BinaryExpr] typeof ... string" | tst.ts:507:9:507:23 | [UnaryExpr] typeof obj[key] | semmle.order | 1 |
| tst.ts:507:9:507:36 | [BinaryExpr] typeof ... string" | tst.ts:507:29:507:36 | [Literal] "string" | semmle.label | 2 |
| tst.ts:507:9:507:36 | [BinaryExpr] typeof ... string" | tst.ts:507:29:507:36 | [Literal] "string" | semmle.order | 2 |
| tst.ts:507:16:507:23 | [IndexExpr] obj[key] | tst.ts:507:16:507:18 | [VarRef] obj | semmle.label | 1 |
| tst.ts:507:16:507:23 | [IndexExpr] obj[key] | tst.ts:507:16:507:18 | [VarRef] obj | semmle.order | 1 |
| tst.ts:507:16:507:23 | [IndexExpr] obj[key] | tst.ts:507:20:507:22 | [VarRef] key | semmle.label | 2 |
| tst.ts:507:16:507:23 | [IndexExpr] obj[key] | tst.ts:507:20:507:22 | [VarRef] key | semmle.order | 2 |
| tst.ts:507:39:509:5 | [BlockStmt] { ... r } | tst.ts:508:7:508:39 | [DeclStmt] var str = ... | semmle.label | 1 |
| tst.ts:507:39:509:5 | [BlockStmt] { ... r } | tst.ts:508:7:508:39 | [DeclStmt] var str = ... | semmle.order | 1 |
| tst.ts:508:7:508:39 | [DeclStmt] var str = ... | tst.ts:508:11:508:38 | [VariableDeclarator] str = o ... rCase() | semmle.label | 1 |
| tst.ts:508:7:508:39 | [DeclStmt] var str = ... | tst.ts:508:11:508:38 | [VariableDeclarator] str = o ... rCase() | semmle.order | 1 |
| tst.ts:508:11:508:38 | [VariableDeclarator] str = o ... rCase() | tst.ts:508:11:508:13 | [VarDecl] str | semmle.label | 1 |
| tst.ts:508:11:508:38 | [VariableDeclarator] str = o ... rCase() | tst.ts:508:11:508:13 | [VarDecl] str | semmle.order | 1 |
| tst.ts:508:11:508:38 | [VariableDeclarator] str = o ... rCase() | tst.ts:508:17:508:38 | [MethodCallExpr] obj[key ... rCase() | semmle.label | 2 |
| tst.ts:508:11:508:38 | [VariableDeclarator] str = o ... rCase() | tst.ts:508:17:508:38 | [MethodCallExpr] obj[key ... rCase() | semmle.order | 2 |
| tst.ts:508:17:508:24 | [IndexExpr] obj[key] | tst.ts:508:17:508:19 | [VarRef] obj | semmle.label | 1 |
| tst.ts:508:17:508:24 | [IndexExpr] obj[key] | tst.ts:508:17:508:19 | [VarRef] obj | semmle.order | 1 |
| tst.ts:508:17:508:24 | [IndexExpr] obj[key] | tst.ts:508:21:508:23 | [VarRef] key | semmle.label | 2 |
| tst.ts:508:17:508:24 | [IndexExpr] obj[key] | tst.ts:508:21:508:23 | [VarRef] key | semmle.order | 2 |
| tst.ts:508:17:508:36 | [DotExpr] obj[key].toUpperCase | tst.ts:508:17:508:24 | [IndexExpr] obj[key] | semmle.label | 1 |
| tst.ts:508:17:508:36 | [DotExpr] obj[key].toUpperCase | tst.ts:508:17:508:24 | [IndexExpr] obj[key] | semmle.order | 1 |
| tst.ts:508:17:508:36 | [DotExpr] obj[key].toUpperCase | tst.ts:508:26:508:36 | [Label] toUpperCase | semmle.label | 2 |
| tst.ts:508:17:508:36 | [DotExpr] obj[key].toUpperCase | tst.ts:508:26:508:36 | [Label] toUpperCase | semmle.order | 2 |
| tst.ts:508:17:508:38 | [MethodCallExpr] obj[key ... rCase() | tst.ts:508:17:508:36 | [DotExpr] obj[key].toUpperCase | semmle.label | 0 |
| tst.ts:508:17:508:38 | [MethodCallExpr] obj[key ... rCase() | tst.ts:508:17:508:36 | [DotExpr] obj[key].toUpperCase | semmle.order | 0 |
| tstModuleCJS.cts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | semmle.label | 1 |
| tstModuleCJS.cts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | semmle.order | 1 |
| tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | tstModuleCJS.cts:1:17:1:28 | [VarDecl] tstModuleCJS | semmle.label | 0 |

View File

@@ -692,6 +692,43 @@ getExprType
| tst.ts:494:24:494:24 | 0 | 0 |
| tst.ts:494:28:494:33 | "even" | "even" |
| tst.ts:494:36:494:40 | "odd" | "odd" |
| tst.ts:498:8:498:11 | TS55 | typeof TS55 in library-tests/TypeScript/Types/tst.ts |
| tst.ts:499:9:499:15 | strings | string[] |
| tst.ts:499:19:499:32 | (["foo", 123]) | (string \| number)[] |
| tst.ts:499:19:500:11 | (["foo" ... .filter | { <S extends string \| number>(predicate: (value... |
| tst.ts:499:19:500:39 | (["foo" ... tring") | string[] |
| tst.ts:499:20:499:31 | ["foo", 123] | (string \| number)[] |
| tst.ts:499:21:499:25 | "foo" | "foo" |
| tst.ts:499:28:499:30 | 123 | 123 |
| tst.ts:500:6:500:11 | filter | { <S extends string \| number>(predicate: (value... |
| tst.ts:500:13:500:13 | s | string \| number |
| tst.ts:500:13:500:38 | s => ty ... string" | (s: string \| number) => s is string |
| tst.ts:500:18:500:25 | typeof s | "string" \| "number" \| "bigint" \| "boolean" \| "s... |
| tst.ts:500:18:500:38 | typeof ... string" | boolean |
| tst.ts:500:25:500:25 | s | string \| number |
| tst.ts:500:31:500:38 | "string" | "string" |
| tst.ts:502:14:502:16 | str | string |
| tst.ts:502:21:502:27 | strings | string[] |
| tst.ts:503:5:503:7 | str | string |
| tst.ts:503:5:503:19 | str.toLowerCase | () => string |
| tst.ts:503:5:503:21 | str.toLowerCase() | string |
| tst.ts:503:9:503:19 | toLowerCase | () => string |
| tst.ts:506:12:506:13 | f1 | (obj: Record<string, unknown>, key: string) => ... |
| tst.ts:506:15:506:17 | obj | Record<string, unknown> |
| tst.ts:506:45:506:47 | key | string |
| tst.ts:507:9:507:23 | typeof obj[key] | "string" \| "number" \| "bigint" \| "boolean" \| "s... |
| tst.ts:507:9:507:36 | typeof ... string" | boolean |
| tst.ts:507:16:507:18 | obj | Record<string, unknown> |
| tst.ts:507:16:507:23 | obj[key] | unknown |
| tst.ts:507:20:507:22 | key | string |
| tst.ts:507:29:507:36 | "string" | "string" |
| tst.ts:508:11:508:13 | str | string |
| tst.ts:508:17:508:19 | obj | Record<string, unknown> |
| tst.ts:508:17:508:24 | obj[key] | string |
| tst.ts:508:17:508:36 | obj[key].toUpperCase | () => string |
| tst.ts:508:17:508:38 | obj[key ... rCase() | string |
| tst.ts:508:21:508:23 | key | string |
| tst.ts:508:26:508:36 | toUpperCase | () => string |
| tstModuleCJS.cts:1:17:1:28 | tstModuleCJS | () => "a" \| "b" |
| tstModuleCJS.cts:2:12:2:15 | Math | Math |
| tstModuleCJS.cts:2:12:2:22 | Math.random | () => number |
@@ -1178,6 +1215,11 @@ getTypeExprType
| tst.ts:487:56:487:58 | C[] | C[] |
| tst.ts:487:76:487:82 | NoInfer | any |
| tst.ts:487:84:487:84 | C | C |
| tst.ts:506:20:506:25 | Record | Record<K, T> |
| tst.ts:506:20:506:42 | Record< ... nknown> | Record<string, unknown> |
| tst.ts:506:27:506:32 | string | string |
| tst.ts:506:35:506:41 | unknown | unknown |
| tst.ts:506:50:506:55 | string | string |
| tstModuleCJS.cts:1:33:1:35 | 'a' | "a" |
| tstModuleCJS.cts:1:33:1:41 | 'a' \| 'b' | "a" \| "b" |
| tstModuleCJS.cts:1:39:1:41 | 'b' | "b" |
@@ -1375,6 +1417,7 @@ unknownType
| tst.ts:228:12:228:16 | other | unknown |
| tst.ts:229:16:229:20 | other | unknown |
| tst.ts:230:20:230:24 | other | unknown |
| tst.ts:507:16:507:23 | obj[key] | unknown |
abstractSignature
| (): HasArea |
| new (): HasArea |

View File

@@ -493,4 +493,19 @@ module TS54 {
const myObj = Object.groupBy([0, 1, 2, 3, 4, 5], (num, index) => {
return num % 2 === 0 ? "even": "odd";
});
}
module TS55 {
const strings = (["foo", 123])
.filter(s => typeof s === "string");
for (const str of strings) {
str.toLowerCase(); // <- string in 5.5, string | number in 5.4
}
function f1(obj: Record<string, unknown>, key: string) {
if (typeof obj[key] === "string") {
var str = obj[key].toUpperCase(); // Now okay, previously was error
}
}
}

View File

@@ -0,0 +1,2 @@
| InsecureHelmetBad.js:6:9:9:2 | helmet( ... uard\\n}) | Helmet security middleware, configured with security setting $@ set to 'false', which disables enforcing that feature. | InsecureHelmetBad.js:7:5:7:32 | content ... : false | contentSecurityPolicy |
| InsecureHelmetBad.js:6:9:9:2 | helmet( ... uard\\n}) | Helmet security middleware, configured with security setting $@ set to 'false', which disables enforcing that feature. | InsecureHelmetBad.js:8:5:8:21 | frameguard: false | frameguard |

View File

@@ -0,0 +1 @@
Security/CWE-693/InsecureHelmet.ql

View File

@@ -0,0 +1,17 @@
const express = require("express");
const helmet = require("helmet");
const app = express();
app.use(helmet({
contentSecurityPolicy: false, // BAD: switch off default CSP
frameguard: false // BAD: switch off default frameguard
}));
app.get("/", (req, res) => {
res.send("Hello, world!");
});
app.listen(3000, () => {
console.log("App is listening on port 3000");
});

View File

@@ -0,0 +1,14 @@
const express = require("express");
const helmet = require("helmet");
const app = express();
app.use(helmet()); // GOOD: use the defaults
app.get("/", (req, res) => {
res.send("Hello, world!");
});
app.listen(3000, () => {
console.log("App is listening on port 3000");
});

View File

@@ -0,0 +1 @@
| polyfill-nocheck.html:4:9:4:98 | <script>...</> | Content loaded from untrusted domain with no integrity check. |

View File

@@ -0,0 +1 @@
Security/CWE-830/FunctionalityFromUntrustedDomain.ql

View File

@@ -0,0 +1,9 @@
<html>
<head>
<title>Polyfill demo - Cloudflare hosted with pinned version and integrity checking</title>
<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?version=4.8.0" integrity="sha384-3d4jRKquKl90C9aFG+eH4lPJmtbPHgACWHrp+VomFOxF8lzx2jxqeYkhpRg18UWC" crossorigin="anonymous"></script>
</head>
<body>
...
</body>
</html>

View File

@@ -0,0 +1,9 @@
<html>
<head>
<title>Polyfill.io demo</title>
<script src="https://cdn.polyfill.io/v2/polyfill.min.js" crossorigin="anonymous"></script>
</head>
<body>
...
</body>
</html>