mirror of
https://github.com/github/codeql.git
synced 2026-04-23 07:45:17 +02:00
Merge branch 'main' into amammad-js-bombs
This commit is contained in:
@@ -4,3 +4,4 @@ groups:
|
||||
- examples
|
||||
dependencies:
|
||||
codeql/javascript-all: ${workspace}
|
||||
warnOnImplicitThis: true
|
||||
|
||||
@@ -6,14 +6,12 @@ import experimental.adaptivethreatmodeling.EndpointTypes
|
||||
private import semmle.javascript.security.dataflow.SqlInjectionCustomizations
|
||||
private import semmle.javascript.security.dataflow.DomBasedXssCustomizations
|
||||
private import semmle.javascript.security.dataflow.NosqlInjectionCustomizations
|
||||
private import semmle.javascript.security.dataflow.TaintedPathCustomizations
|
||||
private import semmle.javascript.heuristics.SyntacticHeuristics as SyntacticHeuristics
|
||||
private import semmle.javascript.filters.ClassifyFiles as ClassifyFiles
|
||||
private import semmle.javascript.security.dataflow.XxeCustomizations
|
||||
private import semmle.javascript.security.dataflow.RemotePropertyInjectionCustomizations
|
||||
private import semmle.javascript.security.dataflow.TypeConfusionThroughParameterTamperingCustomizations
|
||||
private import semmle.javascript.security.dataflow.ZipSlipCustomizations
|
||||
private import semmle.javascript.security.dataflow.TaintedPathCustomizations
|
||||
private import semmle.javascript.security.dataflow.CleartextLoggingCustomizations
|
||||
private import semmle.javascript.security.dataflow.XpathInjectionCustomizations
|
||||
private import semmle.javascript.security.dataflow.Xss::Shared as Xss
|
||||
@@ -28,10 +26,8 @@ private import semmle.javascript.security.dataflow.CommandInjectionCustomization
|
||||
private import semmle.javascript.security.dataflow.PrototypePollutionCustomizations
|
||||
private import semmle.javascript.security.dataflow.UnvalidatedDynamicMethodCallCustomizations
|
||||
private import semmle.javascript.security.dataflow.TaintedFormatStringCustomizations
|
||||
private import semmle.javascript.security.dataflow.NosqlInjectionCustomizations
|
||||
private import semmle.javascript.security.dataflow.PostMessageStarCustomizations
|
||||
private import semmle.javascript.security.dataflow.RegExpInjectionCustomizations
|
||||
private import semmle.javascript.security.dataflow.SqlInjectionCustomizations
|
||||
private import semmle.javascript.security.dataflow.InsecureRandomnessCustomizations
|
||||
private import semmle.javascript.security.dataflow.XmlBombCustomizations
|
||||
private import semmle.javascript.security.dataflow.InsufficientPasswordHashCustomizations
|
||||
|
||||
@@ -23,7 +23,8 @@ class DomBasedXssAtmConfig extends AtmConfig {
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
super.isSanitizer(node) or
|
||||
node instanceof DomBasedXss::Sanitizer
|
||||
node instanceof DomBasedXss::Sanitizer or
|
||||
DomBasedXss::isOptionallySanitizedNode(node)
|
||||
}
|
||||
|
||||
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
|
||||
@@ -31,10 +32,6 @@ class DomBasedXssAtmConfig extends AtmConfig {
|
||||
guard instanceof QuoteGuard or
|
||||
guard instanceof ContainsHtmlGuard
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
DomBasedXss::isOptionallySanitizedEdge(pred, succ)
|
||||
}
|
||||
}
|
||||
|
||||
private import semmle.javascript.security.dataflow.Xss::Shared as Shared
|
||||
|
||||
@@ -23,7 +23,8 @@ class XssThroughDomAtmConfig extends AtmConfig {
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
super.isSanitizer(node) or
|
||||
node instanceof DomBasedXss::Sanitizer
|
||||
node instanceof DomBasedXss::Sanitizer or
|
||||
DomBasedXss::isOptionallySanitizedNode(node)
|
||||
}
|
||||
|
||||
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
|
||||
@@ -34,10 +35,6 @@ class XssThroughDomAtmConfig extends AtmConfig {
|
||||
guard instanceof QuoteGuard or
|
||||
guard instanceof ContainsHtmlGuard
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
DomBasedXss::isOptionallySanitizedEdge(pred, succ)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,3 +8,4 @@ groups:
|
||||
- experimental
|
||||
dependencies:
|
||||
codeql/javascript-all: ${workspace}
|
||||
warnOnImplicitThis: true
|
||||
|
||||
@@ -6,3 +6,4 @@ groups:
|
||||
- experimental
|
||||
mlModels:
|
||||
- "resources/*.codeqlmodel"
|
||||
warnOnImplicitThis: true
|
||||
|
||||
@@ -6,10 +6,8 @@
|
||||
|
||||
import javascript
|
||||
import experimental.adaptivethreatmodeling.AdaptiveThreatModeling
|
||||
import experimental.adaptivethreatmodeling.ATMConfig
|
||||
import experimental.adaptivethreatmodeling.BaseScoring
|
||||
import experimental.adaptivethreatmodeling.EndpointFeatures as EndpointFeatures
|
||||
import experimental.adaptivethreatmodeling.EndpointTypes
|
||||
import semmle.javascript.security.dataflow.NosqlInjectionCustomizations
|
||||
|
||||
/** Gets the positive endpoint type for which you wish to find misclassified examples. */
|
||||
|
||||
@@ -8,3 +8,4 @@ groups:
|
||||
dependencies:
|
||||
codeql/javascript-experimental-atm-lib: ${workspace}
|
||||
codeql/javascript-experimental-atm-model: "0.3.1-2023-03-01-12h42m43s.strong-turtle-1xp3dqvv.ecb17d40286d14132b481c065a43459a7f0ba9059015b7a49c909c9f9ce5fec5"
|
||||
warnOnImplicitThis: true
|
||||
|
||||
@@ -10,3 +10,4 @@ groups:
|
||||
dependencies:
|
||||
codeql/javascript-experimental-atm-lib: ${workspace}
|
||||
codeql/javascript-experimental-atm-model: "0.3.1-2023-03-01-12h42m43s.strong-turtle-1xp3dqvv.ecb17d40286d14132b481c065a43459a7f0ba9059015b7a49c909c9f9ce5fec5"
|
||||
warnOnImplicitThis: true
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
import semmle.javascript.security.dataflow.NosqlInjectionCustomizations
|
||||
import semmle.javascript.security.dataflow.SqlInjectionCustomizations
|
||||
import semmle.javascript.security.dataflow.TaintedPathCustomizations
|
||||
import semmle.javascript.security.dataflow.DomBasedXssCustomizations
|
||||
import semmle.javascript.security.dataflow.ShellCommandInjectionFromEnvironmentCustomizations
|
||||
import experimental.adaptivethreatmodeling.NosqlInjectionATM as NosqlInjectionAtm
|
||||
|
||||
@@ -2,3 +2,4 @@ name: codeql/javascript-experimental-atm-tests
|
||||
extractor: javascript
|
||||
dependencies:
|
||||
codeql/javascript-experimental-atm-model-building: ${workspace}
|
||||
warnOnImplicitThis: true
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export const foo: { bar: number } = { bar: 42};
|
||||
@@ -0,0 +1,5 @@
|
||||
import javascript
|
||||
|
||||
from Expr e, Type t
|
||||
where t = e.getType()
|
||||
select e, t
|
||||
@@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
codeql/javascript-all: '*'
|
||||
warnOnImplicitThis: true
|
||||
3
javascript/ql/integration-tests/all-platforms/no-types/test.py
Executable file
3
javascript/ql/integration-tests/all-platforms/no-types/test.py
Executable file
@@ -0,0 +1,3 @@
|
||||
from create_database_utils import *
|
||||
|
||||
run_codeql_database_create([], lang="javascript", extra_args=["-Oskip_types=true"])
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -1,3 +1,4 @@
|
||||
dependencies:
|
||||
codeql/javascript-all: '*'
|
||||
codeql/javascript-queries: '*'
|
||||
warnOnImplicitThis: true
|
||||
|
||||
15
javascript/ql/lib/BUILD.bazel
Normal file
15
javascript/ql/lib/BUILD.bazel
Normal file
@@ -0,0 +1,15 @@
|
||||
load("@rules_pkg//:mappings.bzl", "pkg_files")
|
||||
|
||||
package(default_visibility = ["//javascript:__pkg__"])
|
||||
|
||||
pkg_files(
|
||||
name = "dbscheme",
|
||||
srcs = ["semmlecode.javascript.dbscheme"],
|
||||
prefix = "javascript",
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = "dbscheme-stats",
|
||||
srcs = ["semmlecode.javascript.dbscheme.stats"],
|
||||
prefix = "javascript",
|
||||
)
|
||||
@@ -1,3 +1,102 @@
|
||||
## 0.8.6
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.8.5
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.8.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added models for the `sqlite` and `better-sqlite3` npm packages.
|
||||
* TypeScript 5.3 is now supported.
|
||||
|
||||
## 0.8.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.8.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.8.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The contents of `.jsp` files are now extracted, and any `<script>` tags inside these files will be parsed as JavaScript.
|
||||
* [Import attributes](https://github.com/tc39/proposal-import-attributes) are now supported in JavaScript code.
|
||||
Note that import attributes are an evolution of an earlier proposal called "import assertions", which were implemented in TypeScript 4.5.
|
||||
The QL library includes new predicates named `getImportAttributes()` that should be used in favor of the now deprecated `getImportAssertion()`;
|
||||
in addition, the `getImportAttributes()` method of the `DynamicImportExpr` has been renamed to `getImportOptions()`.
|
||||
* Deleted the deprecated `getAnImmediateUse`, `getAUse`, `getARhs`, and `getAValueReachingRhs` predicates from the `API::Node` class.
|
||||
* Deleted the deprecated `mayReferToParameter` predicate from `DataFlow::Node`.
|
||||
* Deleted the deprecated `getStaticMethod` and `getAStaticMethod` predicates from `DataFlow::ClassNode`.
|
||||
* Deleted the deprecated `isLibaryFile` predicate from `ClassifyFiles.qll`, use `isLibraryFile` instead.
|
||||
* Deleted many library models that were build on the AST. Use the new models that are build on the dataflow library instead.
|
||||
* Deleted the deprecated `semmle.javascript.security.performance` folder, use `semmle.javascript.security.regexp` instead.
|
||||
* Tagged template literals have been added to `DataFlow::CallNode`. This allows the analysis to find flow into functions called with a tagged template literal,
|
||||
and the arguments to a tagged template literal are part of the API-graph in `ApiGraphs.qll`.
|
||||
|
||||
## 0.8.0
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.7.5
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.7.4
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* Added support for TypeScript 5.2.
|
||||
|
||||
## 0.7.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.7.2
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added `log-injection` as a customizable sink kind for log injection.
|
||||
|
||||
## 0.7.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.7.0
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added models for the Webix Framework.
|
||||
|
||||
## 0.6.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.3
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* Added support for TypeScript 5.1.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Deleted many deprecated predicates and classes with uppercase `XML`, `JSON`, `URL`, `API`, etc. in their names. Use the PascalCased versions instead.
|
||||
* Deleted the deprecated `localTaintStep` predicate from `DataFlow.qll`.
|
||||
* Deleted the deprecated `stringStep`, and `localTaintStep` predicates from `TaintTracking.qll`.
|
||||
* Deleted many modules that started with a lowercase letter. Use the versions that start with an uppercase letter instead.
|
||||
* Deleted the deprecated `HtmlInjectionConfiguration` and `JQueryHtmlOrSelectorInjectionConfiguration` classes from `DomBasedXssQuery.qll`, use `Configuration` instead.
|
||||
* Deleted the deprecated `DefiningIdentifier` class and the `Definitions.qll` file it was in. Use `SsaDefinition` instead.
|
||||
* Deleted the deprecated `definitionReaches`, `localDefinitionReaches`, `getAPseudoDefinitionInput`, `nextDefAfter`, and `localDefinitionOverwrites` predicates from `DefUse.qll`.
|
||||
* Updated the following JavaScript sink kind names. Any custom data extensions that use these sink kinds will need to be updated accordingly in order to continue working.
|
||||
* `command-line-injection` to `command-injection`
|
||||
* `credentials[kind]` to `credentials-kind`
|
||||
* Added a support of sub modules in `node_modules`.
|
||||
|
||||
## 0.6.2
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: majorAnalysis
|
||||
---
|
||||
* Added support for TypeScript 5.1.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
|
||||
- Added a support of sub modules in `node_modules`.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Updated the following JavaScript sink kind names. Any custom data extensions that use these sink kinds will need to be updated accordingly in order to continue working.
|
||||
* `command-line-injection` to `command-injection`
|
||||
* `credentials[kind]` to `credentials-kind`
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The diagnostic query `js/diagnostics/successfully-extracted-files`, and therefore the Code Scanning UI measure of scanned JavaScript and TypeScript files, now considers any JavaScript and TypeScript file seen during extraction, even one with some errors, to be extracted / scanned.
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Deleted many deprecated predicates and classes with uppercase `CPU`, `TLD`, `SSA`, `ASM` etc. in their names. Use the PascalCased versions instead.
|
||||
* Deleted the deprecated `getMessageSuffix` predicates in `CodeInjectionCustomizations.qll`.
|
||||
* Deleted the deprecated `semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedData.qll` file.
|
||||
* Deleted the deprecated `getANonHtmlHeaderDefinition` and `nonHtmlContentTypeHeader` predicates from `ReflectedXssCustomizations.qll`.
|
||||
* Deleted the deprecated `semmle/javascript/security/OverlyLargeRangeQuery.qll`, `semmle/javascript/security/regexp/ExponentialBackTracking.qll`, `semmle/javascript/security/regexp/NfaUtils.qll`, and `semmle/javascript/security/regexp/NfaUtils.qll` files.
|
||||
* Deleted the deprecated `Expressions/TypoDatabase.qll` file.
|
||||
@@ -1,10 +1,19 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
## 0.6.3
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* Added support for TypeScript 5.1.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Deleted many deprecated predicates and classes with uppercase `XML`, `JSON`, `URL`, `API`, etc. in their names. Use the PascalCased versions instead.
|
||||
* Deleted the deprecated `localTaintStep` predicate from `DataFlow.qll`.
|
||||
* Deleted the deprecated `stringStep`, and `localTaintStep` predicates from `TaintTracking.qll`.
|
||||
* Deleted many modules that started with a lowercase letter. Use the versions that start with an uppercase letter instead.
|
||||
* Deleted the deprecated `HtmlInjectionConfiguration` and `JQueryHtmlOrSelectorInjectionConfiguration` classes from `DomBasedXssQuery.qll`, use `Configuration` instead.
|
||||
* Deleted the deprecated `DefiningIdentifier` class and the `Definitions.qll` file it was in. Use `SsaDefinition` instead.
|
||||
* Deleted the deprecated `definitionReaches`, `localDefinitionReaches`, `getAPseudoDefinitionInput`, `nextDefAfter`, and `localDefinitionOverwrites` predicates from `DefUse.qll`.
|
||||
* Deleted the deprecated `definitionReaches`, `localDefinitionReaches`, `getAPseudoDefinitionInput`, `nextDefAfter`, and `localDefinitionOverwrites` predicates from `DefUse.qll`.
|
||||
* Updated the following JavaScript sink kind names. Any custom data extensions that use these sink kinds will need to be updated accordingly in order to continue working.
|
||||
* `command-line-injection` to `command-injection`
|
||||
* `credentials[kind]` to `credentials-kind`
|
||||
* Added a support of sub modules in `node_modules`.
|
||||
3
javascript/ql/lib/change-notes/released/0.6.4.md
Normal file
3
javascript/ql/lib/change-notes/released/0.6.4.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.6.4
|
||||
|
||||
No user-facing changes.
|
||||
5
javascript/ql/lib/change-notes/released/0.7.0.md
Normal file
5
javascript/ql/lib/change-notes/released/0.7.0.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 0.7.0
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added models for the Webix Framework.
|
||||
3
javascript/ql/lib/change-notes/released/0.7.1.md
Normal file
3
javascript/ql/lib/change-notes/released/0.7.1.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.7.1
|
||||
|
||||
No user-facing changes.
|
||||
5
javascript/ql/lib/change-notes/released/0.7.2.md
Normal file
5
javascript/ql/lib/change-notes/released/0.7.2.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 0.7.2
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added `log-injection` as a customizable sink kind for log injection.
|
||||
3
javascript/ql/lib/change-notes/released/0.7.3.md
Normal file
3
javascript/ql/lib/change-notes/released/0.7.3.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.7.3
|
||||
|
||||
No user-facing changes.
|
||||
5
javascript/ql/lib/change-notes/released/0.7.4.md
Normal file
5
javascript/ql/lib/change-notes/released/0.7.4.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 0.7.4
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* Added support for TypeScript 5.2.
|
||||
3
javascript/ql/lib/change-notes/released/0.7.5.md
Normal file
3
javascript/ql/lib/change-notes/released/0.7.5.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.7.5
|
||||
|
||||
No user-facing changes.
|
||||
3
javascript/ql/lib/change-notes/released/0.8.0.md
Normal file
3
javascript/ql/lib/change-notes/released/0.8.0.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.8.0
|
||||
|
||||
No user-facing changes.
|
||||
17
javascript/ql/lib/change-notes/released/0.8.1.md
Normal file
17
javascript/ql/lib/change-notes/released/0.8.1.md
Normal file
@@ -0,0 +1,17 @@
|
||||
## 0.8.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The contents of `.jsp` files are now extracted, and any `<script>` tags inside these files will be parsed as JavaScript.
|
||||
* [Import attributes](https://github.com/tc39/proposal-import-attributes) are now supported in JavaScript code.
|
||||
Note that import attributes are an evolution of an earlier proposal called "import assertions", which were implemented in TypeScript 4.5.
|
||||
The QL library includes new predicates named `getImportAttributes()` that should be used in favor of the now deprecated `getImportAssertion()`;
|
||||
in addition, the `getImportAttributes()` method of the `DynamicImportExpr` has been renamed to `getImportOptions()`.
|
||||
* Deleted the deprecated `getAnImmediateUse`, `getAUse`, `getARhs`, and `getAValueReachingRhs` predicates from the `API::Node` class.
|
||||
* Deleted the deprecated `mayReferToParameter` predicate from `DataFlow::Node`.
|
||||
* Deleted the deprecated `getStaticMethod` and `getAStaticMethod` predicates from `DataFlow::ClassNode`.
|
||||
* Deleted the deprecated `isLibaryFile` predicate from `ClassifyFiles.qll`, use `isLibraryFile` instead.
|
||||
* Deleted many library models that were build on the AST. Use the new models that are build on the dataflow library instead.
|
||||
* Deleted the deprecated `semmle.javascript.security.performance` folder, use `semmle.javascript.security.regexp` instead.
|
||||
* Tagged template literals have been added to `DataFlow::CallNode`. This allows the analysis to find flow into functions called with a tagged template literal,
|
||||
and the arguments to a tagged template literal are part of the API-graph in `ApiGraphs.qll`.
|
||||
3
javascript/ql/lib/change-notes/released/0.8.2.md
Normal file
3
javascript/ql/lib/change-notes/released/0.8.2.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.8.2
|
||||
|
||||
No user-facing changes.
|
||||
3
javascript/ql/lib/change-notes/released/0.8.3.md
Normal file
3
javascript/ql/lib/change-notes/released/0.8.3.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.8.3
|
||||
|
||||
No user-facing changes.
|
||||
6
javascript/ql/lib/change-notes/released/0.8.4.md
Normal file
6
javascript/ql/lib/change-notes/released/0.8.4.md
Normal file
@@ -0,0 +1,6 @@
|
||||
## 0.8.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added models for the `sqlite` and `better-sqlite3` npm packages.
|
||||
* TypeScript 5.3 is now supported.
|
||||
3
javascript/ql/lib/change-notes/released/0.8.5.md
Normal file
3
javascript/ql/lib/change-notes/released/0.8.5.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.8.5
|
||||
|
||||
No user-facing changes.
|
||||
3
javascript/ql/lib/change-notes/released/0.8.6.md
Normal file
3
javascript/ql/lib/change-notes/released/0.8.6.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.8.6
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.6.2
|
||||
lastReleaseVersion: 0.8.6
|
||||
|
||||
@@ -134,6 +134,7 @@ import semmle.javascript.frameworks.TrustedTypes
|
||||
import semmle.javascript.frameworks.UriLibraries
|
||||
import semmle.javascript.frameworks.Vue
|
||||
import semmle.javascript.frameworks.Vuex
|
||||
import semmle.javascript.frameworks.Webix
|
||||
import semmle.javascript.frameworks.WebSocket
|
||||
import semmle.javascript.frameworks.XmlParsers
|
||||
import semmle.javascript.frameworks.xUnit
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
name: codeql/javascript-all
|
||||
version: 0.6.3-dev
|
||||
version: 0.8.7-dev
|
||||
groups: javascript
|
||||
dbscheme: semmlecode.javascript.dbscheme
|
||||
extractor: javascript
|
||||
library: true
|
||||
upgrades: upgrades
|
||||
dependencies:
|
||||
codeql/dataflow: ${workspace}
|
||||
codeql/mad: ${workspace}
|
||||
codeql/regex: ${workspace}
|
||||
codeql/tutorial: ${workspace}
|
||||
|
||||
@@ -7,6 +7,34 @@ import javascript
|
||||
private import semmle.javascript.internal.CachedStages
|
||||
private import Expressions.ExprHasNoEffect
|
||||
|
||||
/**
|
||||
* Companion module to the `AmdModuleDefinition` class.
|
||||
*/
|
||||
module AmdModuleDefinition {
|
||||
/**
|
||||
* A class that can be extended to treat calls as instances of `AmdModuleDefinition`.
|
||||
*
|
||||
* Subclasses should not depend on imports or `DataFlow::Node`.
|
||||
*/
|
||||
abstract class Range extends CallExpr { }
|
||||
|
||||
private class DefaultRange extends Range {
|
||||
DefaultRange() {
|
||||
inVoidContext(this) and
|
||||
this.getCallee().(GlobalVarAccess).getName() = "define" and
|
||||
exists(int n | n = this.getNumArgument() |
|
||||
n = 1
|
||||
or
|
||||
n = 2 and this.getArgument(0) instanceof ArrayExpr
|
||||
or
|
||||
n = 3 and
|
||||
this.getArgument(0) instanceof ConstantString and
|
||||
this.getArgument(1) instanceof ArrayExpr
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An AMD `define` call.
|
||||
*
|
||||
@@ -25,21 +53,7 @@ private import Expressions.ExprHasNoEffect
|
||||
* where the first argument is the module name, the second argument an
|
||||
* array of dependencies, and the third argument a factory method or object.
|
||||
*/
|
||||
class AmdModuleDefinition extends CallExpr {
|
||||
AmdModuleDefinition() {
|
||||
inVoidContext(this) and
|
||||
this.getCallee().(GlobalVarAccess).getName() = "define" and
|
||||
exists(int n | n = this.getNumArgument() |
|
||||
n = 1
|
||||
or
|
||||
n = 2 and this.getArgument(0) instanceof ArrayExpr
|
||||
or
|
||||
n = 3 and
|
||||
this.getArgument(0) instanceof ConstantString and
|
||||
this.getArgument(1) instanceof ArrayExpr
|
||||
)
|
||||
}
|
||||
|
||||
class AmdModuleDefinition extends CallExpr instanceof AmdModuleDefinition::Range {
|
||||
/** Gets the array of module dependencies, if any. */
|
||||
ArrayExpr getDependencies() {
|
||||
result = this.getArgument(0) or
|
||||
|
||||
@@ -153,12 +153,6 @@ module API {
|
||||
*/
|
||||
DataFlow::SourceNode asSource() { Impl::use(this, result) }
|
||||
|
||||
/** DEPRECATED. This predicate has been renamed to `asSource`. */
|
||||
deprecated DataFlow::SourceNode getAnImmediateUse() { result = this.asSource() }
|
||||
|
||||
/** DEPRECATED. This predicate has been renamed to `getAValueReachableFromSource`. */
|
||||
deprecated DataFlow::Node getAUse() { result = this.getAValueReachableFromSource() }
|
||||
|
||||
/**
|
||||
* Gets a call to the function represented by this API component.
|
||||
*/
|
||||
@@ -212,12 +206,6 @@ module API {
|
||||
*/
|
||||
DataFlow::Node getAValueReachingSink() { result = Impl::trackDefNode(this.asSink()) }
|
||||
|
||||
/** DEPRECATED. This predicate has been renamed to `asSink`. */
|
||||
deprecated DataFlow::Node getARhs() { result = this.asSink() }
|
||||
|
||||
/** DEPRECATED. This predicate has been renamed to `getAValueReachingSink`. */
|
||||
deprecated DataFlow::Node getAValueReachingRhs() { result = this.getAValueReachingSink() }
|
||||
|
||||
/**
|
||||
* Gets a node representing member `m` of this API component.
|
||||
*
|
||||
@@ -622,12 +610,6 @@ module API {
|
||||
bindingset[this]
|
||||
EntryPoint() { any() }
|
||||
|
||||
/** DEPRECATED. This predicate has been renamed to `getASource`. */
|
||||
deprecated DataFlow::SourceNode getAUse() { none() }
|
||||
|
||||
/** DEPRECATED. This predicate has been renamed to `getASink`. */
|
||||
deprecated DataFlow::SourceNode getARhs() { none() }
|
||||
|
||||
/** Gets a data-flow node where a value enters the current codebase through this entry-point. */
|
||||
DataFlow::SourceNode getASource() { none() }
|
||||
|
||||
|
||||
@@ -91,14 +91,27 @@ class ImportDeclaration extends Stmt, Import, @import_declaration {
|
||||
override PathExpr getImportedPath() { result = this.getChildExpr(-1) }
|
||||
|
||||
/**
|
||||
* Gets the object literal passed as part of the `assert` clause in this import declaration.
|
||||
* Gets the object literal passed as part of the `with` (or `assert`) clause in this import declaration.
|
||||
*
|
||||
* For example, this gets the `{ type: "json" }` object literal in the following:
|
||||
* ```js
|
||||
* import foo from "foo" with { type: "json" };
|
||||
* import foo from "foo" assert { type: "json" };
|
||||
* ```
|
||||
*/
|
||||
ObjectExpr getImportAssertion() { result = this.getChildExpr(-10) }
|
||||
ObjectExpr getImportAttributes() { result = this.getChildExpr(-10) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getImportAttributes` instead.
|
||||
* Gets the object literal passed as part of the `with` (or `assert`) clause in this import declaration.
|
||||
*
|
||||
* For example, this gets the `{ type: "json" }` object literal in the following:
|
||||
* ```js
|
||||
* import foo from "foo" with { type: "json" };
|
||||
* import foo from "foo" assert { type: "json" };
|
||||
* ```
|
||||
*/
|
||||
deprecated ObjectExpr getImportAssertion() { result = this.getImportAttributes() }
|
||||
|
||||
/** Gets the `i`th import specifier of this import declaration. */
|
||||
ImportSpecifier getSpecifier(int i) { result = this.getChildExpr(i) }
|
||||
@@ -322,17 +335,33 @@ abstract class ExportDeclaration extends Stmt, @export_declaration {
|
||||
override string getAPrimaryQlClass() { result = "ExportDeclaration" }
|
||||
|
||||
/**
|
||||
* Gets the object literal passed as part of the `assert` clause, if this is
|
||||
* Gets the object literal passed as part of the `with` (or `assert`) clause, if this is
|
||||
* a re-export declaration.
|
||||
*
|
||||
* For example, this gets the `{ type: "json" }` expression in each of the following:
|
||||
* ```js
|
||||
* export { x } from 'foo' assert { type: "json" };
|
||||
* export { x } from 'foo' with { type: "json" };
|
||||
* export * from 'foo' with { type: "json" };
|
||||
* export * as x from 'foo' with { type: "json" };
|
||||
* export * from 'foo' assert { type: "json" };
|
||||
* export * as x from 'foo' assert { type: "json" };
|
||||
* ```
|
||||
*/
|
||||
ObjectExpr getImportAssertion() { result = this.getChildExpr(-10) }
|
||||
ObjectExpr getImportAttributes() { result = this.getChildExpr(-10) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getImportAttributes` instead.
|
||||
* Gets the object literal passed as part of the `with` (or `assert`) clause, if this is
|
||||
* a re-export declaration.
|
||||
*
|
||||
* For example, this gets the `{ type: "json" }` expression in each of the following:
|
||||
* ```js
|
||||
* export { x } from 'foo' with { type: "json" };
|
||||
* export * from 'foo' with { type: "json" };
|
||||
* export * as x from 'foo' with { type: "json" };
|
||||
* export * from 'foo' assert { type: "json" };
|
||||
* ```
|
||||
*/
|
||||
deprecated ObjectExpr getImportAssertion() { result = this.getImportAttributes() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2807,7 +2807,7 @@ class FunctionBindExpr extends @bind_expr, Expr {
|
||||
*
|
||||
* ```
|
||||
* import("fs")
|
||||
* import("foo", { assert: { type: "json" }})
|
||||
* import("foo", { with: { type: "json" }})
|
||||
* ```
|
||||
*/
|
||||
class DynamicImportExpr extends @dynamic_import, Expr, Import {
|
||||
@@ -2823,12 +2823,23 @@ class DynamicImportExpr extends @dynamic_import, Expr, Import {
|
||||
/**
|
||||
* Gets the second "argument" to the import expression, that is, the `Y` in `import(X, Y)`.
|
||||
*
|
||||
* For example, gets the `{ assert: { type: "json" }}` expression in the following:
|
||||
* For example, gets the `{ with: { type: "json" }}` expression in the following:
|
||||
* ```js
|
||||
* import('foo', { assert: { type: "json" }})
|
||||
* import('foo', { with: { type: "json" }})
|
||||
* ```
|
||||
*/
|
||||
Expr getImportAttributes() { result = this.getChildExpr(1) }
|
||||
Expr getImportOptions() { result = this.getChildExpr(1) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getImportOptions` instead.
|
||||
* Gets the second "argument" to the import expression, that is, the `Y` in `import(X, Y)`.
|
||||
*
|
||||
* For example, gets the `{ with: { type: "json" }}` expression in the following:
|
||||
* ```js
|
||||
* import('foo', { with: { type: "json" }})
|
||||
* ```
|
||||
*/
|
||||
deprecated Expr getImportAttributes() { result = this.getImportOptions() }
|
||||
|
||||
override Module getEnclosingModule() { result = this.getTopLevel() }
|
||||
|
||||
|
||||
@@ -96,7 +96,10 @@ private class ExtendCallDeep extends ExtendCall {
|
||||
callee = LodashUnderscore::member("merge") or
|
||||
callee = LodashUnderscore::member("mergeWith") or
|
||||
callee = LodashUnderscore::member("defaultsDeep") or
|
||||
callee = AngularJS::angular().getAPropertyRead("merge")
|
||||
callee = AngularJS::angular().getAPropertyRead("merge") or
|
||||
callee =
|
||||
[DataFlow::moduleImport("webix"), DataFlow::globalVarRef("webix")]
|
||||
.getAPropertyRead(["extend", "copy"])
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,166 +2,34 @@
|
||||
|
||||
import javascript
|
||||
private import NodeModuleResolutionImpl
|
||||
private import codeql.util.FileSystem
|
||||
|
||||
/** A file or folder. */
|
||||
abstract class Container extends @container {
|
||||
/**
|
||||
* Gets the absolute, canonical path of this container, using forward slashes
|
||||
* as path separator.
|
||||
*
|
||||
* The path starts with a _root prefix_ followed by zero or more _path
|
||||
* segments_ separated by forward slashes.
|
||||
*
|
||||
* The root prefix is of one of the following forms:
|
||||
*
|
||||
* 1. A single forward slash `/` (Unix-style)
|
||||
* 2. An upper-case drive letter followed by a colon and a forward slash,
|
||||
* such as `C:/` (Windows-style)
|
||||
* 3. Two forward slashes, a computer name, and then another forward slash,
|
||||
* such as `//FileServer/` (UNC-style)
|
||||
*
|
||||
* Path segments are never empty (that is, absolute paths never contain two
|
||||
* contiguous slashes, except as part of a UNC-style root prefix). Also, path
|
||||
* segments never contain forward slashes, and no path segment is of the
|
||||
* form `.` (one dot) or `..` (two dots).
|
||||
*
|
||||
* Note that an absolute path never ends with a forward slash, except if it is
|
||||
* a bare root prefix, that is, the path has no path segments. A container
|
||||
* whose absolute path has no segments is always a `Folder`, not a `File`.
|
||||
*/
|
||||
abstract string getAbsolutePath();
|
||||
private module FsInput implements InputSig {
|
||||
abstract class ContainerBase extends @container {
|
||||
abstract string getAbsolutePath();
|
||||
|
||||
/**
|
||||
* Gets a URL representing the location of this container.
|
||||
*
|
||||
* For more information see [Providing URLs](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls).
|
||||
*/
|
||||
abstract string getURL();
|
||||
ContainerBase getParentContainer() { containerparent(result, this) }
|
||||
|
||||
/**
|
||||
* Gets the relative path of this file or folder from the root folder of the
|
||||
* analyzed source location. The relative path of the root folder itself is
|
||||
* the empty string.
|
||||
*
|
||||
* This has no result if the container is outside the source root, that is,
|
||||
* if the root folder is not a reflexive, transitive parent of this container.
|
||||
*/
|
||||
string getRelativePath() {
|
||||
exists(string absPath, string pref |
|
||||
absPath = this.getAbsolutePath() and sourceLocationPrefix(pref)
|
||||
|
|
||||
absPath = pref and result = ""
|
||||
or
|
||||
absPath = pref.regexpReplaceAll("/$", "") + "/" + result and
|
||||
not result.matches("/%")
|
||||
)
|
||||
string toString() { result = this.getAbsolutePath() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the base name of this container including extension, that is, the last
|
||||
* segment of its absolute path, or the empty string if it has no segments.
|
||||
*
|
||||
* Here are some examples of absolute paths and the corresponding base names
|
||||
* (surrounded with quotes to avoid ambiguity):
|
||||
*
|
||||
* <table border="1">
|
||||
* <tr><th>Absolute path</th><th>Base name</th></tr>
|
||||
* <tr><td>"/tmp/tst.js"</td><td>"tst.js"</td></tr>
|
||||
* <tr><td>"C:/Program Files (x86)"</td><td>"Program Files (x86)"</td></tr>
|
||||
* <tr><td>"/"</td><td>""</td></tr>
|
||||
* <tr><td>"C:/"</td><td>""</td></tr>
|
||||
* <tr><td>"D:/"</td><td>""</td></tr>
|
||||
* <tr><td>"//FileServer/"</td><td>""</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
string getBaseName() {
|
||||
result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(\\.([^.]*))?)", 1)
|
||||
class FolderBase extends ContainerBase, @folder {
|
||||
override string getAbsolutePath() { folders(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the extension of this container, that is, the suffix of its base name
|
||||
* after the last dot character, if any.
|
||||
*
|
||||
* In particular,
|
||||
*
|
||||
* - if the name does not include a dot, there is no extension, so this
|
||||
* predicate has no result;
|
||||
* - if the name ends in a dot, the extension is the empty string;
|
||||
* - if the name contains multiple dots, the extension follows the last dot.
|
||||
*
|
||||
* Here are some examples of absolute paths and the corresponding extensions
|
||||
* (surrounded with quotes to avoid ambiguity):
|
||||
*
|
||||
* <table border="1">
|
||||
* <tr><th>Absolute path</th><th>Extension</th></tr>
|
||||
* <tr><td>"/tmp/tst.js"</td><td>"js"</td></tr>
|
||||
* <tr><td>"/tmp/.classpath"</td><td>"classpath"</td></tr>
|
||||
* <tr><td>"/bin/bash"</td><td>not defined</td></tr>
|
||||
* <tr><td>"/tmp/tst2."</td><td>""</td></tr>
|
||||
* <tr><td>"/tmp/x.tar.gz"</td><td>"gz"</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
string getExtension() {
|
||||
result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(\\.([^.]*))?)", 4)
|
||||
class FileBase extends ContainerBase, @file {
|
||||
override string getAbsolutePath() { files(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the stem of this container, that is, the prefix of its base name up to
|
||||
* (but not including) the last dot character if there is one, or the entire
|
||||
* base name if there is not.
|
||||
*
|
||||
* Here are some examples of absolute paths and the corresponding stems
|
||||
* (surrounded with quotes to avoid ambiguity):
|
||||
*
|
||||
* <table border="1">
|
||||
* <tr><th>Absolute path</th><th>Stem</th></tr>
|
||||
* <tr><td>"/tmp/tst.js"</td><td>"tst"</td></tr>
|
||||
* <tr><td>"/tmp/.classpath"</td><td>""</td></tr>
|
||||
* <tr><td>"/bin/bash"</td><td>"bash"</td></tr>
|
||||
* <tr><td>"/tmp/tst2."</td><td>"tst2"</td></tr>
|
||||
* <tr><td>"/tmp/x.tar.gz"</td><td>"x.tar"</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
string getStem() {
|
||||
result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(\\.([^.]*))?)", 2)
|
||||
}
|
||||
|
||||
/** Gets the parent container of this file or folder, if any. */
|
||||
Container getParentContainer() { containerparent(result, this) }
|
||||
|
||||
/** Gets a file or sub-folder in this container. */
|
||||
Container getAChildContainer() { this = result.getParentContainer() }
|
||||
|
||||
/** Gets a file in this container. */
|
||||
File getAFile() { result = this.getAChildContainer() }
|
||||
|
||||
/** Gets the file in this container that has the given `baseName`, if any. */
|
||||
File getFile(string baseName) {
|
||||
result = this.getAFile() and
|
||||
result.getBaseName() = baseName
|
||||
}
|
||||
|
||||
/** Gets a sub-folder in this container. */
|
||||
Folder getAFolder() { result = this.getAChildContainer() }
|
||||
|
||||
/** Gets the sub-folder in this container that has the given `baseName`, if any. */
|
||||
Folder getFolder(string baseName) {
|
||||
result = this.getAFolder() and
|
||||
result.getBaseName() = baseName
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a textual representation of the path of this container.
|
||||
*
|
||||
* This is the absolute path of the container.
|
||||
*/
|
||||
string toString() { result = this.getAbsolutePath() }
|
||||
predicate hasSourceLocationPrefix = sourceLocationPrefix/1;
|
||||
}
|
||||
|
||||
/** A folder. */
|
||||
class Folder extends Container, @folder {
|
||||
override string getAbsolutePath() { folders(this, result) }
|
||||
private module Impl = Make<FsInput>;
|
||||
|
||||
class Container = Impl::Container;
|
||||
|
||||
/** A folder. */
|
||||
class Folder extends Container, Impl::Folder {
|
||||
/** Gets the file or subfolder in this folder that has the given `name`, if any. */
|
||||
Container getChildContainer(string name) {
|
||||
result = this.getAChildContainer() and
|
||||
@@ -206,13 +74,10 @@ class Folder extends Container, @folder {
|
||||
|
||||
/** Gets a subfolder contained in this folder. */
|
||||
Folder getASubFolder() { result = this.getAChildContainer() }
|
||||
|
||||
/** Gets the URL of this folder. */
|
||||
override string getURL() { result = "folder://" + this.getAbsolutePath() }
|
||||
}
|
||||
|
||||
/** A file. */
|
||||
class File extends Container, @file {
|
||||
class File extends Container, Impl::File {
|
||||
/**
|
||||
* Gets the location of this file.
|
||||
*
|
||||
@@ -220,8 +85,6 @@ class File extends Container, @file {
|
||||
*/
|
||||
Location getLocation() { hasLocation(this, result) }
|
||||
|
||||
override string getAbsolutePath() { files(this, result) }
|
||||
|
||||
/** Gets the number of lines in this file. */
|
||||
int getNumberOfLines() { result = sum(int loc | numlines(this, loc, _, _) | loc) }
|
||||
|
||||
@@ -234,9 +97,6 @@ class File extends Container, @file {
|
||||
/** Gets a toplevel piece of JavaScript code in this file. */
|
||||
TopLevel getATopLevel() { result.getFile() = this }
|
||||
|
||||
/** Gets the URL of this file. */
|
||||
override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }
|
||||
|
||||
/**
|
||||
* Holds if line number `lineno` of this file is indented to depth `d`
|
||||
* using character `c`.
|
||||
|
||||
@@ -69,7 +69,6 @@ module InclusionTest {
|
||||
inner.getContainerNode().getALocalSource() = DataFlow::parameterNode(callee.getAParameter())
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override DataFlow::Node getContainerNode() {
|
||||
exists(int arg |
|
||||
inner.getContainerNode().getALocalSource() =
|
||||
@@ -78,7 +77,6 @@ module InclusionTest {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override DataFlow::Node getContainedNode() {
|
||||
exists(int arg |
|
||||
inner.getContainedNode().getALocalSource() =
|
||||
|
||||
@@ -59,9 +59,6 @@ class Json2CsvTaintStep extends TaintTracking::SharedTaintStep {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for Json2CsvTaintStep */
|
||||
deprecated class JSON2CSVTaintStep = Json2CsvTaintStep;
|
||||
|
||||
/**
|
||||
* A step through the [`prettyjson`](https://www.npmjs.com/package/prettyjson) library.
|
||||
* This is not quite a `JSON.stringify` call, as it e.g. does not wrap keys in double quotes.
|
||||
|
||||
@@ -191,9 +191,6 @@ class PackageJson extends JsonObject {
|
||||
not result.matches("!%")
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for getWhitelistedCpu */
|
||||
deprecated string getWhitelistedCPU() { result = this.getWhitelistedCpu() }
|
||||
|
||||
/** Gets a platform not supported by this package. */
|
||||
string getBlacklistedCpu() {
|
||||
exists(string str | str = this.getCPUs().getElementStringValue(_) |
|
||||
@@ -201,9 +198,6 @@ class PackageJson extends JsonObject {
|
||||
)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for getBlacklistedCpu */
|
||||
deprecated string getBlacklistedCPU() { result = this.getBlacklistedCpu() }
|
||||
|
||||
/** Holds if this package prefers to be installed globally. */
|
||||
predicate isPreferGlobal() { this.getPropValue("preferGlobal").(JsonBoolean).getValue() = "true" }
|
||||
|
||||
|
||||
@@ -380,6 +380,25 @@ private class PathExprString extends PathString {
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlow::Node getAPathExprAlias(PathExpr expr) {
|
||||
result.getImmediatePredecessor().asExpr() = expr
|
||||
or
|
||||
result.getImmediatePredecessor() = getAPathExprAlias(expr)
|
||||
}
|
||||
|
||||
private class PathExprFromAlias extends PathExpr {
|
||||
private PathExpr other;
|
||||
|
||||
PathExprFromAlias() { this = getAPathExprAlias(other).asExpr() }
|
||||
|
||||
override string getValue() { result = other.getValue() }
|
||||
|
||||
override Folder getAdditionalSearchRoot(int priority) {
|
||||
result = other.getAdditionalSearchRoot(priority)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A path expression of the form `p + q`, where both `p` and `q`
|
||||
* are path expressions.
|
||||
@@ -413,6 +432,9 @@ private class ConcatPath extends PathExpr {
|
||||
* Examples include arguments to the CommonJS `require` function or AMD dependency arguments.
|
||||
*/
|
||||
abstract class PathExprCandidate extends Expr {
|
||||
pragma[nomagic]
|
||||
private Expr getAPart1() { result = this or result = this.getAPart().getAChildExpr() }
|
||||
|
||||
/**
|
||||
* Gets an expression that is nested inside this expression.
|
||||
*
|
||||
@@ -421,5 +443,5 @@ abstract class PathExprCandidate extends Expr {
|
||||
* `ConstantString`s).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
Expr getAPart() { result = this or result = this.getAPart().getAChildExpr() }
|
||||
Expr getAPart() { result = this.getAPart1().flow().getImmediatePredecessor*().asExpr() }
|
||||
}
|
||||
|
||||
@@ -83,7 +83,8 @@ private newtype TPrintAstNode =
|
||||
shouldPrint(term, _) and
|
||||
term.isUsedAsRegExp() and
|
||||
any(RegExpLiteral lit).getRoot() = term.getRootTerm()
|
||||
}
|
||||
} or
|
||||
TXmlAttributeNode(XmlAttribute attr) { shouldPrint(attr, _) and not isNotNeeded(attr) }
|
||||
|
||||
/**
|
||||
* A node in the output tree.
|
||||
@@ -246,13 +247,15 @@ private module PrintJavaScript {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets "var" or "const" or "let" depending on what type of declaration `decl` is.
|
||||
* Gets "var" or "const" or "let" or "using" depending on what type of declaration `decl` is.
|
||||
*/
|
||||
private string getDeclarationKeyword(DeclStmt decl) {
|
||||
decl instanceof VarDeclStmt and result = "var"
|
||||
or
|
||||
decl instanceof ConstDeclStmt and result = "const"
|
||||
or
|
||||
decl instanceof UsingDeclStmt and result = "using"
|
||||
or
|
||||
decl instanceof LetStmt and result = "let"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1036,15 +1036,6 @@ deprecated module RegExpPatterns {
|
||||
// according to ranking by http://google.com/search?q=site:.<<TLD>>
|
||||
result = "(?:com|org|edu|gov|uk|net|io)(?![a-z0-9])"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a pattern that matches common top-level domain names in lower case.
|
||||
* DEPRECATED: use `getACommonTld` instead
|
||||
*/
|
||||
deprecated predicate commonTld = getACommonTld/0;
|
||||
|
||||
/** DEPRECATED: Alias for commonTld */
|
||||
deprecated predicate commonTLD = commonTld/0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -758,6 +758,3 @@ module Ssa {
|
||||
/** Gets the SSA variable corresponding to `d`. */
|
||||
SsaVariable variable(VarDef d) { result.getDefinition() = definition(d) }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for Ssa */
|
||||
deprecated module SSA = Ssa;
|
||||
|
||||
@@ -295,9 +295,6 @@ class AsmJSDirective extends KnownDirective {
|
||||
AsmJSDirective() { this.getDirectiveText() = "use asm" }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for AsmJSDirective */
|
||||
deprecated class ASMJSDirective = AsmJSDirective;
|
||||
|
||||
/**
|
||||
* A Babel directive.
|
||||
*
|
||||
@@ -1041,6 +1038,17 @@ class VarDeclStmt extends @var_decl_stmt, DeclStmt { }
|
||||
*/
|
||||
class ConstDeclStmt extends @const_decl_stmt, DeclStmt { }
|
||||
|
||||
/**
|
||||
* A `using` declaration statement.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* using file = new TextFile("file.txt");
|
||||
* ```
|
||||
*/
|
||||
class UsingDeclStmt extends @using_decl_stmt, DeclStmt { }
|
||||
|
||||
/**
|
||||
* A `let` declaration statement.
|
||||
*
|
||||
|
||||
@@ -67,7 +67,6 @@ module StringOps {
|
||||
inner.getSubstring().getALocalSource().getEnclosingExpr() = callee.getAParameter()
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override DataFlow::Node getBaseString() {
|
||||
exists(int arg |
|
||||
inner.getBaseString().getALocalSource().getEnclosingExpr() = callee.getParameter(arg) and
|
||||
@@ -75,7 +74,6 @@ module StringOps {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override DataFlow::Node getSubstring() {
|
||||
exists(int arg |
|
||||
inner.getSubstring().getALocalSource().getEnclosingExpr() = callee.getParameter(arg) and
|
||||
@@ -294,7 +292,6 @@ module StringOps {
|
||||
inner.getSubstring().getALocalSource().getEnclosingExpr() = callee.getAParameter()
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override DataFlow::Node getBaseString() {
|
||||
exists(int arg |
|
||||
inner.getBaseString().getALocalSource().getEnclosingExpr() = callee.getParameter(arg) and
|
||||
@@ -302,7 +299,6 @@ module StringOps {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override DataFlow::Node getSubstring() {
|
||||
exists(int arg |
|
||||
inner.getSubstring().getALocalSource().getEnclosingExpr() = callee.getParameter(arg) and
|
||||
|
||||
@@ -32,9 +32,6 @@ class XmlLocatable extends @xmllocatable, TXmlLocatable {
|
||||
string toString() { none() } // overridden in subclasses
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlLocatable */
|
||||
deprecated class XMLLocatable = XmlLocatable;
|
||||
|
||||
/**
|
||||
* An `XmlParent` is either an `XmlElement` or an `XmlFile`,
|
||||
* both of which can contain other elements.
|
||||
@@ -95,9 +92,6 @@ class XmlParent extends @xmlparent {
|
||||
string toString() { result = this.getName() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlParent */
|
||||
deprecated class XMLParent = XmlParent;
|
||||
|
||||
/** An XML file. */
|
||||
class XmlFile extends XmlParent, File {
|
||||
XmlFile() { xmlEncoding(this, _) }
|
||||
@@ -119,14 +113,8 @@ class XmlFile extends XmlParent, File {
|
||||
|
||||
/** Gets a DTD associated with this XML file. */
|
||||
XmlDtd getADtd() { xmlDTDs(result, _, _, _, this) }
|
||||
|
||||
/** DEPRECATED: Alias for getADtd */
|
||||
deprecated XmlDtd getADTD() { result = this.getADtd() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlFile */
|
||||
deprecated class XMLFile = XmlFile;
|
||||
|
||||
/**
|
||||
* An XML document type definition (DTD).
|
||||
*
|
||||
@@ -163,9 +151,6 @@ class XmlDtd extends XmlLocatable, @xmldtd {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlDtd */
|
||||
deprecated class XMLDTD = XmlDtd;
|
||||
|
||||
/**
|
||||
* An XML element in an XML file.
|
||||
*
|
||||
@@ -221,9 +206,6 @@ class XmlElement extends @xmlelement, XmlParent, XmlLocatable {
|
||||
override string toString() { result = this.getName() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlElement */
|
||||
deprecated class XMLElement = XmlElement;
|
||||
|
||||
/**
|
||||
* An attribute that occurs inside an XML element.
|
||||
*
|
||||
@@ -254,9 +236,6 @@ class XmlAttribute extends @xmlattribute, XmlLocatable {
|
||||
override string toString() { result = this.getName() + "=" + this.getValue() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlAttribute */
|
||||
deprecated class XMLAttribute = XmlAttribute;
|
||||
|
||||
/**
|
||||
* A namespace used in an XML file.
|
||||
*
|
||||
@@ -273,9 +252,6 @@ class XmlNamespace extends XmlLocatable, @xmlnamespace {
|
||||
/** Gets the URI of this namespace. */
|
||||
string getUri() { xmlNs(this, _, result, _) }
|
||||
|
||||
/** DEPRECATED: Alias for getUri */
|
||||
deprecated string getURI() { result = this.getUri() }
|
||||
|
||||
/** Holds if this namespace has no prefix. */
|
||||
predicate isDefault() { this.getPrefix() = "" }
|
||||
|
||||
@@ -286,9 +262,6 @@ class XmlNamespace extends XmlLocatable, @xmlnamespace {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlNamespace */
|
||||
deprecated class XMLNamespace = XmlNamespace;
|
||||
|
||||
/**
|
||||
* A comment in an XML file.
|
||||
*
|
||||
@@ -309,9 +282,6 @@ class XmlComment extends @xmlcomment, XmlLocatable {
|
||||
override string toString() { result = this.getText() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlComment */
|
||||
deprecated class XMLComment = XmlComment;
|
||||
|
||||
/**
|
||||
* A sequence of characters that occurs between opening and
|
||||
* closing tags of an XML element, excluding other elements.
|
||||
@@ -335,6 +305,3 @@ class XmlCharacters extends @xmlcharacters, XmlLocatable {
|
||||
/** Gets a printable representation of this XML character sequence. */
|
||||
override string toString() { result = this.getCharacters() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlCharacters */
|
||||
deprecated class XMLCharacters = XmlCharacters;
|
||||
|
||||
@@ -65,48 +65,3 @@ deprecated class YAMLValue = YamlValue;
|
||||
|
||||
/** DEPRECATED: Alias for YamlScalar */
|
||||
deprecated class YAMLScalar = YamlScalar;
|
||||
|
||||
/** DEPRECATED: Alias for YamlInteger */
|
||||
deprecated class YAMLInteger = YamlInteger;
|
||||
|
||||
/** DEPRECATED: Alias for YamlFloat */
|
||||
deprecated class YAMLFloat = YamlFloat;
|
||||
|
||||
/** DEPRECATED: Alias for YamlTimestamp */
|
||||
deprecated class YAMLTimestamp = YamlTimestamp;
|
||||
|
||||
/** DEPRECATED: Alias for YamlBool */
|
||||
deprecated class YAMLBool = YamlBool;
|
||||
|
||||
/** DEPRECATED: Alias for YamlNull */
|
||||
deprecated class YAMLNull = YamlNull;
|
||||
|
||||
/** DEPRECATED: Alias for YamlString */
|
||||
deprecated class YAMLString = YamlString;
|
||||
|
||||
/** DEPRECATED: Alias for YamlMergeKey */
|
||||
deprecated class YAMLMergeKey = YamlMergeKey;
|
||||
|
||||
/** DEPRECATED: Alias for YamlInclude */
|
||||
deprecated class YAMLInclude = YamlInclude;
|
||||
|
||||
/** DEPRECATED: Alias for YamlCollection */
|
||||
deprecated class YAMLCollection = YamlCollection;
|
||||
|
||||
/** DEPRECATED: Alias for YamlMapping */
|
||||
deprecated class YAMLMapping = YamlMapping;
|
||||
|
||||
/** DEPRECATED: Alias for YamlSequence */
|
||||
deprecated class YAMLSequence = YamlSequence;
|
||||
|
||||
/** DEPRECATED: Alias for YamlAliasNode */
|
||||
deprecated class YAMLAliasNode = YamlAliasNode;
|
||||
|
||||
/** DEPRECATED: Alias for YamlDocument */
|
||||
deprecated class YAMLDocument = YamlDocument;
|
||||
|
||||
/** DEPRECATED: Alias for YamlParseError */
|
||||
deprecated class YAMLParseError = YamlParseError;
|
||||
|
||||
/** DEPRECATED: Alias for YamlMappingLikeNode */
|
||||
deprecated class YAMLMappingLikeNode = YamlMappingLikeNode;
|
||||
|
||||
@@ -71,7 +71,6 @@
|
||||
private import javascript
|
||||
private import internal.FlowSteps
|
||||
private import internal.AccessPaths
|
||||
private import internal.CallGraphs
|
||||
private import semmle.javascript.Unit
|
||||
private import semmle.javascript.internal.CachedStages
|
||||
|
||||
@@ -166,6 +165,26 @@ abstract class Configuration extends string {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if flow into `node` is prohibited.
|
||||
*/
|
||||
predicate isBarrierIn(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow out `node` is prohibited.
|
||||
*/
|
||||
predicate isBarrierOut(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow into `node` is prohibited for the flow label `lbl`.
|
||||
*/
|
||||
predicate isBarrierIn(DataFlow::Node node, FlowLabel lbl) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow out `node` is prohibited for the flow label `lbl`.
|
||||
*/
|
||||
predicate isBarrierOut(DataFlow::Node node, FlowLabel lbl) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow from `pred` to `succ` is prohibited.
|
||||
*/
|
||||
@@ -494,7 +513,7 @@ private BasicBlock getADominatedBasicBlock(BarrierGuardNode guard, ConditionGuar
|
||||
*
|
||||
* Only holds for barriers that should apply to all flow labels.
|
||||
*/
|
||||
private predicate isBarrierEdge(Configuration cfg, DataFlow::Node pred, DataFlow::Node succ) {
|
||||
private predicate isBarrierEdgeRaw(Configuration cfg, DataFlow::Node pred, DataFlow::Node succ) {
|
||||
cfg.isBarrierEdge(pred, succ)
|
||||
or
|
||||
exists(DataFlow::BarrierGuardNode guard |
|
||||
@@ -503,11 +522,26 @@ private predicate isBarrierEdge(Configuration cfg, DataFlow::Node pred, DataFlow
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a barrier edge `pred -> succ` in `cfg` either through an explicit barrier edge
|
||||
* or one implied by a barrier guard, or by an out/in barrier for `pred` or `succ`, respectively.
|
||||
*
|
||||
* Only holds for barriers that should apply to all flow labels.
|
||||
*/
|
||||
pragma[inline]
|
||||
private predicate isBarrierEdge(Configuration cfg, DataFlow::Node pred, DataFlow::Node succ) {
|
||||
isBarrierEdgeRaw(cfg, pred, succ)
|
||||
or
|
||||
cfg.isBarrierOut(pred)
|
||||
or
|
||||
cfg.isBarrierIn(succ)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a labeled barrier edge `pred -> succ` in `cfg` either through an explicit barrier edge
|
||||
* or one implied by a barrier guard.
|
||||
*/
|
||||
private predicate isLabeledBarrierEdge(
|
||||
private predicate isLabeledBarrierEdgeRaw(
|
||||
Configuration cfg, DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel label
|
||||
) {
|
||||
cfg.isBarrierEdge(pred, succ, label)
|
||||
@@ -518,6 +552,21 @@ private predicate isLabeledBarrierEdge(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a labeled barrier edge `pred -> succ` in `cfg` either through an explicit barrier edge
|
||||
* or one implied by a barrier guard, or by an out/in barrier for `pred` or `succ`, respectively.
|
||||
*/
|
||||
pragma[inline]
|
||||
private predicate isLabeledBarrierEdge(
|
||||
Configuration cfg, DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel label
|
||||
) {
|
||||
isLabeledBarrierEdgeRaw(cfg, pred, succ, label)
|
||||
or
|
||||
cfg.isBarrierOut(pred, label)
|
||||
or
|
||||
cfg.isBarrierIn(succ, label)
|
||||
}
|
||||
|
||||
/**
|
||||
* A guard node that only blocks specific labels.
|
||||
*/
|
||||
|
||||
@@ -138,14 +138,6 @@ module DataFlow {
|
||||
CallGraph::getABoundFunctionReference(result, boundArgs, _).flowsTo(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `DataFlow::ParameterNode::flowsTo()` instead.
|
||||
* Holds if this expression may refer to the initial value of parameter `p`.
|
||||
*/
|
||||
deprecated predicate mayReferToParameter(Parameter p) {
|
||||
parameterNode(p).(SourceNode).flowsTo(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
@@ -980,6 +972,28 @@ module DataFlow {
|
||||
override File getFile() { result = attr.getFile() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node representing an XML attribute.
|
||||
*/
|
||||
class XmlAttributeNode extends DataFlow::Node, TXmlAttributeNode {
|
||||
XmlAttribute attr;
|
||||
|
||||
XmlAttributeNode() { this = TXmlAttributeNode(attr) }
|
||||
|
||||
override string toString() { result = attr.toString() }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
attr.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the attribute corresponding to this data flow node. */
|
||||
XmlAttribute getAttribute() { result = attr }
|
||||
|
||||
override File getFile() { result = attr.getLocation().getFile() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node representing the exceptions thrown by a function.
|
||||
*/
|
||||
@@ -1277,6 +1291,41 @@ module DataFlow {
|
||||
result >= 0 and kind = "call" and result = originalCall.getNumArgument() - 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node representing a call with a tagged template literal.
|
||||
*/
|
||||
private class TaggedTemplateLiteralCallNode extends CallNodeDef, ValueNode {
|
||||
override TaggedTemplateExpr astNode;
|
||||
|
||||
override InvokeExpr getInvokeExpr() { none() } // There is no InvokeExpr for this.
|
||||
|
||||
override string getCalleeName() {
|
||||
result = astNode.getTag().getUnderlyingValue().(Identifier).getName()
|
||||
}
|
||||
|
||||
override DataFlow::Node getCalleeNode() { result = DataFlow::valueNode(astNode.getTag()) }
|
||||
|
||||
override DataFlow::Node getArgument(int i) {
|
||||
// the first argument sent to the function is the array of string parts, which we don't model.
|
||||
// rank is 1-indexed, which is perfect here.
|
||||
result =
|
||||
DataFlow::valueNode(rank[i](Expr e, int index |
|
||||
e = astNode.getTemplate().getElement(index) and not e instanceof TemplateElement
|
||||
|
|
||||
e order by index
|
||||
))
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnArgument() { result = this.getArgument(_) }
|
||||
|
||||
override DataFlow::Node getASpreadArgument() { none() }
|
||||
|
||||
// we don't model the string constants as arguments, but we still count them.
|
||||
override int getNumArgument() { result = count(this.getArgument(_)) + 1 }
|
||||
|
||||
override DataFlow::Node getReceiver() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -92,13 +92,20 @@ class InvokeNode extends DataFlow::SourceNode instanceof DataFlow::Impl::InvokeN
|
||||
* but the position of `z` cannot be determined, hence there are no first and second
|
||||
* argument nodes.
|
||||
*/
|
||||
DataFlow::Node getArgument(int i) { result = super.getArgument(i) }
|
||||
cached
|
||||
DataFlow::Node getArgument(int i) {
|
||||
result = super.getArgument(i) and Stages::DataFlowStage::ref()
|
||||
}
|
||||
|
||||
/** Gets the data flow node corresponding to an argument of this invocation. */
|
||||
DataFlow::Node getAnArgument() { result = super.getAnArgument() }
|
||||
cached
|
||||
DataFlow::Node getAnArgument() { result = super.getAnArgument() and Stages::DataFlowStage::ref() }
|
||||
|
||||
/** Gets the data flow node corresponding to the last argument of this invocation. */
|
||||
DataFlow::Node getLastArgument() { result = this.getArgument(this.getNumArgument() - 1) }
|
||||
cached
|
||||
DataFlow::Node getLastArgument() {
|
||||
result = this.getArgument(this.getNumArgument() - 1) and Stages::DataFlowStage::ref()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a data flow node corresponding to an array of values being passed as
|
||||
@@ -1150,30 +1157,12 @@ module ClassNode {
|
||||
cached
|
||||
abstract FunctionNode getStaticMember(string name, MemberKind kind);
|
||||
|
||||
/**
|
||||
* DEPRECATED. Override `getStaticMember` instead.
|
||||
*
|
||||
* Gets the static method of this class with the given name.
|
||||
*/
|
||||
cached
|
||||
deprecated FunctionNode getStaticMethod(string name) { none() }
|
||||
|
||||
/**
|
||||
* Gets a static member of this class of the given kind.
|
||||
*/
|
||||
cached
|
||||
abstract FunctionNode getAStaticMember(MemberKind kind);
|
||||
|
||||
/**
|
||||
* DEPRECATED. Override `getAStaticMember` instead.
|
||||
*
|
||||
* Gets a static method of this class.
|
||||
*
|
||||
* The constructor is not considered a static method.
|
||||
*/
|
||||
cached
|
||||
deprecated FunctionNode getAStaticMethod() { none() }
|
||||
|
||||
/**
|
||||
* Gets a dataflow node representing a class to be used as the super-class
|
||||
* of this node.
|
||||
|
||||
@@ -62,6 +62,26 @@ module TaintTracking {
|
||||
*/
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow into `node` is prohibited.
|
||||
*/
|
||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow out `node` is prohibited.
|
||||
*/
|
||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow into `node` is prohibited for the flow label `lbl`.
|
||||
*/
|
||||
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowLabel lbl) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow out `node` is prohibited for the flow label `lbl`.
|
||||
*/
|
||||
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowLabel lbl) { none() }
|
||||
|
||||
/** Holds if the edge from `pred` to `succ` is a taint sanitizer. */
|
||||
predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) { none() }
|
||||
|
||||
@@ -108,6 +128,22 @@ module TaintTracking {
|
||||
this.isSanitizerEdge(source, sink) and lbl.isTaint()
|
||||
}
|
||||
|
||||
final override predicate isBarrierIn(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowLabel lbl) {
|
||||
this.isSanitizerIn(node, lbl)
|
||||
or
|
||||
this.isSanitizerIn(node) and lbl.isTaint()
|
||||
}
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowLabel lbl) {
|
||||
this.isSanitizerOut(node, lbl)
|
||||
or
|
||||
this.isSanitizerOut(node) and lbl.isTaint()
|
||||
}
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuardNode guard) {
|
||||
super.isBarrierGuard(guard) or
|
||||
guard.(AdditionalSanitizerGuardNode).appliesTo(this) or
|
||||
|
||||
@@ -27,10 +27,8 @@
|
||||
|
||||
private import javascript
|
||||
import AbstractValues
|
||||
import AbstractProperties
|
||||
private import InferredTypes
|
||||
private import Refinements
|
||||
private import internal.AbstractValuesImpl
|
||||
import internal.BasicExprTypeInference
|
||||
import internal.InterModuleTypeInference
|
||||
import internal.InterProceduralTypeInference
|
||||
|
||||
@@ -27,6 +27,7 @@ newtype TNode =
|
||||
exists(decl.getASpecifier().getImportedName())
|
||||
} or
|
||||
THtmlAttributeNode(HTML::Attribute attr) or
|
||||
TXmlAttributeNode(XmlAttribute attr) or
|
||||
TFunctionReturnNode(Function f) or
|
||||
TExceptionalFunctionReturnNode(Function f) or
|
||||
TExceptionalInvocationReturnNode(InvokeExpr e) or
|
||||
|
||||
@@ -75,9 +75,6 @@ predicate isExternsFile(File f) {
|
||||
*/
|
||||
predicate isLibraryFile(File f) { f.getATopLevel() instanceof FrameworkLibraryInstance }
|
||||
|
||||
/** DEPRECATED: Alias for isLibraryFile */
|
||||
deprecated predicate isLibaryFile = isLibraryFile/1;
|
||||
|
||||
/**
|
||||
* Holds if `f` contains template code.
|
||||
*/
|
||||
|
||||
@@ -618,27 +618,6 @@ private class JQLiteObject extends JQuery::ObjectSource::Range {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `AngularJSCallNode` instead.
|
||||
* A call to an AngularJS function.
|
||||
*
|
||||
* Used for exposing behavior that is similar to the behavior of other libraries.
|
||||
*/
|
||||
deprecated class AngularJSCall extends CallExpr {
|
||||
AngularJSCallNode node;
|
||||
|
||||
AngularJSCall() { this.flow() = node }
|
||||
|
||||
/** Holds if `e` is an argument that this call interprets as HTML. */
|
||||
deprecated predicate interpretsArgumentAsHtml(Expr e) { node.interpretsArgumentAsHtml(e.flow()) }
|
||||
|
||||
/** Holds if `e` is an argument that this call stores globally, e.g. in a cookie. */
|
||||
deprecated predicate storesArgumentGlobally(Expr e) { node.storesArgumentGlobally(e.flow()) }
|
||||
|
||||
/** Holds if `e` is an argument that this call interprets as code. */
|
||||
deprecated predicate interpretsArgumentAsCode(Expr e) { node.interpretsArgumentAsCode(e.flow()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to an AngularJS function.
|
||||
*
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
import javascript
|
||||
private import AngularJS
|
||||
private import ServiceDefinitions
|
||||
|
||||
/**
|
||||
* Holds if `nd` is an `angular.injector()` value
|
||||
|
||||
@@ -447,21 +447,6 @@ BuiltinServiceReference getBuiltinServiceOfKind(string kind) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `ServiceRequestNode` instead.
|
||||
* A request for one or more AngularJS services.
|
||||
*/
|
||||
deprecated class ServiceRequest extends Expr {
|
||||
ServiceRequestNode node;
|
||||
|
||||
ServiceRequest() { this.flow() = node }
|
||||
|
||||
/** Gets the parameter of this request into which `service` is injected. */
|
||||
deprecated Parameter getDependencyParameter(ServiceReference service) {
|
||||
result.flow() = node.getDependencyParameter(service)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A request for one or more AngularJS services.
|
||||
*/
|
||||
|
||||
@@ -118,8 +118,6 @@ module Connect {
|
||||
override string getCredentialsKind() { result = kind }
|
||||
}
|
||||
|
||||
deprecated class RequestExpr = NodeJSLib::RequestExpr;
|
||||
|
||||
class RequestNode = NodeJSLib::RequestNode;
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,23 +5,6 @@
|
||||
|
||||
import javascript
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `CredentialsNode` instead.
|
||||
* An expression whose value is used to supply credentials such
|
||||
* as a user name, a password, or a key.
|
||||
*/
|
||||
deprecated class CredentialsExpr extends Expr {
|
||||
CredentialsNode node;
|
||||
|
||||
CredentialsExpr() { node.asExpr() = this }
|
||||
|
||||
/**
|
||||
* Gets a description of the kind of credential this expression is used as,
|
||||
* such as `"user name"`, `"password"`, `"key"`.
|
||||
*/
|
||||
deprecated string getCredentialsKind() { result = node.getCredentialsKind() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression whose value is used to supply credentials such
|
||||
* as a user name, a password, or a key.
|
||||
|
||||
@@ -51,6 +51,7 @@ private module AsmCrypto {
|
||||
private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode {
|
||||
DataFlow::Node input;
|
||||
CryptographicAlgorithm algorithm; // non-functional
|
||||
DataFlow::PropRead algorithmSelection;
|
||||
private string algorithmName;
|
||||
private string methodName;
|
||||
|
||||
@@ -68,11 +69,14 @@ private module AsmCrypto {
|
||||
exists(DataFlow::SourceNode asmCrypto |
|
||||
asmCrypto = DataFlow::globalVarRef("asmCrypto") and
|
||||
algorithm.matchesName(algorithmName) and
|
||||
this = asmCrypto.getAPropertyRead(algorithmName).getAMemberCall(methodName) and
|
||||
algorithmSelection = asmCrypto.getAPropertyRead(algorithmName) and
|
||||
this = algorithmSelection.getAMemberCall(methodName) and
|
||||
input = this.getArgument(0)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = algorithmSelection }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = input }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
@@ -103,6 +107,7 @@ private module BrowserIdCrypto {
|
||||
|
||||
private class Apply extends CryptographicOperation::Range instanceof DataFlow::MethodCallNode {
|
||||
CryptographicAlgorithm algorithm; // non-functional
|
||||
DataFlow::CallNode keygen;
|
||||
|
||||
Apply() {
|
||||
/*
|
||||
@@ -122,8 +127,7 @@ private module BrowserIdCrypto {
|
||||
*/
|
||||
|
||||
exists(
|
||||
DataFlow::SourceNode mod, DataFlow::Node algorithmNameNode, DataFlow::CallNode keygen,
|
||||
DataFlow::FunctionNode callback
|
||||
DataFlow::SourceNode mod, DataFlow::Node algorithmNameNode, DataFlow::FunctionNode callback
|
||||
|
|
||||
mod = DataFlow::moduleImport("browserid-crypto") and
|
||||
keygen = mod.getAMemberCall("generateKeypair") and
|
||||
@@ -134,6 +138,8 @@ private module BrowserIdCrypto {
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = keygen }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = super.getArgument(0) }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
@@ -239,6 +245,8 @@ private module NodeJSCrypto {
|
||||
|
||||
Apply() { this = instantiation.getAMethodCall(any(string m | m = "update" or m = "write")) }
|
||||
|
||||
override DataFlow::Node getInitialization() { result = instantiation }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = super.getArgument(0) }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = instantiation.getAlgorithm() }
|
||||
@@ -324,7 +332,9 @@ private module CryptoJS {
|
||||
)
|
||||
}
|
||||
|
||||
private API::CallNode getEncryptionApplication(API::Node input, CryptographicAlgorithm algorithm) {
|
||||
private API::CallNode getEncryptionApplication(
|
||||
API::Node input, API::Node algorithmNode, CryptographicAlgorithm algorithm
|
||||
) {
|
||||
/*
|
||||
* ```
|
||||
* var CryptoJS = require("crypto-js");
|
||||
@@ -338,11 +348,14 @@ private module CryptoJS {
|
||||
* Also matches where `CryptoJS.<algorithmName>` has been replaced by `require("crypto-js/<algorithmName>")`
|
||||
*/
|
||||
|
||||
result = getAlgorithmNode(algorithm).getMember("encrypt").getACall() and
|
||||
algorithmNode = getAlgorithmNode(algorithm) and
|
||||
result = algorithmNode.getMember("encrypt").getACall() and
|
||||
input = result.getParameter(0)
|
||||
}
|
||||
|
||||
private API::CallNode getDirectApplication(API::Node input, CryptographicAlgorithm algorithm) {
|
||||
private API::CallNode getDirectApplication(
|
||||
API::Node input, API::Node algorithmNode, CryptographicAlgorithm algorithm
|
||||
) {
|
||||
/*
|
||||
* ```
|
||||
* var CryptoJS = require("crypto-js");
|
||||
@@ -357,7 +370,8 @@ private module CryptoJS {
|
||||
* Also matches where `CryptoJS.<algorithmName>` has been replaced by `require("crypto-js/<algorithmName>")`
|
||||
*/
|
||||
|
||||
result = getAlgorithmNode(algorithm).getACall() and
|
||||
algorithmNode = getAlgorithmNode(algorithm) and
|
||||
result = algorithmNode.getACall() and
|
||||
input = result.getParameter(0)
|
||||
}
|
||||
|
||||
@@ -389,18 +403,23 @@ private module CryptoJS {
|
||||
private class Apply extends CryptographicOperation::Range instanceof API::CallNode {
|
||||
API::Node input;
|
||||
CryptographicAlgorithm algorithm; // non-functional
|
||||
DataFlow::Node instantiation;
|
||||
|
||||
Apply() {
|
||||
this = getEncryptionApplication(input, algorithm)
|
||||
or
|
||||
this = getDirectApplication(input, algorithm)
|
||||
or
|
||||
exists(InstantiatedAlgorithm instantiation |
|
||||
this = getUpdatedApplication(input, instantiation) and
|
||||
algorithm = instantiation.getAlgorithm()
|
||||
exists(API::Node algorithmNode |
|
||||
this = getEncryptionApplication(input, algorithmNode, algorithm)
|
||||
or
|
||||
this = getDirectApplication(input, algorithmNode, algorithm)
|
||||
|
|
||||
instantiation = algorithmNode.asSource()
|
||||
)
|
||||
or
|
||||
this = getUpdatedApplication(input, instantiation) and
|
||||
algorithm = instantiation.(InstantiatedAlgorithm).getAlgorithm()
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = instantiation }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = input.asSink() }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
@@ -504,6 +523,8 @@ private module TweetNaCl {
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = this }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = input }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
@@ -539,6 +560,7 @@ private module HashJs {
|
||||
private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode {
|
||||
DataFlow::Node input;
|
||||
CryptographicAlgorithm algorithm; // non-functional
|
||||
DataFlow::CallNode init;
|
||||
|
||||
Apply() {
|
||||
/*
|
||||
@@ -554,10 +576,13 @@ private module HashJs {
|
||||
* Also matches where `hash.<algorithmName>()` has been replaced by a more specific require a la `require("hash.js/lib/hash/sha/512")`
|
||||
*/
|
||||
|
||||
this = getAlgorithmNode(algorithm).getAMemberCall("update") and
|
||||
init = getAlgorithmNode(algorithm) and
|
||||
this = init.getAMemberCall("update") and
|
||||
input = super.getArgument(0)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = init }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = input }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
@@ -653,6 +678,8 @@ private module Forge {
|
||||
algorithm = cipher.getAlgorithm()
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = cipher }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = input }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
@@ -715,6 +742,8 @@ private module Md5 {
|
||||
super.getArgument(0) = input
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = this }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = input }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
@@ -731,17 +760,18 @@ private module Bcrypt {
|
||||
private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode {
|
||||
DataFlow::Node input;
|
||||
CryptographicAlgorithm algorithm;
|
||||
API::Node init;
|
||||
|
||||
Apply() {
|
||||
// `require("bcrypt").hash(password);` with minor naming variations
|
||||
algorithm.matchesName("BCRYPT") and
|
||||
this =
|
||||
API::moduleImport(["bcrypt", "bcryptjs", "bcrypt-nodejs"])
|
||||
.getMember(["hash", "hashSync"])
|
||||
.getACall() and
|
||||
init = API::moduleImport(["bcrypt", "bcryptjs", "bcrypt-nodejs"]) and
|
||||
this = init.getMember(["hash", "hashSync"]).getACall() and
|
||||
super.getArgument(0) = input
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = init.asSource() }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = input }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
@@ -769,6 +799,8 @@ private module Hasha {
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = this }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = input }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
|
||||
|
||||
@@ -133,9 +133,6 @@ module Electron {
|
||||
override IpcDispatch getAReturnDispatch() { result.getCalleeName() = "sendSync" }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for IpcSendRegistration */
|
||||
deprecated class IPCSendRegistration = IpcSendRegistration;
|
||||
|
||||
/**
|
||||
* A dispatch of an IPC event.
|
||||
* An IPC event is sent from the renderer to the main process.
|
||||
@@ -171,9 +168,6 @@ module Electron {
|
||||
result.getEmitter() instanceof RendererProcess
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for IpcDispatch */
|
||||
deprecated class IPCDispatch = IpcDispatch;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,9 +17,6 @@ class EmscriptenStartAsmComment extends EmscriptenMarkerComment {
|
||||
EmscriptenStartAsmComment() { this.getText().trim() = "EMSCRIPTEN_START_ASM" }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for EmscriptenStartAsmComment */
|
||||
deprecated class EmscriptenStartASMComment = EmscriptenStartAsmComment;
|
||||
|
||||
/**
|
||||
* An `EMSCRIPTEN_START_FUNCS` marker comment.
|
||||
*/
|
||||
@@ -34,9 +31,6 @@ class EmscriptenEndAsmComment extends EmscriptenMarkerComment {
|
||||
EmscriptenEndAsmComment() { this.getText().trim() = "EMSCRIPTEN_END_ASM" }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for EmscriptenEndAsmComment */
|
||||
deprecated class EmscriptenEndASMComment = EmscriptenEndAsmComment;
|
||||
|
||||
/**
|
||||
* An `EMSCRIPTEN_END_FUNCS` marker comment.
|
||||
*/
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import semmle.javascript.frameworks.HTTP
|
||||
import semmle.javascript.frameworks.ExpressModules
|
||||
private import semmle.javascript.dataflow.InferredTypes
|
||||
private import semmle.javascript.frameworks.ConnectExpressShared::ConnectExpressShared
|
||||
@@ -55,14 +54,6 @@ module Express {
|
||||
WebpackDevServer::webpackDevServerApp().flowsTo(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `RouterDefinition.ref()` or `RouteSetup` instead.
|
||||
* An expression that refers to a route.
|
||||
*/
|
||||
deprecated class RouteExpr extends MethodCallExpr {
|
||||
RouteExpr() { isRouter(this.flow()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of an Express router method that sets up a route.
|
||||
*/
|
||||
@@ -145,17 +136,6 @@ module Express {
|
||||
/** Holds if this is a call `use`, such as `app.use(handler)`. */
|
||||
predicate isUseCall() { this.getMethodName() = "use" }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getRouteHandlerNode` instead.
|
||||
* Gets the `n`th handler registered by this setup, with 0 being the first.
|
||||
*
|
||||
* This differs from `getARouteHandler` in that the argument expression is
|
||||
* returned, not its dataflow source.
|
||||
*/
|
||||
deprecated Expr getRouteHandlerExpr(int index) {
|
||||
result = this.getRouteHandlerNode(index).asExpr()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `n`th handler registered by this setup, with 0 being the first.
|
||||
*
|
||||
@@ -174,25 +154,11 @@ module Express {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getARouteHandlerNode` instead.
|
||||
* Gets an argument that represents a route handler being registered.
|
||||
*/
|
||||
deprecated Expr getARouteHandlerExpr() { result = this.getRouteHandlerExpr(_) }
|
||||
|
||||
/**
|
||||
* Gets an argument that represents a route handler being registered.
|
||||
*/
|
||||
DataFlow::Node getARouteHandlerNode() { result = this.getRouteHandlerNode(_) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getLastRouteHandlerExpr` instead.
|
||||
* Gets the last argument representing a route handler being registered.
|
||||
*/
|
||||
deprecated Expr getLastRouteHandlerExpr() {
|
||||
result = max(int i | | this.getRouteHandlerExpr(i) order by i)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last argument representing a route handler being registered.
|
||||
*/
|
||||
@@ -294,52 +260,6 @@ module Express {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `RouteHandlerNode` instead.
|
||||
* An expression used as an Express route handler, such as `submitHandler` below:
|
||||
* ```
|
||||
* app.post('/submit', submitHandler)
|
||||
* ```
|
||||
*
|
||||
* Unlike `RouterHandler`, this is the argument passed to a setup, as opposed to
|
||||
* a function that flows into such an argument.
|
||||
*/
|
||||
deprecated class RouteHandlerExpr extends Expr {
|
||||
RouteHandlerNode node;
|
||||
|
||||
RouteHandlerExpr() { this.flow() = node }
|
||||
|
||||
/** Gets the setup call that registers this route handler. */
|
||||
deprecated RouteSetup getSetup() { result = node.getSetup() }
|
||||
|
||||
/** Gets the function body of this handler, if it is defined locally. */
|
||||
deprecated RouteHandler getBody() { result = node.getBody() }
|
||||
|
||||
/** Holds if this is not followed by more handlers. */
|
||||
deprecated predicate isLastHandler() { node.isLastHandler() }
|
||||
|
||||
/** Gets a route handler that immediately precedes this in the route stack. */
|
||||
deprecated Express::RouteHandlerExpr getPreviousMiddleware() {
|
||||
result = node.getPreviousMiddleware().asExpr()
|
||||
}
|
||||
|
||||
/** Gets a route handler that may follow immediately after this one in its route stack. */
|
||||
deprecated Express::RouteHandlerExpr getNextMiddleware() {
|
||||
result = node.getNextMiddleware().asExpr()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a route handler that precedes this one (not necessarily immediately), may handle
|
||||
* same request method, and matches on the same path or a prefix.
|
||||
*/
|
||||
deprecated Express::RouteHandlerExpr getAMatchingAncestor() {
|
||||
result = node.getAMatchingAncestor().asExpr()
|
||||
}
|
||||
|
||||
/** Gets the router being registered as a sub-router here, if any. */
|
||||
deprecated RouterDefinition getAsSubRouter() { result = node.getAsSubRouter() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression used as an Express route handler, such as `submitHandler` below:
|
||||
* ```
|
||||
@@ -584,14 +504,6 @@ module Express {
|
||||
override RouteHandler getRouteHandler() { none() } // Not known.
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `ResponseNode` instead.
|
||||
* An Express response expression.
|
||||
*/
|
||||
deprecated class ResponseExpr extends NodeJSLib::ResponseExpr {
|
||||
ResponseExpr() { this.flow() instanceof ResponseNode }
|
||||
}
|
||||
|
||||
/**
|
||||
* An Express response expression.
|
||||
*/
|
||||
@@ -599,14 +511,6 @@ module Express {
|
||||
override ResponseSource src;
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `RequestNode` instead.
|
||||
* An Express request expression.
|
||||
*/
|
||||
deprecated class RequestExpr extends NodeJSLib::RequestExpr {
|
||||
RequestExpr() { this.flow() instanceof RequestNode }
|
||||
}
|
||||
|
||||
/**
|
||||
* An Express request expression.
|
||||
*/
|
||||
@@ -713,6 +617,10 @@ module Express {
|
||||
or
|
||||
kind = "body" and
|
||||
this = ref.getAPropertyRead("body")
|
||||
or
|
||||
// `req.path`
|
||||
kind = "url" and
|
||||
this = ref.getAPropertyRead("path")
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -154,12 +154,6 @@ module Fastify {
|
||||
|
||||
override DataFlow::SourceNode getServer() { result = server }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getARouteHandlerNode` instead.
|
||||
* Gets an argument that represents a route handler being registered.
|
||||
*/
|
||||
deprecated DataFlow::Node getARouteHandlerExpr() { result = this.getARouteHandlerNode() }
|
||||
|
||||
/** Gets an argument that represents a route handler being registered. */
|
||||
DataFlow::Node getARouteHandlerNode() {
|
||||
if methodName = "route"
|
||||
|
||||
@@ -11,9 +11,6 @@ class GwtVersionVariable extends GlobalVariable {
|
||||
GwtVersionVariable() { this.getName() = "$gwt_version" }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for GwtVersionVariable */
|
||||
deprecated class GWTVersionVariable = GwtVersionVariable;
|
||||
|
||||
/**
|
||||
* A GWT header script that defines the `$gwt_version` variable.
|
||||
*/
|
||||
@@ -36,15 +33,9 @@ class GwtHeader extends InlineScript {
|
||||
deprecated string getGWTVersion() { result = this.getGwtVersion() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for GwtHeader */
|
||||
deprecated class GWTHeader = GwtHeader;
|
||||
|
||||
/**
|
||||
* A toplevel in a file that appears to be GWT-generated.
|
||||
*/
|
||||
class GwtGeneratedTopLevel extends TopLevel {
|
||||
GwtGeneratedTopLevel() { exists(GwtHeader h | this.getFile() = h.getFile()) }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for GwtGeneratedTopLevel */
|
||||
deprecated class GWTGeneratedTopLevel = GwtGeneratedTopLevel;
|
||||
|
||||
@@ -65,23 +65,9 @@ module Http {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `definesHeaderValue` instead.
|
||||
* Holds if the header with (lower-case) name `headerName` is set to the value of `headerValue`.
|
||||
*/
|
||||
deprecated predicate definesExplicitly(string headerName, Expr headerValue) {
|
||||
this.definesHeaderValue(headerName, headerValue.flow())
|
||||
}
|
||||
|
||||
/** Holds if the header with (lower-case) name `headerName` is set to the value of `headerValue`. */
|
||||
abstract predicate definesHeaderValue(string headerName, DataFlow::Node headerValue);
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getNameNode()` instead.
|
||||
* Returns the expression used to compute the header name.
|
||||
*/
|
||||
deprecated Expr getNameExpr() { result = this.getNameNode().asExpr() }
|
||||
|
||||
/** Returns the expression used to compute the header name. */
|
||||
abstract DataFlow::Node getNameNode();
|
||||
}
|
||||
@@ -202,26 +188,12 @@ module Http {
|
||||
*/
|
||||
final Servers::ResponseSource getAResponseSource() { result.getRouteHandler() = this }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getARequestNode()` instead.
|
||||
* Gets an expression that contains a request object handled
|
||||
* by this handler.
|
||||
*/
|
||||
deprecated RequestExpr getARequestExpr() { result.flow() = this.getARequestNode() }
|
||||
|
||||
/**
|
||||
* Gets an expression that contains a request object handled
|
||||
* by this handler.
|
||||
*/
|
||||
RequestNode getARequestNode() { result.getRouteHandler() = this }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getAResponseNode()` instead.
|
||||
* Gets an expression that contains a response object provided
|
||||
* by this handler.
|
||||
*/
|
||||
deprecated ResponseExpr getAResponseExpr() { result.flow() = this.getAResponseNode() }
|
||||
|
||||
/**
|
||||
* Gets an expression that contains a response object provided
|
||||
* by this handler.
|
||||
@@ -265,30 +237,6 @@ module Http {
|
||||
abstract RouteHandler getRouteHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `RequestNode` instead.
|
||||
* An expression that may contain a request object.
|
||||
*/
|
||||
deprecated class RequestExpr extends Expr {
|
||||
RequestExpr() { this.flow() instanceof ResponseNode }
|
||||
|
||||
/**
|
||||
* Gets the route handler that handles this request.
|
||||
*/
|
||||
RouteHandler getRouteHandler() { result = this.flow().(ResponseNode).getRouteHandler() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `ResponseNode` instead.
|
||||
* An expression that may contain a response object.
|
||||
*/
|
||||
deprecated class ResponseExpr extends Expr {
|
||||
/**
|
||||
* Gets the route handler that handles this request.
|
||||
*/
|
||||
RouteHandler getRouteHandler() { result = this.flow().(ResponseNode).getRouteHandler() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Boiler-plate implementation of a `Server` and its associated classes.
|
||||
* Made for easily defining new HTTP servers
|
||||
@@ -309,12 +257,6 @@ module Http {
|
||||
|
||||
/** Gets a data flow node referring to this server. */
|
||||
DataFlow::SourceNode ref() { result = this.ref(DataFlow::TypeTracker::end()) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `ref().flowsToExpr()` instead.
|
||||
* Holds if `sink` may refer to this server definition.
|
||||
*/
|
||||
deprecated predicate flowsTo(Expr sink) { this.ref().flowsToExpr(sink) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -402,30 +344,6 @@ module Http {
|
||||
override RouteHandler getRouteHandler() { result = src.getRouteHandler() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A request expression arising from a request source.
|
||||
*/
|
||||
deprecated class StandardRequestExpr extends RequestExpr {
|
||||
RequestSource src;
|
||||
|
||||
StandardRequestExpr() { src.ref().flowsToExpr(this) }
|
||||
|
||||
override RouteHandler getRouteHandler() { result = src.getRouteHandler() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A response expression arising from a response source.
|
||||
*/
|
||||
deprecated class StandardResponseExpr extends ResponseExpr {
|
||||
ResponseSource src;
|
||||
|
||||
StandardResponseExpr() { src.ref().flowsToExpr(this) }
|
||||
|
||||
override RouteHandler getRouteHandler() {
|
||||
result = this.flow().(StandardResponseNode).getRouteHandler()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A standard header definition.
|
||||
*/
|
||||
@@ -689,6 +607,3 @@ module Http {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for Http */
|
||||
deprecated module HTTP = Http;
|
||||
|
||||
@@ -87,14 +87,6 @@ module Hapi {
|
||||
override RouteHandler getRouteHandler() { result = rh }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `ResponseNode` instead.
|
||||
* A Hapi response expression.
|
||||
*/
|
||||
deprecated class ResponseExpr extends HTTP::Servers::StandardResponseExpr {
|
||||
ResponseExpr() { this.flow() instanceof ResponseNode }
|
||||
}
|
||||
|
||||
/**
|
||||
* A Hapi response node.
|
||||
*/
|
||||
@@ -102,14 +94,6 @@ module Hapi {
|
||||
override ResponseSource src;
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `RequestNode` instead.
|
||||
* An Hapi request expression.
|
||||
*/
|
||||
deprecated class RequestExpr extends HTTP::Servers::StandardRequestExpr {
|
||||
RequestExpr() { this.flow() instanceof RequestNode }
|
||||
}
|
||||
|
||||
/**
|
||||
* A Hapi request node.
|
||||
*/
|
||||
@@ -255,8 +239,6 @@ module Hapi {
|
||||
pragma[noinline]
|
||||
private DataFlow::Node getRouteHandler() { result = handler }
|
||||
|
||||
deprecated Expr getRouteHandlerExpr() { result = handler.asExpr() }
|
||||
|
||||
override DataFlow::Node getServer() { result = server }
|
||||
}
|
||||
|
||||
|
||||
@@ -44,13 +44,6 @@ module Koa {
|
||||
result = this.getAFunctionValue().getParameter(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getAContextNode` instead.
|
||||
* Gets an expression that contains the "context" object of
|
||||
* a route handler invocation.
|
||||
*/
|
||||
deprecated Expr getAContextExpr() { result = this.getAContextNode().asExpr() }
|
||||
|
||||
/**
|
||||
* Gets an expression that contains the "context" object of
|
||||
* a route handler invocation.
|
||||
@@ -61,15 +54,6 @@ module Koa {
|
||||
*/
|
||||
DataFlow::Node getAContextNode() { result.(ContextNode).getRouteHandler() = this }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getAResponseOrContextNode` instead.
|
||||
* Gets an expression that contains the context or response
|
||||
* object of a route handler invocation.
|
||||
*/
|
||||
deprecated Expr getAResponseOrContextExpr() {
|
||||
result = this.getAResponseOrContextNode().asExpr()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression that contains the context or response
|
||||
* object of a route handler invocation.
|
||||
@@ -78,13 +62,6 @@ module Koa {
|
||||
result = this.getAResponseNode() or result = this.getAContextNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getARequestOrContextNode` instead.
|
||||
* Gets an expression that contains the context or request
|
||||
* object of a route handler invocation.
|
||||
*/
|
||||
deprecated Expr getARequestOrContextExpr() { result = this.getARequestOrContextNode().asExpr() }
|
||||
|
||||
/**
|
||||
* Gets an expression that contains the context or request
|
||||
* object of a route handler invocation.
|
||||
@@ -273,19 +250,6 @@ module Koa {
|
||||
override RouteHandler getRouteHandler() { result = ctx.getRouteHandler() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `ContextNode` instead.
|
||||
* An expression that may hold a Koa context object.
|
||||
*/
|
||||
deprecated class ContextExpr extends Expr {
|
||||
ContextNode node;
|
||||
|
||||
ContextExpr() { node.asExpr() = this }
|
||||
|
||||
/** Gets the route handler that provides this response. */
|
||||
deprecated RouteHandler getRouteHandler() { result = node.getRouteHandler() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that may hold a Koa context object.
|
||||
*/
|
||||
@@ -300,14 +264,6 @@ module Koa {
|
||||
RouteHandler getRouteHandler() { result = src.getRouteHandler() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `RequestNode` instead.
|
||||
* An expression that may hold a Koa request object.
|
||||
*/
|
||||
deprecated class RequestExpr extends HTTP::Servers::StandardRequestExpr {
|
||||
RequestExpr() { this.flow() instanceof RequestNode }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that may hold a Koa request object.
|
||||
*/
|
||||
@@ -315,14 +271,6 @@ module Koa {
|
||||
override RequestSource src;
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `ResponseNode` instead.
|
||||
* An expression that may hold a Koa response object.
|
||||
*/
|
||||
deprecated class ResponseExpr extends HTTP::Servers::StandardResponseExpr {
|
||||
ResponseExpr() { this.flow() instanceof ResponseNode }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that may hold a Koa response object.
|
||||
*/
|
||||
|
||||
@@ -62,18 +62,10 @@ private module Micro {
|
||||
override Http::RouteHandler getRouteHandler() { result = h }
|
||||
}
|
||||
|
||||
deprecated class MicroRequestExpr extends NodeJSLib::RequestExpr {
|
||||
override MicroRequestSource src;
|
||||
}
|
||||
|
||||
class MicroRequestNode extends NodeJSLib::RequestNode {
|
||||
override MicroRequestSource src;
|
||||
}
|
||||
|
||||
deprecated class MicroReseponseExpr extends NodeJSLib::ResponseExpr {
|
||||
override MicroResponseSource src;
|
||||
}
|
||||
|
||||
class MicroResponseNode extends NodeJSLib::ResponseNode {
|
||||
override MicroResponseSource src;
|
||||
}
|
||||
|
||||
@@ -64,17 +64,6 @@ module NodeJSLib {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `ResponseNode` instead.
|
||||
* A Node.js HTTP response.
|
||||
*
|
||||
* A server library that provides an (enhanced) NodesJS HTTP response
|
||||
* object should implement a library specific subclass of this class.
|
||||
*/
|
||||
deprecated class ResponseExpr extends HTTP::Servers::StandardResponseExpr {
|
||||
ResponseExpr() { this.flow() instanceof ResponseNode }
|
||||
}
|
||||
|
||||
/**
|
||||
* A Node.js HTTP response.
|
||||
*
|
||||
@@ -83,17 +72,6 @@ module NodeJSLib {
|
||||
*/
|
||||
abstract class ResponseNode extends Http::Servers::StandardResponseNode { }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `RequestNode` instead.
|
||||
* A Node.js HTTP request.
|
||||
*
|
||||
* A server library that provides an (enhanced) NodesJS HTTP request
|
||||
* object should implement a library specific subclass of this class.
|
||||
*/
|
||||
deprecated class RequestExpr extends HTTP::Servers::StandardRequestExpr {
|
||||
RequestExpr() { this.flow() instanceof RequestNode }
|
||||
}
|
||||
|
||||
/**
|
||||
* A Node.js HTTP request.
|
||||
*
|
||||
@@ -168,14 +146,6 @@ module NodeJSLib {
|
||||
override RouteHandler getRouteHandler() { result = rh }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `BuiltinRouteHandlerResponseNode` instead.
|
||||
* A builtin Node.js HTTP response.
|
||||
*/
|
||||
deprecated private class BuiltinRouteHandlerResponseExpr extends ResponseExpr {
|
||||
BuiltinRouteHandlerResponseExpr() { src instanceof ResponseSource }
|
||||
}
|
||||
|
||||
/**
|
||||
* A builtin Node.js HTTP response.
|
||||
*/
|
||||
@@ -183,14 +153,6 @@ module NodeJSLib {
|
||||
BuiltinRouteHandlerResponseNode() { src instanceof ResponseSource }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `BuiltinRouteHandlerRequestNode` instead.
|
||||
* A builtin Node.js HTTP request.
|
||||
*/
|
||||
deprecated private class BuiltinRouteHandlerRequestExpr extends RequestExpr {
|
||||
BuiltinRouteHandlerRequestExpr() { src instanceof RequestSource }
|
||||
}
|
||||
|
||||
/**
|
||||
* A builtin Node.js HTTP request.
|
||||
*/
|
||||
@@ -288,12 +250,6 @@ module NodeJSLib {
|
||||
|
||||
override DataFlow::Node getServer() { result = server }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getRouteHandlerNode` instead.
|
||||
* Gets the expression for the handler registered by this setup.
|
||||
*/
|
||||
deprecated Expr getRouteHandlerExpr() { result = handler.asExpr() }
|
||||
|
||||
/**
|
||||
* Gets the expression for the handler registered by this setup.
|
||||
*/
|
||||
@@ -554,7 +510,11 @@ module NodeJSLib {
|
||||
t.start()
|
||||
or
|
||||
t.start() and
|
||||
result = DataFlow::moduleMember("fs", "promises")
|
||||
(
|
||||
result = DataFlow::moduleMember("fs", "promises")
|
||||
or
|
||||
result = DataFlow::moduleImport("fs/promises")
|
||||
)
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2, DataFlow::SourceNode pred | pred = fsModule(t2) |
|
||||
result = pred.track(t2, t)
|
||||
|
||||
@@ -852,13 +852,13 @@ private class StateTaintStep extends TaintTracking::SharedTaintStep {
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint propagating data flow edge for assignments of the form `c1.props.p = v`,
|
||||
* A data propagating data flow edge for assignments of the form `c1.props.p = v`,
|
||||
* where `c1` is an instance of React component `C`; in this case, we consider
|
||||
* taint to flow from `v` to any read of `c2.props.p`, where `c2`
|
||||
* data to flow from `v` to any read of `c2.props.p`, where `c2`
|
||||
* also is an instance of `C`.
|
||||
*/
|
||||
private class PropsTaintStep extends TaintTracking::SharedTaintStep {
|
||||
override predicate viewComponentStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
private class PropsFlowStep extends PreCallGraphStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(ReactComponent c, string name, DataFlow::PropRead prn |
|
||||
prn = c.getAPropRead(name) or
|
||||
prn = c.getAPreviousPropsSource().getAPropertyRead(name)
|
||||
|
||||
@@ -72,14 +72,6 @@ module Restify {
|
||||
override RouteHandler getRouteHandler() { result = rh }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `ResponseNode` instead.
|
||||
* A Node.js HTTP response provided by Restify.
|
||||
*/
|
||||
deprecated class ResponseExpr extends NodeJSLib::ResponseExpr {
|
||||
ResponseExpr() { src instanceof ResponseSource }
|
||||
}
|
||||
|
||||
/**
|
||||
* A Node.js HTTP response provided by Restify.
|
||||
*/
|
||||
@@ -87,14 +79,6 @@ module Restify {
|
||||
ResponseNode() { src instanceof ResponseSource or src instanceof FormatterResponseSource }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `RequestNode` instead.
|
||||
* A Node.js HTTP request provided by Restify.
|
||||
*/
|
||||
deprecated class RequestExpr extends NodeJSLib::RequestExpr {
|
||||
RequestExpr() { src instanceof RequestSource }
|
||||
}
|
||||
|
||||
/**
|
||||
* A Node.js HTTP request provided by Restify.
|
||||
*/
|
||||
|
||||
@@ -104,7 +104,7 @@ private module Postgres {
|
||||
API::Node clientOrPool() { result = API::Node::ofType("pg", ["Client", "PoolClient", "Pool"]) }
|
||||
|
||||
/** A call to the Postgres `query` method. */
|
||||
private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode {
|
||||
private class QueryCall extends DatabaseAccess, API::CallNode {
|
||||
QueryCall() { this = clientOrPool().getMember(["execute", "query"]).getACall() }
|
||||
|
||||
override DataFlow::Node getAResult() {
|
||||
@@ -117,15 +117,25 @@ private module Postgres {
|
||||
PromiseFlow::loadStep(this.getALocalUse(), result, Promises::valueProp())
|
||||
}
|
||||
|
||||
override DataFlow::Node getAQueryArgument() { result = this.getArgument(0) }
|
||||
override DataFlow::Node getAQueryArgument() {
|
||||
result = this.getArgument(0) or result = this.getParameter(0).getMember("text").asSink()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Postgres Query class.
|
||||
* This class can be used to create reusable query objects (see https://node-postgres.com/apis/client).
|
||||
*/
|
||||
API::Node query() { result = API::moduleImport("pg").getMember("Query") }
|
||||
|
||||
/** An expression that is passed to the `query` method and hence interpreted as SQL. */
|
||||
class QueryString extends SQL::SqlString {
|
||||
QueryString() {
|
||||
this = any(QueryCall qc).getAQueryArgument()
|
||||
or
|
||||
this = API::moduleImport("pg-cursor").getParameter(0).asSink()
|
||||
or
|
||||
this = query().getParameter(0).asSink()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,7 +253,7 @@ private module Postgres {
|
||||
/**
|
||||
* Provides classes modeling the `sqlite3` package.
|
||||
*/
|
||||
private module Sqlite {
|
||||
private module Sqlite3 {
|
||||
/** Gets an expression that constructs or returns a Sqlite database instance. */
|
||||
API::Node database() { result = API::Node::ofType("sqlite3", "Database") }
|
||||
|
||||
@@ -267,6 +277,62 @@ private module Sqlite {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides classes modeling the `sqlite` package.
|
||||
*/
|
||||
private module Sqlite {
|
||||
/** Gets an expression that constructs or returns a Sqlite database instance. */
|
||||
API::Node database() {
|
||||
result = API::moduleImport("sqlite").getMember("open").getReturn().getPromised()
|
||||
}
|
||||
|
||||
/** A call to a Sqlite query method. */
|
||||
private class QueryCall extends DatabaseAccess, API::CallNode {
|
||||
QueryCall() {
|
||||
this = database().getMember(["all", "each", "exec", "get", "prepare", "run"]).getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getAResult() { result = this }
|
||||
|
||||
override DataFlow::Node getAQueryArgument() { result = this.getArgument(0) }
|
||||
}
|
||||
|
||||
/** An expression that is passed to the `query` method and hence interpreted as SQL. */
|
||||
class QueryString extends SQL::SqlString {
|
||||
QueryString() { this = any(QueryCall qc).getAQueryArgument() }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides classes modeling the `better-sqlite3` package.
|
||||
*/
|
||||
private module BetterSqlite3 {
|
||||
/**
|
||||
* Gets a `better-sqlite3` database instance.
|
||||
*/
|
||||
API::Node database() {
|
||||
result =
|
||||
[
|
||||
API::moduleImport("better-sqlite3").getInstance(),
|
||||
API::moduleImport("better-sqlite3").getReturn()
|
||||
]
|
||||
or
|
||||
result = database().getMember("exec").getReturn()
|
||||
}
|
||||
|
||||
/** A call to a better-sqlite3 query method. */
|
||||
private class QueryCall extends DatabaseAccess, API::CallNode {
|
||||
QueryCall() { this = database().getMember(["exec", "prepare"]).getACall() }
|
||||
|
||||
override DataFlow::Node getAQueryArgument() { result = this.getArgument(0) }
|
||||
}
|
||||
|
||||
/** An expression that is passed to the `query` method and hence interpreted as SQL. */
|
||||
class QueryString extends SQL::SqlString {
|
||||
QueryString() { this = any(QueryCall qc).getAQueryArgument() }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides classes modeling the `mssql` package.
|
||||
*/
|
||||
|
||||
@@ -1,120 +1,52 @@
|
||||
/**
|
||||
* Provides classes and predicates for working with serverless handlers.
|
||||
* E.g. [AWS](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html) or [serverless](https://npmjs.com/package/serverless)
|
||||
* In particular a `RemoteFlowSource` is added for AWS, Alibaba, and serverless.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import codeql.serverless.ServerLess
|
||||
|
||||
private module YamlImpl implements Input {
|
||||
import semmle.javascript.Files
|
||||
import semmle.javascript.YAML
|
||||
}
|
||||
|
||||
module SL = ServerLess<YamlImpl>;
|
||||
|
||||
/**
|
||||
* Provides classes and predicates for working with serverless handlers.
|
||||
* In particular a `RemoteFlowSource` is added for AWS, Alibaba, and serverless.
|
||||
* Gets a function that is a serverless request handler.
|
||||
*
|
||||
* For example: if an AWS serverless resource contains the following properties (in the "template.yml" file):
|
||||
* ```yaml
|
||||
* Handler: mylibrary.handler
|
||||
* Runtime: nodejs12.x
|
||||
* CodeUri: backend/src/
|
||||
* ```
|
||||
*
|
||||
* And a file "mylibrary.js" exists in the folder "backend/src" (relative to the "template.yml" file).
|
||||
* Then the result of this predicate is a function exported as "handler" from "mylibrary.js".
|
||||
* The "mylibrary.js" file could for example look like:
|
||||
*
|
||||
* ```JavaScript
|
||||
* module.exports.handler = function (event) { ... }
|
||||
* ```
|
||||
*/
|
||||
private module ServerLess {
|
||||
/**
|
||||
* Holds if the `.yml` file `ymlFile` contains a serverless configuration with `handler` and `codeURI` properties.
|
||||
* `codeURI` defaults to the empty string if no explicit value is set in the configuration.
|
||||
*/
|
||||
private predicate hasServerlessHandler(File ymlFile, string handler, string codeUri) {
|
||||
exists(YamlMapping resource | ymlFile = resource.getFile() |
|
||||
// There exists at least "AWS::Serverless::Function" and "Aliyun::Serverless::Function"
|
||||
resource.lookup("Type").(YamlScalar).getValue().regexpMatch(".*::Serverless::Function") and
|
||||
exists(YamlMapping properties | properties = resource.lookup("Properties") |
|
||||
handler = properties.lookup("Handler").(YamlScalar).getValue() and
|
||||
if exists(properties.lookup("CodeUri"))
|
||||
then codeUri = properties.lookup("CodeUri").(YamlScalar).getValue()
|
||||
else codeUri = ""
|
||||
)
|
||||
or
|
||||
// The `serverless` library, which specifies a top-level `functions` property
|
||||
exists(YamlMapping functions |
|
||||
functions = resource.lookup("functions") and
|
||||
not exists(resource.getParentNode()) and
|
||||
handler = functions.getValue(_).(YamlMapping).lookup("handler").(YamlScalar).getValue() and
|
||||
codeUri = ""
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string where an ending "/." is simplified to "/" (if it exists).
|
||||
*/
|
||||
bindingset[base]
|
||||
private string removeTrailingDot(string base) {
|
||||
if base.regexpMatch(".*/\\.")
|
||||
then result = base.substring(0, base.length() - 1)
|
||||
else result = base
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string where a leading "./" is simplified to "" (if it exists).
|
||||
*/
|
||||
bindingset[base]
|
||||
private string removeLeadingDotSlash(string base) {
|
||||
if base.regexpMatch("\\./.*") then result = base.substring(2, base.length()) else result = base
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a path to a file from a `codeURI` property and a file name from a serverless configuration.
|
||||
*
|
||||
* For example if `codeURI` is "function/." and `file` is "index", then the result becomes "function/index.js".
|
||||
*/
|
||||
bindingset[codeUri, file]
|
||||
private string getPathFromHandlerProperties(string codeUri, string file) {
|
||||
exists(string folder | folder = removeLeadingDotSlash(removeTrailingDot(codeUri)) |
|
||||
result = folder + file + ".js"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `file` has a serverless handler function with name `func`.
|
||||
*/
|
||||
private predicate hasServerlessHandler(File file, string func) {
|
||||
exists(File ymlFile, string handler, string codeUri, string fileName |
|
||||
hasServerlessHandler(ymlFile, handler, codeUri) and
|
||||
// Splits a `handler` into two components. The `fileName` to the left of the dot, and the `func` to the right.
|
||||
// E.g. if `handler` is "index.foo", then `fileName` is "index" and `func` is "foo".
|
||||
exists(string pattern | pattern = "(.*)\\.(.*)" |
|
||||
fileName = handler.regexpCapture(pattern, 1) and
|
||||
func = handler.regexpCapture(pattern, 2)
|
||||
)
|
||||
|
|
||||
file.getAbsolutePath() =
|
||||
ymlFile.getParentContainer().getAbsolutePath() + "/" +
|
||||
getPathFromHandlerProperties(codeUri, fileName)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a function that is a serverless request handler.
|
||||
*
|
||||
* For example: if an AWS serverless resource contains the following properties (in the "template.yml" file):
|
||||
* ```yaml
|
||||
* Handler: mylibrary.handler
|
||||
* Runtime: nodejs12.x
|
||||
* CodeUri: backend/src/
|
||||
* ```
|
||||
*
|
||||
* And a file "mylibrary.js" exists in the folder "backend/src" (relative to the "template.yml" file).
|
||||
* Then the result of this predicate is a function exported as "handler" from "mylibrary.js".
|
||||
* The "mylibrary.js" file could for example look like:
|
||||
*
|
||||
* ```JavaScript
|
||||
* module.exports.handler = function (event) { ... }
|
||||
* ```
|
||||
*/
|
||||
private DataFlow::FunctionNode getAServerlessHandler() {
|
||||
exists(File file, string handler, Module mod | hasServerlessHandler(file, handler) |
|
||||
mod.getFile() = file and
|
||||
result = mod.getAnExportedValue(handler).getAFunctionValue()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A serverless request handler event, seen as a RemoteFlowSource.
|
||||
*/
|
||||
private class ServerlessHandlerEventAsRemoteFlow extends RemoteFlowSource {
|
||||
ServerlessHandlerEventAsRemoteFlow() { this = getAServerlessHandler().getParameter(0) }
|
||||
|
||||
override string getSourceType() { result = "Serverless event" }
|
||||
}
|
||||
private DataFlow::FunctionNode getAServerlessHandler() {
|
||||
exists(File file, string stem, string handler, Module mod |
|
||||
SL::hasServerlessHandler(stem, handler, _, _) and
|
||||
file.getAbsolutePath() = stem + ".js"
|
||||
|
|
||||
mod.getFile() = file and
|
||||
result = mod.getAnExportedValue(handler).getAFunctionValue()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A serverless request handler event, seen as a RemoteFlowSource.
|
||||
*/
|
||||
private class ServerlessHandlerEventAsRemoteFlow extends RemoteFlowSource {
|
||||
ServerlessHandlerEventAsRemoteFlow() { this = getAServerlessHandler().getParameter(0) }
|
||||
|
||||
override string getSourceType() { result = "Serverless event" }
|
||||
}
|
||||
|
||||
@@ -580,6 +580,22 @@ module Templating {
|
||||
override string getAPackageName() { result = "ejs" }
|
||||
}
|
||||
|
||||
/**
|
||||
* doT-style syntax, using `{{! }}` for safe interpolation, and `{{= }}` for
|
||||
* unsafe interpolation.
|
||||
*/
|
||||
private class DotStyleSyntax extends TemplateSyntax {
|
||||
DotStyleSyntax() { this = "dot" }
|
||||
|
||||
override string getRawInterpolationRegexp() { result = "(?s)\\{\\{!(.*?)\\}\\}" }
|
||||
|
||||
override string getEscapingInterpolationRegexp() { result = "(?s)\\{\\{=(.*?)\\}\\}" }
|
||||
|
||||
override string getAFileExtension() { result = "dot" }
|
||||
|
||||
override string getAPackageName() { result = "dot" }
|
||||
}
|
||||
|
||||
private TemplateSyntax getOwnTemplateSyntaxInFolder(Folder f) {
|
||||
exists(PackageDependencies deps |
|
||||
deps.getADependency(result.getAPackageName(), _) and
|
||||
|
||||
@@ -37,9 +37,6 @@ class BddTest extends Test, @call_expr {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for BddTest */
|
||||
deprecated class BDDTest = BddTest;
|
||||
|
||||
/**
|
||||
* Gets the test file for `f` with stem extension `stemExt`, where `stemExt` is "test" or "spec".
|
||||
* That is, a file named `<base>.<stemExt>.<ext>` in the
|
||||
|
||||
@@ -20,9 +20,7 @@ module Vue {
|
||||
private class VueExportEntryPoint extends API::EntryPoint {
|
||||
VueExportEntryPoint() { this = "VueExportEntryPoint" }
|
||||
|
||||
override DataFlow::Node getASink() {
|
||||
result = any(SingleFileComponent c).getModule().getDefaultOrBulkExport()
|
||||
}
|
||||
override DataFlow::Node getASink() { result = getModuleFromVueFile(_).getDefaultOrBulkExport() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -455,6 +453,13 @@ module Vue {
|
||||
}
|
||||
}
|
||||
|
||||
private Module getModuleFromVueFile(VueFile file) {
|
||||
exists(HTML::ScriptElement elem |
|
||||
xmlElements(elem, _, _, _, file) and // Avoid materializing all of Locatable.getFile()
|
||||
result.getTopLevel() = elem.getScript()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A single file Vue component in a `.vue` file.
|
||||
*/
|
||||
@@ -482,12 +487,7 @@ module Vue {
|
||||
}
|
||||
|
||||
/** Gets the module defined by the `script` tag in this .vue file, if any. */
|
||||
Module getModule() {
|
||||
exists(HTML::ScriptElement elem |
|
||||
xmlElements(elem, _, _, _, file) and // Avoid materializing all of Locatable.getFile()
|
||||
result.getTopLevel() = elem.getScript()
|
||||
)
|
||||
}
|
||||
Module getModule() { result = getModuleFromVueFile(file) }
|
||||
|
||||
override API::Node getComponentRef() {
|
||||
// There is no explicit `new Vue()` call in .vue files, so instead get all the imports
|
||||
|
||||
23
javascript/ql/lib/semmle/javascript/frameworks/Webix.qll
Normal file
23
javascript/ql/lib/semmle/javascript/frameworks/Webix.qll
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Provides classes and predicates for working with the `webix` library.
|
||||
*/
|
||||
|
||||
private import javascript
|
||||
|
||||
/**
|
||||
* Provides classes and predicates for working with the `webix` library.
|
||||
*/
|
||||
module Webix {
|
||||
/** The global variable `webix` as an entry point for API graphs. */
|
||||
private class WebixGlobalEntry extends API::EntryPoint {
|
||||
WebixGlobalEntry() { this = "WebixGlobalEntry" }
|
||||
|
||||
override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("webix") }
|
||||
}
|
||||
|
||||
/** Gets a reference to the Webix package. */
|
||||
API::Node webix() {
|
||||
result = API::moduleImport("webix") or
|
||||
result = any(WebixGlobalEntry w).getANode()
|
||||
}
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
/**
|
||||
* Module for parsing access paths from MaD models, both the identifying access path used
|
||||
* by dynamic languages, and the input/output specifications for summary steps.
|
||||
*
|
||||
* This file is used by the shared data flow library and by the JavaScript libraries
|
||||
* (which does not use the shared data flow libraries).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Convenience-predicate for extracting two capture groups at once.
|
||||
*/
|
||||
bindingset[input, regexp]
|
||||
private predicate regexpCaptureTwo(string input, string regexp, string capture1, string capture2) {
|
||||
capture1 = input.regexpCapture(regexp, 1) and
|
||||
capture2 = input.regexpCapture(regexp, 2)
|
||||
}
|
||||
|
||||
/** Companion module to the `AccessPath` class. */
|
||||
module AccessPath {
|
||||
/** A string that should be parsed as an access path. */
|
||||
abstract class Range extends string {
|
||||
bindingset[this]
|
||||
Range() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an integer constant `n` or interval `n1..n2` (inclusive) and gets the value
|
||||
* of the constant or any value contained in the interval.
|
||||
*/
|
||||
bindingset[arg]
|
||||
int parseInt(string arg) {
|
||||
result = arg.toInt()
|
||||
or
|
||||
// Match "n1..n2"
|
||||
exists(string lo, string hi |
|
||||
regexpCaptureTwo(arg, "(-?\\d+)\\.\\.(-?\\d+)", lo, hi) and
|
||||
result = [lo.toInt() .. hi.toInt()]
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a lower-bounded interval `n..` and gets the lower bound.
|
||||
*/
|
||||
bindingset[arg]
|
||||
int parseLowerBound(string arg) { result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt() }
|
||||
|
||||
/**
|
||||
* Parses an integer constant or interval (bounded or unbounded) that explicitly
|
||||
* references the arity, such as `N-1` or `N-3..N-1`.
|
||||
*
|
||||
* Note that expressions of form `N-x` will never resolve to a negative index,
|
||||
* even if `N` is zero (it will have no result in that case).
|
||||
*/
|
||||
bindingset[arg, arity]
|
||||
private int parseIntWithExplicitArity(string arg, int arity) {
|
||||
result >= 0 and // do not allow N-1 to resolve to a negative index
|
||||
exists(string lo |
|
||||
// N-x
|
||||
lo = arg.regexpCapture("N-(\\d+)", 1) and
|
||||
result = arity - lo.toInt()
|
||||
or
|
||||
// N-x..
|
||||
lo = arg.regexpCapture("N-(\\d+)\\.\\.", 1) and
|
||||
result = [arity - lo.toInt(), arity - 1]
|
||||
)
|
||||
or
|
||||
exists(string lo, string hi |
|
||||
// x..N-y
|
||||
regexpCaptureTwo(arg, "(-?\\d+)\\.\\.N-(\\d+)", lo, hi) and
|
||||
result = [lo.toInt() .. arity - hi.toInt()]
|
||||
or
|
||||
// N-x..N-y
|
||||
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.N-(\\d+)", lo, hi) and
|
||||
result = [arity - lo.toInt() .. arity - hi.toInt()] and
|
||||
result >= 0
|
||||
or
|
||||
// N-x..y
|
||||
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.(\\d+)", lo, hi) and
|
||||
result = [arity - lo.toInt() .. hi.toInt()] and
|
||||
result >= 0
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an integer constant or interval (bounded or unbounded) and gets any
|
||||
* of the integers contained within (of which there may be infinitely many).
|
||||
*
|
||||
* Has no result for arguments involving an explicit arity, such as `N-1`.
|
||||
*/
|
||||
bindingset[arg, result]
|
||||
int parseIntUnbounded(string arg) {
|
||||
result = parseInt(arg)
|
||||
or
|
||||
result >= parseLowerBound(arg)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an integer constant or interval (bounded or unbounded) that
|
||||
* may reference the arity of a call, such as `N-1` or `N-3..N-1`.
|
||||
*
|
||||
* Note that expressions of form `N-x` will never resolve to a negative index,
|
||||
* even if `N` is zero (it will have no result in that case).
|
||||
*/
|
||||
bindingset[arg, arity]
|
||||
int parseIntWithArity(string arg, int arity) {
|
||||
result = parseInt(arg)
|
||||
or
|
||||
result in [parseLowerBound(arg) .. arity - 1]
|
||||
or
|
||||
result = parseIntWithExplicitArity(arg, arity)
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets the `n`th token on the access path as a string. */
|
||||
private string getRawToken(AccessPath path, int n) {
|
||||
// Avoid splitting by '.' since tokens may contain dots, e.g. `Field[foo.Bar.x]`.
|
||||
// Instead use regexpFind to match valid tokens, and supplement with a final length
|
||||
// check (in `AccessPath.hasSyntaxError`) to ensure all characters were included in a token.
|
||||
result = path.regexpFind("\\w+(?:\\[[^\\]]*\\])?(?=\\.|$)", n, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* A string that occurs as an access path (either identifying or input/output spec)
|
||||
* which might be relevant for this database.
|
||||
*/
|
||||
class AccessPath extends string instanceof AccessPath::Range {
|
||||
/** Holds if this string is not a syntactically valid access path. */
|
||||
predicate hasSyntaxError() {
|
||||
// If the lengths match, all characters must haven been included in a token
|
||||
// or seen by the `.` lookahead pattern.
|
||||
this != "" and
|
||||
not this.length() = sum(int n | | getRawToken(this, n).length() + 1) - 1
|
||||
}
|
||||
|
||||
/** Gets the `n`th token on the access path (if there are no syntax errors). */
|
||||
AccessPathToken getToken(int n) {
|
||||
result = getRawToken(this, n) and
|
||||
not this.hasSyntaxError()
|
||||
}
|
||||
|
||||
/** Gets the number of tokens on the path (if there are no syntax errors). */
|
||||
int getNumToken() {
|
||||
result = count(int n | exists(getRawToken(this, n))) and
|
||||
not this.hasSyntaxError()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An access part token such as `Argument[1]` or `ReturnValue`, appearing in one or more access paths.
|
||||
*/
|
||||
class AccessPathToken extends string {
|
||||
AccessPathToken() { this = getRawToken(_, _) }
|
||||
|
||||
private string getPart(int part) {
|
||||
result = this.regexpCapture("([^\\[]+)(?:\\[([^\\]]*)\\])?", part)
|
||||
}
|
||||
|
||||
/** Gets the name of the token, such as `Member` from `Member[x]` */
|
||||
string getName() { result = this.getPart(1) }
|
||||
|
||||
/**
|
||||
* Gets the argument list, such as `1,2` from `Member[1,2]`,
|
||||
* or has no result if there are no arguments.
|
||||
*/
|
||||
string getArgumentList() { result = this.getPart(2) }
|
||||
|
||||
/** Gets the `n`th argument to this token, such as `x` or `y` from `Member[x,y]`. */
|
||||
string getArgument(int n) { result = this.getArgumentList().splitAt(",", n).trim() }
|
||||
|
||||
/** Gets the `n`th argument to this `name` token, such as `x` or `y` from `Member[x,y]`. */
|
||||
pragma[nomagic]
|
||||
string getArgument(string name, int n) { name = this.getName() and result = this.getArgument(n) }
|
||||
|
||||
/** Gets an argument to this token, such as `x` or `y` from `Member[x,y]`. */
|
||||
string getAnArgument() { result = this.getArgument(_) }
|
||||
|
||||
/** Gets an argument to this `name` token, such as `x` or `y` from `Member[x,y]`. */
|
||||
string getAnArgument(string name) { result = this.getArgument(name, _) }
|
||||
|
||||
/** Gets the number of arguments to this token, such as 2 for `Member[x,y]` or zero for `ReturnValue`. */
|
||||
int getNumArgument() { result = count(int n | exists(this.getArgument(n))) }
|
||||
}
|
||||
@@ -70,8 +70,8 @@ private module API = Specific::API;
|
||||
|
||||
private module DataFlow = Specific::DataFlow;
|
||||
|
||||
private import Specific::AccessPathSyntax
|
||||
private import ApiGraphModelsExtensions as Extensions
|
||||
private import codeql.dataflow.internal.AccessPathSyntax
|
||||
|
||||
/** Module containing hooks for providing input data to be interpreted as a model. */
|
||||
module ModelInput {
|
||||
@@ -327,29 +327,29 @@ predicate isRelevantFullPath(string type, string path) {
|
||||
}
|
||||
|
||||
/** A string from a CSV row that should be parsed as an access path. */
|
||||
private class AccessPathRange extends AccessPath::Range {
|
||||
AccessPathRange() {
|
||||
isRelevantFullPath(_, this)
|
||||
or
|
||||
exists(string type | isRelevantType(type) |
|
||||
summaryModel(type, _, this, _, _) or
|
||||
summaryModel(type, _, _, this, _)
|
||||
)
|
||||
or
|
||||
typeVariableModel(_, this)
|
||||
}
|
||||
private predicate accessPathRange(string s) {
|
||||
isRelevantFullPath(_, s)
|
||||
or
|
||||
exists(string type | isRelevantType(type) |
|
||||
summaryModel(type, _, s, _, _) or
|
||||
summaryModel(type, _, _, s, _)
|
||||
)
|
||||
or
|
||||
typeVariableModel(_, s)
|
||||
}
|
||||
|
||||
import AccessPath<accessPathRange/1>
|
||||
|
||||
/**
|
||||
* Gets a successor of `node` in the API graph.
|
||||
*/
|
||||
bindingset[token]
|
||||
API::Node getSuccessorFromNode(API::Node node, AccessPathToken token) {
|
||||
API::Node getSuccessorFromNode(API::Node node, AccessPathTokenBase token) {
|
||||
// API graphs use the same label for arguments and parameters. An edge originating from a
|
||||
// use-node represents an argument, and an edge originating from a def-node represents a parameter.
|
||||
// We just map both to the same thing.
|
||||
token.getName() = ["Argument", "Parameter"] and
|
||||
result = node.getParameter(AccessPath::parseIntUnbounded(token.getAnArgument()))
|
||||
result = node.getParameter(parseIntUnbounded(token.getAnArgument()))
|
||||
or
|
||||
token.getName() = "ReturnValue" and
|
||||
result = node.getReturn()
|
||||
@@ -362,11 +362,9 @@ API::Node getSuccessorFromNode(API::Node node, AccessPathToken token) {
|
||||
* Gets an API-graph successor for the given invocation.
|
||||
*/
|
||||
bindingset[token]
|
||||
API::Node getSuccessorFromInvoke(Specific::InvokeNode invoke, AccessPathToken token) {
|
||||
API::Node getSuccessorFromInvoke(Specific::InvokeNode invoke, AccessPathTokenBase token) {
|
||||
token.getName() = "Argument" and
|
||||
result =
|
||||
invoke
|
||||
.getParameter(AccessPath::parseIntWithArity(token.getAnArgument(), invoke.getNumArgument()))
|
||||
result = invoke.getParameter(parseIntWithArity(token.getAnArgument(), invoke.getNumArgument()))
|
||||
or
|
||||
token.getName() = "ReturnValue" and
|
||||
result = invoke.getReturn()
|
||||
@@ -378,10 +376,12 @@ API::Node getSuccessorFromInvoke(Specific::InvokeNode invoke, AccessPathToken to
|
||||
/**
|
||||
* Holds if `invoke` invokes a call-site filter given by `token`.
|
||||
*/
|
||||
pragma[inline]
|
||||
private predicate invocationMatchesCallSiteFilter(Specific::InvokeNode invoke, AccessPathToken token) {
|
||||
bindingset[token]
|
||||
private predicate invocationMatchesCallSiteFilter(
|
||||
Specific::InvokeNode invoke, AccessPathTokenBase token
|
||||
) {
|
||||
token.getName() = "WithArity" and
|
||||
invoke.getNumArgument() = AccessPath::parseIntUnbounded(token.getAnArgument())
|
||||
invoke.getNumArgument() = parseIntUnbounded(token.getAnArgument())
|
||||
or
|
||||
Specific::invocationMatchesExtraCallSiteFilter(invoke, token)
|
||||
}
|
||||
@@ -454,6 +454,14 @@ private API::Node getNodeFromPath(string type, AccessPath path, int n) {
|
||||
or
|
||||
// Apply a type step
|
||||
typeStep(getNodeFromPath(type, path, n), result)
|
||||
or
|
||||
// Apply a fuzzy step (without advancing 'n')
|
||||
path.getToken(n).getName() = "Fuzzy" and
|
||||
result = Specific::getAFuzzySuccessor(getNodeFromPath(type, path, n))
|
||||
or
|
||||
// Skip a fuzzy step (advance 'n' without changing the current node)
|
||||
path.getToken(n - 1).getName() = "Fuzzy" and
|
||||
result = getNodeFromPath(type, path, n - 1)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -500,6 +508,14 @@ private API::Node getNodeFromSubPath(API::Node base, AccessPath subPath, int n)
|
||||
// will themselves find by following type-steps.
|
||||
n > 0 and
|
||||
n < subPath.getNumToken()
|
||||
or
|
||||
// Apply a fuzzy step (without advancing 'n')
|
||||
subPath.getToken(n).getName() = "Fuzzy" and
|
||||
result = Specific::getAFuzzySuccessor(getNodeFromSubPath(base, subPath, n))
|
||||
or
|
||||
// Skip a fuzzy step (advance 'n' without changing the current node)
|
||||
subPath.getToken(n - 1).getName() = "Fuzzy" and
|
||||
result = getNodeFromSubPath(base, subPath, n - 1)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -561,7 +577,7 @@ private Specific::InvokeNode getInvocationFromPath(string type, AccessPath path)
|
||||
*/
|
||||
bindingset[name]
|
||||
private predicate isValidTokenNameInIdentifyingAccessPath(string name) {
|
||||
name = ["Argument", "Parameter", "ReturnValue", "WithArity", "TypeVar"]
|
||||
name = ["Argument", "Parameter", "ReturnValue", "WithArity", "TypeVar", "Fuzzy"]
|
||||
or
|
||||
Specific::isExtraValidTokenNameInIdentifyingAccessPath(name)
|
||||
}
|
||||
@@ -572,7 +588,7 @@ private predicate isValidTokenNameInIdentifyingAccessPath(string name) {
|
||||
*/
|
||||
bindingset[name]
|
||||
private predicate isValidNoArgumentTokenInIdentifyingAccessPath(string name) {
|
||||
name = "ReturnValue"
|
||||
name = ["ReturnValue", "Fuzzy"]
|
||||
or
|
||||
Specific::isExtraValidNoArgumentTokenInIdentifyingAccessPath(name)
|
||||
}
|
||||
@@ -643,6 +659,15 @@ module ModelOutput {
|
||||
baseNode = getInvocationFromPath(type, path)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a `baseNode` is a callable identified by the `type,path` part of a summary row.
|
||||
*/
|
||||
cached
|
||||
predicate resolvedSummaryRefBase(string type, string path, API::Node baseNode) {
|
||||
summaryModel(type, path, _, _, _) and
|
||||
baseNode = getNodeFromPath(type, path)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is seen as an instance of `type` due to a type definition
|
||||
* contributed by a CSV model.
|
||||
|
||||
@@ -17,7 +17,7 @@ extensible predicate sourceModel(string type, string path, string kind);
|
||||
extensible predicate sinkModel(string type, string path, string kind);
|
||||
|
||||
/**
|
||||
* Holds if calls to `(type, path)`, the value referred to by `input`
|
||||
* Holds if in calls to `(type, path)`, the value referred to by `input`
|
||||
* can flow to the value referred to by `output`.
|
||||
*
|
||||
* `kind` should be either `value` or `taint`, for value-preserving or taint-preserving steps,
|
||||
@@ -25,6 +25,13 @@ extensible predicate sinkModel(string type, string path, string kind);
|
||||
*/
|
||||
extensible predicate summaryModel(string type, string path, string input, string output, string kind);
|
||||
|
||||
/**
|
||||
* Holds if calls to `(type, path)` should be considered neutral. The meaning of this depends on the `kind`.
|
||||
* If `kind` is `summary`, the call does not propagate data flow. If `kind` is `source`, the call is not a source.
|
||||
* If `kind` is `sink`, the call is not a sink.
|
||||
*/
|
||||
extensible predicate neutralModel(string type, string path, string kind);
|
||||
|
||||
/**
|
||||
* Holds if `(type2, path)` should be seen as an instance of `type1`.
|
||||
*/
|
||||
|
||||
@@ -4,14 +4,13 @@
|
||||
* It must export the following members:
|
||||
* ```ql
|
||||
* class Unit // a unit type
|
||||
* module AccessPathSyntax // a re-export of the AccessPathSyntax module
|
||||
* class InvokeNode // a type representing an invocation connected to the API graph
|
||||
* module API // the API graph module
|
||||
* predicate isPackageUsed(string package)
|
||||
* API::Node getExtraNodeFromPath(string package, string type, string path, int n)
|
||||
* API::Node getExtraSuccessorFromNode(API::Node node, AccessPathToken token)
|
||||
* API::Node getExtraSuccessorFromInvoke(InvokeNode node, AccessPathToken token)
|
||||
* predicate invocationMatchesExtraCallSiteFilter(InvokeNode invoke, AccessPathToken token)
|
||||
* API::Node getExtraSuccessorFromNode(API::Node node, AccessPathTokenBase token)
|
||||
* API::Node getExtraSuccessorFromInvoke(InvokeNode node, AccessPathTokenBase token)
|
||||
* predicate invocationMatchesExtraCallSiteFilter(InvokeNode invoke, AccessPathTokenBase token)
|
||||
* InvokeNode getAnInvocationOf(API::Node node)
|
||||
* predicate isExtraValidTokenNameInIdentifyingAccessPath(string name)
|
||||
* predicate isExtraValidNoArgumentTokenInIdentifyingAccessPath(string name)
|
||||
@@ -21,13 +20,12 @@
|
||||
|
||||
private import javascript as JS
|
||||
private import ApiGraphModels
|
||||
private import codeql.dataflow.internal.AccessPathSyntax
|
||||
|
||||
// Re-export libraries needed by ApiGraphModels.qll
|
||||
module API = JS::API;
|
||||
|
||||
import semmle.javascript.frameworks.data.internal.AccessPathSyntax as AccessPathSyntax
|
||||
import JS::DataFlow as DataFlow
|
||||
private import AccessPathSyntax
|
||||
|
||||
/**
|
||||
* Holds if `rawType` represents the JavaScript type `qualifiedName` from the given NPM `package`.
|
||||
@@ -50,6 +48,8 @@ predicate parseTypeString(string rawType, string package, string qualifiedName)
|
||||
predicate isPackageUsed(string package) {
|
||||
exists(DataFlow::moduleImport(package))
|
||||
or
|
||||
exists(JS::PackageJson json | json.getPackageName() = package)
|
||||
or
|
||||
package = "global"
|
||||
or
|
||||
any(DataFlow::SourceNode sn).hasUnderlyingType(package, _)
|
||||
@@ -126,7 +126,7 @@ API::Node getExtraNodeFromType(string type) {
|
||||
parseRelevantTypeString(type, package, qualifiedName)
|
||||
|
|
||||
qualifiedName = "" and
|
||||
result = API::moduleImport(package)
|
||||
result = [API::moduleImport(package), API::moduleExport(package)]
|
||||
or
|
||||
// Access instance of a type based on type annotations
|
||||
result = API::Internal::getANodeOfTypeRaw(package, qualifiedName)
|
||||
@@ -137,7 +137,7 @@ API::Node getExtraNodeFromType(string type) {
|
||||
* Gets a JavaScript-specific API graph successor of `node` reachable by resolving `token`.
|
||||
*/
|
||||
bindingset[token]
|
||||
API::Node getExtraSuccessorFromNode(API::Node node, AccessPathToken token) {
|
||||
API::Node getExtraSuccessorFromNode(API::Node node, AccessPathTokenBase token) {
|
||||
token.getName() = "Member" and
|
||||
result = node.getMember(token.getAnArgument())
|
||||
or
|
||||
@@ -183,7 +183,7 @@ API::Node getExtraSuccessorFromNode(API::Node node, AccessPathToken token) {
|
||||
* Gets a JavaScript-specific API graph successor of `node` reachable by resolving `token`.
|
||||
*/
|
||||
bindingset[token]
|
||||
API::Node getExtraSuccessorFromInvoke(API::InvokeNode node, AccessPathToken token) {
|
||||
API::Node getExtraSuccessorFromInvoke(API::InvokeNode node, AccessPathTokenBase token) {
|
||||
token.getName() = "Instance" and
|
||||
result = node.getInstance()
|
||||
or
|
||||
@@ -192,11 +192,48 @@ API::Node getExtraSuccessorFromInvoke(API::InvokeNode node, AccessPathToken toke
|
||||
result.asSink() = node.(DataFlow::CallNode).getReceiver()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `name` is the name of a built-in method on Object, Array, or String.
|
||||
*/
|
||||
private predicate isCommonBuiltinMethodName(string name) {
|
||||
exists(JS::ExternalInstanceMemberDecl member |
|
||||
member.getBaseName() in ["Object", "Array", "String"] and
|
||||
name = member.getName()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if fuzzy evaluation should not traverse through `call`.
|
||||
*/
|
||||
private predicate blockFuzzyCall(DataFlow::CallNode call) {
|
||||
isCommonBuiltinMethodName(call.getCalleeName())
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
API::Node getAFuzzySuccessor(API::Node node) {
|
||||
result = node.getAMember() and
|
||||
// Block traversal into calls to built-ins like .toString() and .substring()
|
||||
// Since there is no API node representing the call itself, block flow into the callee node.
|
||||
not exists(DataFlow::CallNode call |
|
||||
node.asSource() = call.getCalleeNode() and
|
||||
blockFuzzyCall(call)
|
||||
)
|
||||
or
|
||||
result = node.getAParameter()
|
||||
or
|
||||
result = node.getReturn()
|
||||
or
|
||||
result = node.getPromised()
|
||||
or
|
||||
// include 'this' parameters but not 'this' arguments
|
||||
result = node.getReceiver() and result.asSource() instanceof DataFlow::ThisNode
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `invoke` matches the JS-specific call site filter in `token`.
|
||||
*/
|
||||
bindingset[token]
|
||||
predicate invocationMatchesExtraCallSiteFilter(API::InvokeNode invoke, AccessPathToken token) {
|
||||
predicate invocationMatchesExtraCallSiteFilter(API::InvokeNode invoke, AccessPathTokenBase token) {
|
||||
token.getName() = "NewCall" and
|
||||
invoke instanceof API::NewNode
|
||||
or
|
||||
@@ -209,9 +246,8 @@ predicate invocationMatchesExtraCallSiteFilter(API::InvokeNode invoke, AccessPat
|
||||
operand = token.getAnArgument() and
|
||||
argIndex = operand.splitAt("=", 0) and
|
||||
stringValue = operand.splitAt("=", 1) and
|
||||
invoke
|
||||
.getArgument(AccessPath::parseIntWithArity(argIndex, invoke.getNumArgument()))
|
||||
.getStringValue() = stringValue
|
||||
invoke.getArgument(parseIntWithArity(argIndex, invoke.getNumArgument())).getStringValue() =
|
||||
stringValue
|
||||
)
|
||||
}
|
||||
|
||||
@@ -301,7 +337,7 @@ predicate isExtraValidTokenArgumentInIdentifyingAccessPath(string name, string a
|
||||
or
|
||||
name = "WithStringArgument" and
|
||||
exists(argument.indexOf("=")) and
|
||||
exists(AccessPath::parseIntWithArity(argument.splitAt("=", 0), 10))
|
||||
exists(parseIntWithArity(argument.splitAt("=", 0), 10))
|
||||
}
|
||||
|
||||
module ModelOutputSpecific {
|
||||
|
||||
@@ -15,6 +15,11 @@ extensions:
|
||||
extensible: summaryModel
|
||||
data: []
|
||||
|
||||
- addsTo:
|
||||
pack: codeql/javascript-all
|
||||
extensible: neutralModel
|
||||
data: []
|
||||
|
||||
- addsTo:
|
||||
pack: codeql/javascript-all
|
||||
extensible: typeModel
|
||||
|
||||
@@ -145,6 +145,12 @@ module Stages {
|
||||
exists(any(DataFlow::PropRef ref).getBase())
|
||||
or
|
||||
exists(any(DataFlow::ClassNode cls))
|
||||
or
|
||||
exists(any(DataFlow::CallNode node).getArgument(_))
|
||||
or
|
||||
exists(any(DataFlow::CallNode node).getAnArgument())
|
||||
or
|
||||
exists(any(DataFlow::CallNode node).getLastArgument())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,9 @@ module Cryptography {
|
||||
/** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */
|
||||
CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() }
|
||||
|
||||
/** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */
|
||||
DataFlow::Node getInitialization() { result = super.getInitialization() }
|
||||
|
||||
/** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */
|
||||
DataFlow::Node getAnInput() { result = super.getAnInput() }
|
||||
|
||||
@@ -65,6 +68,9 @@ module Cryptography {
|
||||
* extend `CryptographicOperation` instead.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */
|
||||
abstract DataFlow::Node getInitialization();
|
||||
|
||||
/** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */
|
||||
abstract CryptographicAlgorithm getAlgorithm();
|
||||
|
||||
|
||||
@@ -15,6 +15,14 @@ private class DangerousPrefix extends string {
|
||||
this = "<!--" or
|
||||
this = "<" + ["iframe", "script", "cript", "scrip", "style"]
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a character that is important to the dangerous prefix.
|
||||
* That is, a char that should be mentioned in a regular expression that explicitly sanitizes the dangerous prefix.
|
||||
*/
|
||||
string getAnImportantChar() {
|
||||
if this = ["/..", "../"] then result = ["/", "."] else result = "<"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,7 +70,11 @@ private DangerousPrefixSubstring getADangerousMatchedChar(EmptyReplaceRegExpTerm
|
||||
*/
|
||||
private DangerousPrefix getADangerousMatchedPrefix(EmptyReplaceRegExpTerm t) {
|
||||
result = getADangerousMatchedPrefixSubstring(t) and
|
||||
not exists(EmptyReplaceRegExpTerm pred | pred = t.getPredecessor+() and not pred.isNullable())
|
||||
not exists(EmptyReplaceRegExpTerm pred | pred = t.getPredecessor+() and not pred.isNullable()) and
|
||||
// the regex must explicitly mention a char important to the prefix.
|
||||
forex(string char | char = result.getAnImportantChar() |
|
||||
t.getRootTerm().getAChild*().(RegExpConstant).getValue().matches("%" + char + "%")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,22 +13,6 @@ import javascript
|
||||
import semmle.javascript.security.internal.SensitiveDataHeuristics
|
||||
private import HeuristicNames
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `SensitiveNode` instead.
|
||||
* An expression that might contain sensitive data.
|
||||
*/
|
||||
deprecated class SensitiveExpr extends Expr {
|
||||
SensitiveNode node;
|
||||
|
||||
SensitiveExpr() { node.asExpr() = this }
|
||||
|
||||
/** Gets a human-readable description of this expression for use in alert messages. */
|
||||
deprecated string describe() { result = node.describe() }
|
||||
|
||||
/** Gets a classification of the kind of sensitive data this expression might contain. */
|
||||
deprecated SensitiveDataClassification getClassification() { result = node.getClassification() }
|
||||
}
|
||||
|
||||
/** An expression that might contain sensitive data. */
|
||||
cached
|
||||
abstract class SensitiveNode extends DataFlow::Node {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user