mirror of
https://github.com/github/codeql.git
synced 2026-04-30 03:05:15 +02:00
Merge branch 'main' into moreReDoS
This commit is contained in:
22
javascript/ql/src/IDEContextual.qll
Normal file
22
javascript/ql/src/IDEContextual.qll
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Provides shared predicates related to contextual queries in the code viewer.
|
||||
*/
|
||||
|
||||
import semmle.files.FileSystem
|
||||
|
||||
/**
|
||||
* Returns the `File` matching the given source file name as encoded by the VS
|
||||
* Code extension.
|
||||
*/
|
||||
cached
|
||||
File getFileBySourceArchiveName(string name) {
|
||||
// The name provided for a file in the source archive by the VS Code extension
|
||||
// has some differences from the absolute path in the database:
|
||||
// 1. colons are replaced by underscores
|
||||
// 2. there's a leading slash, even for Windows paths: "C:/foo/bar" ->
|
||||
// "/C_/foo/bar"
|
||||
// 3. double slashes in UNC prefixes are replaced with a single slash
|
||||
// We can handle 2 and 3 together by unconditionally adding a leading slash
|
||||
// before replacing double slashes.
|
||||
name = ("/" + result.getAbsolutePath().replaceAll(":", "_")).replaceAll("//", "/")
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import IDEContextual
|
||||
private import Declarations.Declarations
|
||||
|
||||
/**
|
||||
@@ -178,11 +179,3 @@ ASTNode definitionOf(Locatable e, string kind) {
|
||||
or
|
||||
jsdocTypeLookup(e, result, kind)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an appropriately encoded version of a filename `name`
|
||||
* passed by the VS Code extension in order to coincide with the
|
||||
* output of `.getFile()` on locatable entities.
|
||||
*/
|
||||
cached
|
||||
File getEncodedFile(string name) { result.getAbsolutePath().replaceAll(":", "_") = name }
|
||||
|
||||
@@ -123,9 +123,11 @@ module Cookie {
|
||||
class InsecureJsCookie extends Cookie {
|
||||
InsecureJsCookie() {
|
||||
this =
|
||||
[DataFlow::globalVarRef("Cookie"),
|
||||
DataFlow::globalVarRef("Cookie").getAMemberCall("noConflict"),
|
||||
DataFlow::moduleImport("js-cookie")].getAMemberCall("set")
|
||||
[
|
||||
DataFlow::globalVarRef("Cookie"),
|
||||
DataFlow::globalVarRef("Cookie").getAMemberCall("noConflict"),
|
||||
DataFlow::moduleImport("js-cookie")
|
||||
].getAMemberCall("set")
|
||||
}
|
||||
|
||||
override string getKind() { result = "js-cookie" }
|
||||
|
||||
@@ -79,12 +79,14 @@ import semmle.javascript.frameworks.ClosureLibrary
|
||||
import semmle.javascript.frameworks.CookieLibraries
|
||||
import semmle.javascript.frameworks.Credentials
|
||||
import semmle.javascript.frameworks.CryptoLibraries
|
||||
import semmle.javascript.frameworks.DateFunctions
|
||||
import semmle.javascript.frameworks.DigitalOcean
|
||||
import semmle.javascript.frameworks.Electron
|
||||
import semmle.javascript.frameworks.EventEmitter
|
||||
import semmle.javascript.frameworks.Files
|
||||
import semmle.javascript.frameworks.Firebase
|
||||
import semmle.javascript.frameworks.jQuery
|
||||
import semmle.javascript.frameworks.JWT
|
||||
import semmle.javascript.frameworks.Handlebars
|
||||
import semmle.javascript.frameworks.LazyCache
|
||||
import semmle.javascript.frameworks.LodashUnderscore
|
||||
|
||||
@@ -12,5 +12,5 @@ import definitions
|
||||
external string selectedSourceFile();
|
||||
|
||||
from Locatable e, ASTNode def, string kind
|
||||
where def = definitionOf(e, kind) and e.getFile() = getEncodedFile(selectedSourceFile())
|
||||
where def = definitionOf(e, kind) and e.getFile() = getFileBySourceArchiveName(selectedSourceFile())
|
||||
select e, def, kind
|
||||
|
||||
@@ -12,5 +12,6 @@ import definitions
|
||||
external string selectedSourceFile();
|
||||
|
||||
from Locatable e, ASTNode def, string kind
|
||||
where def = definitionOf(e, kind) and def.getFile() = getEncodedFile(selectedSourceFile())
|
||||
where
|
||||
def = definitionOf(e, kind) and def.getFile() = getFileBySourceArchiveName(selectedSourceFile())
|
||||
select e, def, kind
|
||||
|
||||
@@ -23,6 +23,6 @@ class PrintAstConfigurationOverride extends PrintAstConfiguration {
|
||||
*/
|
||||
override predicate shouldPrint(Locatable e, Location l) {
|
||||
super.shouldPrint(e, l) and
|
||||
l.getFile() = getEncodedFile(selectedSourceFile())
|
||||
l.getFile() = getFileBySourceArchiveName(selectedSourceFile())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,40 @@ class ES2015Module extends Module {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `mod` contains one or more named export declarations other than `default`.
|
||||
*/
|
||||
private predicate hasNamedExports(ES2015Module mod) {
|
||||
mod.getAnExport().(ExportNamedDeclaration).getASpecifier().getExportedName() != "default"
|
||||
or
|
||||
exists(mod.getAnExport().(ExportNamedDeclaration).getAnExportedDecl())
|
||||
or
|
||||
// Bulk re-exports only export named bindings (not "default")
|
||||
mod.getAnExport() instanceof BulkReExportDeclaration
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this module contains a `default` export.
|
||||
*/
|
||||
private predicate hasDefaultExport(ES2015Module mod) {
|
||||
// export default foo;
|
||||
mod.getAnExport() instanceof ExportDefaultDeclaration
|
||||
or
|
||||
// export { foo as default };
|
||||
mod.getAnExport().(ExportNamedDeclaration).getASpecifier().getExportedName() = "default"
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `mod` contains both named and `default` exports.
|
||||
*
|
||||
* This is used to determine whether a default-import of the module should be reinterpreted
|
||||
* as a namespace-import, to accomodate the non-standard behavior implemented by some compilers.
|
||||
*/
|
||||
private predicate hasBothNamedAndDefaultExports(ES2015Module mod) {
|
||||
hasNamedExports(mod) and
|
||||
hasDefaultExport(mod)
|
||||
}
|
||||
|
||||
/**
|
||||
* An import declaration.
|
||||
*
|
||||
@@ -70,6 +104,10 @@ class ImportDeclaration extends Stmt, Import, @import_declaration {
|
||||
is instanceof ImportNamespaceSpecifier and
|
||||
count(getASpecifier()) = 1
|
||||
or
|
||||
// For compatibility with the non-standard implementation of default imports,
|
||||
// treat default imports as namespace imports in cases where it can't cause ambiguity
|
||||
// between named exports and the properties of a default-exported object.
|
||||
not hasBothNamedAndDefaultExports(getImportedModule()) and
|
||||
is.getImportedName() = "default"
|
||||
)
|
||||
or
|
||||
|
||||
@@ -13,9 +13,11 @@ class JsonStringifyCall extends DataFlow::CallNode {
|
||||
callee = DataFlow::globalVarRef("JSON").getAPropertyRead("stringify") or
|
||||
callee = DataFlow::moduleMember("json3", "stringify") or
|
||||
callee =
|
||||
DataFlow::moduleImport(["json-stringify-safe", "json-stable-stringify", "stringify-object",
|
||||
"fast-json-stable-stringify", "fast-safe-stringify", "javascript-stringify",
|
||||
"js-stringify"]) or
|
||||
DataFlow::moduleImport([
|
||||
"json-stringify-safe", "json-stable-stringify", "stringify-object",
|
||||
"fast-json-stable-stringify", "fast-safe-stringify", "javascript-stringify",
|
||||
"js-stringify"
|
||||
]) or
|
||||
// require("util").inspect() and similar
|
||||
callee = DataFlow::moduleMember("util", "inspect") or
|
||||
callee = DataFlow::moduleImport(["pretty-format", "object-inspect"])
|
||||
|
||||
@@ -205,15 +205,18 @@ private predicate isRequire(DataFlow::Node nd) {
|
||||
or
|
||||
isRequire(nd.getAPredecessor())
|
||||
or
|
||||
// `import { createRequire } from 'module';` support.
|
||||
// specialized to ES2015 modules to avoid recursion in the `DataFlow::moduleImport()` predicate.
|
||||
exists(ImportDeclaration imp | imp.getImportedPath().getValue() = "module" |
|
||||
nd =
|
||||
imp
|
||||
.getImportedModuleNode()
|
||||
.(DataFlow::SourceNode)
|
||||
.getAPropertyRead("createRequire")
|
||||
.getACall()
|
||||
// `import { createRequire } from 'module';`.
|
||||
// specialized to ES2015 modules to avoid recursion in the `DataFlow::moduleImport()` predicate and to avoid
|
||||
// negative recursion between `Import.getImportedModuleNode()` and `Import.getImportedModule()`.
|
||||
exists(ImportDeclaration imp, DataFlow::SourceNode baseObj |
|
||||
imp.getImportedPath().getValue() = "module"
|
||||
|
|
||||
baseObj =
|
||||
[
|
||||
DataFlow::destructuredModuleImportNode(imp),
|
||||
DataFlow::valueNode(imp.getASpecifier().(ImportNamespaceSpecifier))
|
||||
] and
|
||||
nd = baseObj.getAPropertyRead("createRequire").getACall()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -299,8 +299,10 @@ module PromiseFlow {
|
||||
or
|
||||
prop = errorProp() and
|
||||
value =
|
||||
[promise.getRejectParameter().getACall().getArgument(0),
|
||||
promise.getExecutor().getExceptionalReturn()]
|
||||
[
|
||||
promise.getRejectParameter().getACall().getArgument(0),
|
||||
promise.getExecutor().getExceptionalReturn()
|
||||
]
|
||||
)
|
||||
or
|
||||
// promise creation call, e.g. `Promise.resolve`.
|
||||
|
||||
@@ -699,8 +699,10 @@ module TaintTracking {
|
||||
private DataFlow::PropRead getAStaticCaptureRef() {
|
||||
result =
|
||||
DataFlow::globalVarRef("RegExp")
|
||||
.getAPropertyRead(["$" + [1 .. 9], "input", "lastMatch", "leftContext", "rightContext",
|
||||
"$&", "$^", "$`"])
|
||||
.getAPropertyRead([
|
||||
"$" + [1 .. 9], "input", "lastMatch", "leftContext", "rightContext", "$&", "$^",
|
||||
"$`"
|
||||
])
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -318,7 +318,12 @@ private class AnalyzedVariableExport extends AnalyzedPropertyWrite, DataFlow::Va
|
||||
override predicate writes(AbstractValue baseVal, string propName, DataFlow::AnalyzedNode source) {
|
||||
baseVal = TAbstractExportsObject(export.getEnclosingModule()) and
|
||||
propName = name and
|
||||
source = varDef.getSource().analyze()
|
||||
(
|
||||
source = varDef.getSource().analyze()
|
||||
or
|
||||
varDef.getTarget() instanceof DestructuringPattern and
|
||||
source = export.getSourceNode(propName)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate writesValue(AbstractValue baseVal, string propName, AbstractValue val) {
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/** Provides taint steps modeling flow through date-manipulation libraries. */
|
||||
|
||||
private import javascript
|
||||
|
||||
private module DateFns {
|
||||
private API::Node formatFunction() {
|
||||
result = API::moduleImport(["date-fns", "date-fns/esm"]).getMember(["format", "lightFormat"])
|
||||
or
|
||||
result =
|
||||
API::moduleImport([
|
||||
"date-fns/format", "date-fns/lightFormat", "date-fns/esm/format",
|
||||
"date-fns/esm/lightFormat"
|
||||
])
|
||||
}
|
||||
|
||||
private API::Node curriedFormatFunction() {
|
||||
result =
|
||||
API::moduleImport(["date-fns/fp", "date-fns/esm/fp"]).getMember(["format", "lightFormat"])
|
||||
or
|
||||
result =
|
||||
API::moduleImport([
|
||||
"date-fns/fp/format", "date-fns/fp/lightFormat", "date-fns/esm/fp/format",
|
||||
"date-fns/esm/fp/lightFormat"
|
||||
])
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint step of form: `f -> format(date, f)`
|
||||
*
|
||||
* A format string can use single-quotes to include mostly arbitrary text.
|
||||
*/
|
||||
private class FormatStep extends TaintTracking::AdditionalTaintStep, DataFlow::CallNode {
|
||||
FormatStep() { this = formatFunction().getACall() }
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
pred = getArgument(1) and
|
||||
succ = this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint step of form: `f -> format(f)(date)`
|
||||
*/
|
||||
private class CurriedFormatStep extends TaintTracking::AdditionalTaintStep, DataFlow::CallNode {
|
||||
CurriedFormatStep() { this = curriedFormatFunction().getACall() }
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
pred = getArgument(0) and
|
||||
succ = getACall()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private module Moment {
|
||||
/** Gets a reference to a `moment` object. */
|
||||
private API::Node moment() {
|
||||
result = API::moduleImport(["moment", "moment-timezone"])
|
||||
or
|
||||
result = moment().getReturn()
|
||||
or
|
||||
result = moment().getAMember()
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint step of form: `f -> momentObj.format(f)`
|
||||
*
|
||||
* The format string can use backslash-escaping to include mostly arbitrary text.
|
||||
*/
|
||||
private class MomentFormatStep extends TaintTracking::AdditionalTaintStep, DataFlow::CallNode {
|
||||
MomentFormatStep() { this = moment().getMember("format").getACall() }
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
pred = getArgument(0) and
|
||||
succ = this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private module DateFormat {
|
||||
/**
|
||||
* Taint step of form: `x -> dateformat(..., x)`
|
||||
*
|
||||
* The format string can use single-quotes to include mostly arbitrary text.
|
||||
*/
|
||||
private class DateFormatStep extends TaintTracking::AdditionalTaintStep, DataFlow::CallNode {
|
||||
DateFormatStep() { this = DataFlow::moduleImport("dateformat").getACall() }
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
pred = getArgument(1) and
|
||||
succ = this
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -491,8 +491,10 @@ module Express {
|
||||
RequestInputAccess() {
|
||||
kind = "parameter" and
|
||||
this =
|
||||
[getAQueryObjectReference(DataFlow::TypeTracker::end(), rh),
|
||||
getAParamsObjectReference(DataFlow::TypeTracker::end(), rh)].getAPropertyRead()
|
||||
[
|
||||
getAQueryObjectReference(DataFlow::TypeTracker::end(), rh),
|
||||
getAParamsObjectReference(DataFlow::TypeTracker::end(), rh)
|
||||
].getAPropertyRead()
|
||||
or
|
||||
exists(DataFlow::SourceNode request | request = rh.getARequestSource().ref() |
|
||||
kind = "parameter" and
|
||||
|
||||
@@ -118,8 +118,10 @@ module Fastify {
|
||||
.flow()
|
||||
.(DataFlow::MethodCallNode)
|
||||
.getOptionArgument(0,
|
||||
["onRequest", "preParsing", "preValidation", "preHandler", "preSerialization",
|
||||
"onSend", "onResponse", "handler"])
|
||||
[
|
||||
"onRequest", "preParsing", "preValidation", "preHandler", "preSerialization",
|
||||
"onSend", "onResponse", "handler"
|
||||
])
|
||||
else result = getLastArgument().flow()
|
||||
}
|
||||
}
|
||||
|
||||
50
javascript/ql/src/semmle/javascript/frameworks/JWT.qll
Normal file
50
javascript/ql/src/semmle/javascript/frameworks/JWT.qll
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Provides classes for working with JWT libraries.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
|
||||
/**
|
||||
* Provides classes and predicates modeling the `jwt-decode` libary.
|
||||
*/
|
||||
private module JwtDecode {
|
||||
/**
|
||||
* A taint-step for `succ = require("jwt-decode")(pred)`.
|
||||
*/
|
||||
private class JwtDecodeStep extends TaintTracking::AdditionalTaintStep, DataFlow::CallNode {
|
||||
JwtDecodeStep() { this = DataFlow::moduleImport("jwt-decode").getACall() }
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
pred = this.getArgument(0) and
|
||||
succ = this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides classes and predicates modeling the `jsonwebtoken` libary.
|
||||
*/
|
||||
private module JsonWebToken {
|
||||
/**
|
||||
* A taint-step for `require("jsonwebtoken").verify(pred, "key", (err succ) => {...})`.
|
||||
*/
|
||||
private class VerifyStep extends TaintTracking::AdditionalTaintStep, DataFlow::CallNode {
|
||||
VerifyStep() { this = DataFlow::moduleMember("jsonwebtoken", "verify").getACall() }
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
pred = this.getArgument(0) and
|
||||
succ = this.getABoundCallbackParameter(2, 1)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The private key for a JWT as a `CredentialsExpr`.
|
||||
*/
|
||||
private class JWTKey extends CredentialsExpr {
|
||||
JWTKey() {
|
||||
this = DataFlow::moduleMember("jsonwebtoken", "sign").getACall().getArgument(1).asExpr()
|
||||
}
|
||||
|
||||
override string getCredentialsKind() { result = "key" }
|
||||
}
|
||||
}
|
||||
@@ -403,16 +403,18 @@ module LodashUnderscore {
|
||||
call = any(Member member | member.getName() = name).getACall()
|
||||
|
|
||||
name =
|
||||
["find", "filter", "findWhere", "where", "reject", "pluck", "max", "min", "sortBy",
|
||||
"shuffle", "sample", "toArray", "partition", "compact", "first", "initial", "last",
|
||||
"rest", "flatten", "without", "difference", "uniq", "unique", "unzip", "transpose",
|
||||
"object", "chunk", "values", "mapObject", "pick", "omit", "defaults", "clone", "tap",
|
||||
"identity",
|
||||
// String category
|
||||
"camelCase", "capitalize", "deburr", "kebabCase", "lowerCase", "lowerFirst", "pad",
|
||||
"padEnd", "padStart", "repeat", "replace", "snakeCase", "split", "startCase", "toLower",
|
||||
"toUpper", "trim", "trimEnd", "trimStart", "truncate", "unescape", "upperCase",
|
||||
"upperFirst", "words"] and
|
||||
[
|
||||
"find", "filter", "findWhere", "where", "reject", "pluck", "max", "min", "sortBy",
|
||||
"shuffle", "sample", "toArray", "partition", "compact", "first", "initial", "last",
|
||||
"rest", "flatten", "without", "difference", "uniq", "unique", "unzip", "transpose",
|
||||
"object", "chunk", "values", "mapObject", "pick", "omit", "defaults", "clone", "tap",
|
||||
"identity",
|
||||
// String category
|
||||
"camelCase", "capitalize", "deburr", "kebabCase", "lowerCase", "lowerFirst", "pad",
|
||||
"padEnd", "padStart", "repeat", "replace", "snakeCase", "split", "startCase", "toLower",
|
||||
"toUpper", "trim", "trimEnd", "trimStart", "truncate", "unescape", "upperCase",
|
||||
"upperFirst", "words"
|
||||
] and
|
||||
pred = call.getArgument(0) and
|
||||
succ = call
|
||||
or
|
||||
|
||||
@@ -798,10 +798,12 @@ private module Redis {
|
||||
bindingset[argIndex]
|
||||
predicate argumentIsAmbiguousKey(string method, int argIndex) {
|
||||
method =
|
||||
["set", "publish", "append", "bitfield", "decrby", "getset", "hincrby", "hincrbyfloat",
|
||||
"hset", "hsetnx", "incrby", "incrbyfloat", "linsert", "lpush", "lpushx", "lset",
|
||||
"ltrim", "rename", "renamenx", "rpushx", "setbit", "setex", "smove", "zincrby",
|
||||
"zinterstore", "hdel", "lpush", "pfadd", "rpush", "sadd", "sdiffstore", "srem"] and
|
||||
[
|
||||
"set", "publish", "append", "bitfield", "decrby", "getset", "hincrby", "hincrbyfloat",
|
||||
"hset", "hsetnx", "incrby", "incrbyfloat", "linsert", "lpush", "lpushx", "lset", "ltrim",
|
||||
"rename", "renamenx", "rpushx", "setbit", "setex", "smove", "zincrby", "zinterstore",
|
||||
"hdel", "lpush", "pfadd", "rpush", "sadd", "sdiffstore", "srem"
|
||||
] and
|
||||
argIndex = 0
|
||||
or
|
||||
method = ["bitop", "hmset", "mset", "msetnx", "geoadd"] and argIndex >= 0
|
||||
|
||||
@@ -472,8 +472,10 @@ module NodeJSLib {
|
||||
result = promisifyAllCall and
|
||||
pred.flowsTo(promisifyAllCall.getArgument(0)) and
|
||||
promisifyAllCall =
|
||||
[DataFlow::moduleMember("bluebird", "promisifyAll"),
|
||||
DataFlow::moduleImport("util-promisifyall")].getACall()
|
||||
[
|
||||
DataFlow::moduleMember("bluebird", "promisifyAll"),
|
||||
DataFlow::moduleImport("util-promisifyall")
|
||||
].getACall()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -771,8 +773,10 @@ module NodeJSLib {
|
||||
* Gets the code to be executed as part of this invocation.
|
||||
*/
|
||||
DataFlow::Node getACodeArgument() {
|
||||
memberName in ["Script", "SourceTextModule", "compileFunction", "runInContext",
|
||||
"runInNewContext", "runInThisContext"] and
|
||||
memberName in [
|
||||
"Script", "SourceTextModule", "compileFunction", "runInContext", "runInNewContext",
|
||||
"runInThisContext"
|
||||
] and
|
||||
// all of the above methods/constructors take the command as their first argument
|
||||
result = getArgument(0)
|
||||
}
|
||||
|
||||
@@ -569,10 +569,12 @@ private class UseStateStep extends PreCallGraphStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(DataFlow::CallNode call | call = react().getAMemberCall("useState") |
|
||||
pred =
|
||||
[call.getArgument(0), // initial state
|
||||
call.getCallback(0).getReturnNode(), // lazy initial state
|
||||
call.getAPropertyRead("1").getACall().getArgument(0), // setState invocation
|
||||
call.getAPropertyRead("1").getACall().getCallback(0).getReturnNode()] and // setState with callback
|
||||
[
|
||||
call.getArgument(0), // initial state
|
||||
call.getCallback(0).getReturnNode(), // lazy initial state
|
||||
call.getAPropertyRead("1").getACall().getArgument(0), // setState invocation
|
||||
call.getAPropertyRead("1").getACall().getCallback(0).getReturnNode() // setState with callback
|
||||
] and
|
||||
succ = call.getAPropertyRead("0")
|
||||
or
|
||||
// Propagate current state into the callback argument of `setState(prevState => { ... })`
|
||||
|
||||
@@ -33,8 +33,10 @@ module Vue {
|
||||
/** Gets the name of a lifecycle hook method. */
|
||||
private string lifecycleHookName() {
|
||||
result =
|
||||
["beforeCreate", "created", "beforeMount", "mounted", "beforeUpdate", "updated", "activated",
|
||||
"deactivated", "beforeDestroy", "destroyed", "errorCaptured"]
|
||||
[
|
||||
"beforeCreate", "created", "beforeMount", "mounted", "beforeUpdate", "updated", "activated",
|
||||
"deactivated", "beforeDestroy", "destroyed", "errorCaptured"
|
||||
]
|
||||
}
|
||||
|
||||
/** Gets a value that can be used as a `@Component` decorator. */
|
||||
|
||||
@@ -53,8 +53,10 @@ module ImproperCodeSanitization {
|
||||
|
|
||||
functionLeaf
|
||||
.getStringValue()
|
||||
.regexpMatch([".*function( )?([a-zA-Z0-9]+)?( )?\\(.*", ".*eval\\(.*",
|
||||
".*new Function\\(.*", "(^|.*[^a-zA-Z0-9])\\(.*\\)( )?=>.*"])
|
||||
.regexpMatch([
|
||||
".*function( )?([a-zA-Z0-9]+)?( )?\\(.*", ".*eval\\(.*", ".*new Function\\(.*",
|
||||
"(^|.*[^a-zA-Z0-9])\\(.*\\)( )?=>.*"
|
||||
])
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -66,9 +66,11 @@ module IndirectCommandInjection {
|
||||
exists(string method |
|
||||
not method =
|
||||
// the methods that does not return a chained `yargs` object.
|
||||
["getContext", "getDemandedOptions", "getDemandedCommands", "getDeprecatedOptions",
|
||||
"_getParseContext", "getOptions", "getGroups", "getStrict", "getStrictCommands",
|
||||
"getExitProcess", "locale", "getUsageInstance", "getCommandInstance"]
|
||||
[
|
||||
"getContext", "getDemandedOptions", "getDemandedCommands", "getDeprecatedOptions",
|
||||
"_getParseContext", "getOptions", "getGroups", "getStrict", "getStrictCommands",
|
||||
"getExitProcess", "locale", "getUsageInstance", "getCommandInstance"
|
||||
]
|
||||
|
|
||||
result = yargs().getAMethodCall(method)
|
||||
)
|
||||
|
||||
@@ -96,8 +96,10 @@ module InsecureDownload {
|
||||
*/
|
||||
string unsafeExtension() {
|
||||
result =
|
||||
["exe", "dmg", "pkg", "tar.gz", "zip", "sh", "bat", "cmd", "app", "apk", "msi", "dmg",
|
||||
"tar.gz", "zip", "js", "py", "jar", "war"]
|
||||
[
|
||||
"exe", "dmg", "pkg", "tar.gz", "zip", "sh", "bat", "cmd", "app", "apk", "msi", "dmg",
|
||||
"tar.gz", "zip", "js", "py", "jar", "war"
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -105,8 +105,10 @@ module UnsafeShellCommandConstruction {
|
||||
|
||||
ArrayAppendEndingInCommandExecutinSink() {
|
||||
this =
|
||||
[array.(DataFlow::ArrayCreationNode).getAnElement(),
|
||||
array.getAMethodCall(["push", "unshift"]).getAnArgument()] and
|
||||
[
|
||||
array.(DataFlow::ArrayCreationNode).getAnElement(),
|
||||
array.getAMethodCall(["push", "unshift"]).getAnArgument()
|
||||
] and
|
||||
exists(DataFlow::MethodCallNode joinCall | array.getAMethodCall("join") = joinCall |
|
||||
joinCall = isExecutedAsShellCommand(DataFlow::TypeBackTracker::end(), sys) and
|
||||
joinCall.getNumArgument() = 1 and
|
||||
|
||||
Reference in New Issue
Block a user