mirror of
https://github.com/github/codeql.git
synced 2026-04-28 18:25:24 +02:00
Merge remote-tracking branch 'upstream/main' into incomplete-hostname
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
import javascript
|
||||
import semmle.javascript.RestrictedLocations
|
||||
|
||||
predicate isRepeatedDependency(AngularJS::InjectableFunction f, string name, ASTNode location) {
|
||||
predicate isRepeatedDependency(AngularJS::InjectableFunction f, string name, AstNode location) {
|
||||
exists(int i, int j |
|
||||
i < j and
|
||||
exists(f.getDependencyDeclaration(i, name)) and
|
||||
@@ -20,7 +20,7 @@ predicate isRepeatedDependency(AngularJS::InjectableFunction f, string name, AST
|
||||
)
|
||||
}
|
||||
|
||||
from AngularJS::InjectableFunction f, ASTNode node, string name
|
||||
from AngularJS::InjectableFunction f, AstNode node, string name
|
||||
where
|
||||
isRepeatedDependency(f, name, node) and
|
||||
not count(f.asFunction().getParameterByName(name)) > 1 // avoid duplicating reports from js/duplicate-parameter-name
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
import javascript
|
||||
import semmle.javascript.RestrictedLocations
|
||||
|
||||
from AngularJS::InjectableFunction f, ASTNode explicitInjection
|
||||
from AngularJS::InjectableFunction f, AstNode explicitInjection
|
||||
where
|
||||
count(f.getAnExplicitDependencyInjection()) > 1 and
|
||||
explicitInjection = f.getAnExplicitDependencyInjection()
|
||||
|
||||
@@ -21,7 +21,7 @@ predicate isUnusedParameter(Function f, string msg, Parameter parameter) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate isMissingParameter(AngularJS::InjectableFunction f, string msg, ASTNode location) {
|
||||
predicate isMissingParameter(AngularJS::InjectableFunction f, string msg, AstNode location) {
|
||||
exists(int paramCount, int injectionCount |
|
||||
DataFlow::valueNode(location) = f and
|
||||
paramCount = f.asFunction().getNumParameter() and
|
||||
@@ -41,7 +41,7 @@ predicate isMissingParameter(AngularJS::InjectableFunction f, string msg, ASTNod
|
||||
)
|
||||
}
|
||||
|
||||
from AngularJS::InjectableFunction f, string message, ASTNode location
|
||||
from AngularJS::InjectableFunction f, string message, AstNode location
|
||||
where
|
||||
isUnusedParameter(f.asFunction(), message, location) or isMissingParameter(f, message, location)
|
||||
select location.(FirstLineOf), message
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
## 0.0.12
|
||||
|
||||
## 0.0.11
|
||||
|
||||
### New Queries
|
||||
|
||||
@@ -35,7 +35,7 @@ where
|
||||
// the variable should be accessed somewhere; otherwise it will be flagged by UnusedVariable
|
||||
exists(v.getAnAccess()) and
|
||||
// don't flag ambient variable definitions
|
||||
not dead.(ASTNode).isAmbient() and
|
||||
not dead.(AstNode).isAmbient() and
|
||||
// don't flag variables with ambient uses
|
||||
not exists(LexicalAccess access |
|
||||
access.getALexicalName() = v.getADeclaration().getALexicalName() and
|
||||
@@ -55,7 +55,7 @@ where
|
||||
// don't flag default inits that are later overwritten
|
||||
not (isDefaultInit(dead.getSource().(Expr).getUnderlyingValue()) and dead.isOverwritten(v)) and
|
||||
// don't flag assignments in externs
|
||||
not dead.(ASTNode).inExternsFile() and
|
||||
not dead.(AstNode).inExternsFile() and
|
||||
// don't flag exported variables
|
||||
not any(ES2015Module m).exportsAs(v, _) and
|
||||
// don't flag 'exports' assignments in closure modules
|
||||
@@ -70,5 +70,5 @@ where
|
||||
else msg = "The value assigned to " + v.getName() + " here is unused."
|
||||
) and
|
||||
// ignore Angular templates
|
||||
not dead.(ASTNode).getTopLevel() instanceof Angular2::TemplateTopLevel
|
||||
not dead.(AstNode).getTopLevel() instanceof Angular2::TemplateTopLevel
|
||||
select dead, msg
|
||||
|
||||
@@ -101,7 +101,7 @@ predicate isDeadAssignment(string name, DataFlow::PropWrite assign1, DataFlow::P
|
||||
noPropAccessBetweenInsideBasicBlock(name, assign1, assign2) or
|
||||
noPropAccessBetweenAcrossBasicBlocks(name, assign1, assign2)
|
||||
) and
|
||||
not isDOMProperty(name)
|
||||
not isDomProperty(name)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import javascript
|
||||
|
||||
/** An identifier appearing in a defining position. */
|
||||
class DefiningIdentifier extends Identifier {
|
||||
/**
|
||||
* DEPRECATED: Use `SsaDefinition` from `SSA.qll` instead.
|
||||
* An identifier appearing in a defining position.
|
||||
*/
|
||||
deprecated class DefiningIdentifier extends Identifier {
|
||||
DefiningIdentifier() {
|
||||
this instanceof VarDecl or
|
||||
exists(Assignment assgn | this = assgn.getLhs()) or
|
||||
|
||||
@@ -37,20 +37,20 @@ predicate isPropertyFilter(UnusedLocal v) {
|
||||
}
|
||||
|
||||
predicate hasJsxInScope(UnusedLocal v) {
|
||||
any(JSXNode n).getParent+() = v.getScope().getScopeElement()
|
||||
any(JsxNode n).getParent+() = v.getScope().getScopeElement()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is a "React" variable that is implicitly used by a JSX element.
|
||||
*/
|
||||
predicate isReactForJSX(UnusedLocal v) {
|
||||
predicate isReactForJsx(UnusedLocal v) {
|
||||
hasJsxInScope(v) and
|
||||
(
|
||||
v.getName() = "React"
|
||||
or
|
||||
exists(TopLevel tl | tl = v.getADeclaration().getTopLevel() |
|
||||
// legacy `@jsx` pragmas
|
||||
exists(JSXPragma p | p.getTopLevel() = tl | p.getDOMName() = v.getName())
|
||||
exists(JsxPragma p | p.getTopLevel() = tl | p.getDomName() = v.getName())
|
||||
or
|
||||
// JSX pragma from a .babelrc file
|
||||
exists(Babel::TransformReactJsxConfig plugin |
|
||||
@@ -59,7 +59,7 @@ predicate isReactForJSX(UnusedLocal v) {
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(JSONObject tsconfig |
|
||||
exists(JsonObject tsconfig |
|
||||
tsconfig.isTopLevel() and tsconfig.getFile().getBaseName() = "tsconfig.json"
|
||||
|
|
||||
v.getName() =
|
||||
@@ -148,7 +148,7 @@ predicate whitelisted(UnusedLocal v) {
|
||||
isPropertyFilter(v)
|
||||
or
|
||||
// exclude imports of React that are implicitly referenced by JSX
|
||||
isReactForJSX(v)
|
||||
isReactForJsx(v)
|
||||
or
|
||||
// exclude names that are used as types
|
||||
exists(VarDecl vd | v = vd.getVariable() |
|
||||
@@ -198,7 +198,7 @@ predicate unusedImports(ImportVarDeclProvider provider, string msg) {
|
||||
)
|
||||
}
|
||||
|
||||
from ASTNode sel, string msg
|
||||
from AstNode sel, string msg
|
||||
where
|
||||
(
|
||||
unusedNonImports(sel, msg) or
|
||||
|
||||
@@ -7,7 +7,7 @@ import javascript
|
||||
/**
|
||||
* Gets an opaque integer value encoding the type of AST node `nd`.
|
||||
*/
|
||||
private int kindOf(ASTNode nd) {
|
||||
private int kindOf(AstNode nd) {
|
||||
// map expression kinds to even non-negative numbers
|
||||
result = nd.(Expr).getKind() * 2
|
||||
or
|
||||
@@ -25,7 +25,7 @@ private int kindOf(ASTNode nd) {
|
||||
/**
|
||||
* Holds if `nd` has the given `kind`, and its number of children is `arity`.
|
||||
*/
|
||||
private predicate kindAndArity(ASTNode nd, int kind, int arity) {
|
||||
private predicate kindAndArity(AstNode nd, int kind, int arity) {
|
||||
kindOf(nd) = kind and arity = nd.getNumChild()
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ private predicate kindAndArity(ASTNode nd, int kind, int arity) {
|
||||
*
|
||||
* Every AST node has at most one value.
|
||||
*/
|
||||
private string valueOf(ASTNode nd) {
|
||||
private string valueOf(AstNode nd) {
|
||||
result = nd.(Literal).getRawValue() or
|
||||
result = nd.(TemplateElement).getRawValue() or
|
||||
result = nd.(Identifier).getName()
|
||||
@@ -47,18 +47,18 @@ private string valueOf(ASTNode nd) {
|
||||
* Clients must override the `candidate()` method to identify the
|
||||
* nodes for which structural comparison will be interesting.
|
||||
*/
|
||||
abstract class StructurallyCompared extends ASTNode {
|
||||
abstract class StructurallyCompared extends AstNode {
|
||||
/**
|
||||
* Gets a candidate node that we may want to structurally compare this node to.
|
||||
*/
|
||||
abstract ASTNode candidate();
|
||||
abstract AstNode candidate();
|
||||
|
||||
/**
|
||||
* Gets a node that structurally corresponds to this node, either because it is
|
||||
* a candidate node, or because it is at the same position relative to a
|
||||
* candidate node as this node.
|
||||
*/
|
||||
ASTNode candidateInternal() {
|
||||
AstNode candidateInternal() {
|
||||
// in order to correspond, nodes need to have the same kind and shape
|
||||
exists(int kind, int numChildren | kindAndArity(this, kind, numChildren) |
|
||||
result = this.candidateKind(kind, numChildren)
|
||||
@@ -71,18 +71,18 @@ abstract class StructurallyCompared extends ASTNode {
|
||||
* Gets a node that structurally corresponds to the parent node of this node,
|
||||
* where this node is the `i`th child of its parent.
|
||||
*/
|
||||
private ASTNode getAStructuralUncle(int i) {
|
||||
private AstNode getAStructuralUncle(int i) {
|
||||
exists(StructurallyCompared parent | this = parent.getChild(i) |
|
||||
result = parent.candidateInternal()
|
||||
)
|
||||
}
|
||||
|
||||
private ASTNode candidateKind(int kind, int numChildren) {
|
||||
private AstNode candidateKind(int kind, int numChildren) {
|
||||
result = this.candidate() and kindAndArity(result, kind, numChildren)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private ASTNode uncleKind(int kind, int numChildren) {
|
||||
private AstNode uncleKind(int kind, int numChildren) {
|
||||
exists(int i | result = this.getAStructuralUncle(i).getChild(i)) and
|
||||
kindAndArity(result, kind, numChildren)
|
||||
}
|
||||
@@ -92,7 +92,7 @@ abstract class StructurallyCompared extends ASTNode {
|
||||
* rooted at node `that`, where `that` structurally corresponds to `this` as
|
||||
* determined by `candidateInternal`.
|
||||
*/
|
||||
private predicate sameInternal(ASTNode that) {
|
||||
private predicate sameInternal(AstNode that) {
|
||||
that = this.candidateInternal() and
|
||||
/*
|
||||
* Check that `this` and `that` bind to the same variable, if any.
|
||||
@@ -120,7 +120,7 @@ abstract class StructurallyCompared extends ASTNode {
|
||||
* rooted at node `that`, which must be a candidate node as determined by
|
||||
* `candidate`.
|
||||
*/
|
||||
predicate same(ASTNode that) {
|
||||
predicate same(AstNode that) {
|
||||
that = this.candidate() and
|
||||
this.sameInternal(that)
|
||||
}
|
||||
@@ -132,7 +132,7 @@ abstract class StructurallyCompared extends ASTNode {
|
||||
private class InternalCandidate extends StructurallyCompared {
|
||||
InternalCandidate() { exists(this.getParent().(StructurallyCompared).candidateInternal()) }
|
||||
|
||||
override ASTNode candidate() { none() }
|
||||
override AstNode candidate() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,7 +24,7 @@ private import semmle.javascript.DefensiveProgramming
|
||||
* Besides the usual comparison operators, `switch` statements are also considered to be comparisons,
|
||||
* with the switched-on expression being the right operand and all case labels the left operands.
|
||||
*/
|
||||
predicate comparisonOperands(ASTNode nd, Expr left, Expr right) {
|
||||
predicate comparisonOperands(AstNode nd, Expr left, Expr right) {
|
||||
exists(Comparison cmp | cmp = nd | left = cmp.getLeftOperand() and right = cmp.getRightOperand())
|
||||
or
|
||||
exists(SwitchStmt switch | switch = nd |
|
||||
@@ -45,7 +45,7 @@ predicate hasImplicitConversionMethod(DefiniteAbstractValue av) {
|
||||
/**
|
||||
* Gets a type of `operand`, which is an operand of the strict equality test `eq`.
|
||||
*/
|
||||
InferredType strictEqualityOperandType(ASTNode eq, DataFlow::AnalyzedNode operand) {
|
||||
InferredType strictEqualityOperandType(AstNode eq, DataFlow::AnalyzedNode operand) {
|
||||
// strict equality tests do no conversion at all
|
||||
operand.asExpr() = eq.(StrictEqualityTest).getAChildExpr() and result = operand.getAType()
|
||||
or
|
||||
@@ -60,7 +60,7 @@ InferredType strictEqualityOperandType(ASTNode eq, DataFlow::AnalyzedNode operan
|
||||
* Holds if `operand` is an operand of the non-strict equality test or relational
|
||||
* operator `parent`, and may have a `toString` or `valueOf` method.
|
||||
*/
|
||||
predicate implicitlyConvertedOperand(ASTNode parent, DataFlow::AnalyzedNode operand) {
|
||||
predicate implicitlyConvertedOperand(AstNode parent, DataFlow::AnalyzedNode operand) {
|
||||
(parent instanceof NonStrictEqualityTest or parent instanceof RelationalComparison) and
|
||||
operand.asExpr() = parent.getAChildExpr() and
|
||||
hasImplicitConversionMethod(operand.getAValue())
|
||||
@@ -70,7 +70,7 @@ predicate implicitlyConvertedOperand(ASTNode parent, DataFlow::AnalyzedNode oper
|
||||
* Gets a type of `operand`, which is an operand of the non-strict equality test or
|
||||
* relational operator `parent`.
|
||||
*/
|
||||
InferredType nonStrictOperandType(ASTNode parent, DataFlow::AnalyzedNode operand) {
|
||||
InferredType nonStrictOperandType(AstNode parent, DataFlow::AnalyzedNode operand) {
|
||||
// non-strict equality tests perform conversions
|
||||
operand.asExpr() = parent.(NonStrictEqualityTest).getAChildExpr() and
|
||||
exists(InferredType tp | tp = operand.getAValue().getType() |
|
||||
@@ -109,7 +109,7 @@ InferredType nonStrictOperandType(ASTNode parent, DataFlow::AnalyzedNode operand
|
||||
* Gets a type that `operand`, which is an operand of comparison `parent`,
|
||||
* could be converted to at runtime.
|
||||
*/
|
||||
InferredType convertedOperandType(ASTNode parent, DataFlow::AnalyzedNode operand) {
|
||||
InferredType convertedOperandType(AstNode parent, DataFlow::AnalyzedNode operand) {
|
||||
result = strictEqualityOperandType(parent, operand)
|
||||
or
|
||||
// if `operand` might have `toString`/`valueOf`, just assume it could
|
||||
@@ -125,7 +125,7 @@ InferredType convertedOperandType(ASTNode parent, DataFlow::AnalyzedNode operand
|
||||
* common type they coerce to.
|
||||
*/
|
||||
predicate isHeterogeneousComparison(
|
||||
ASTNode cmp, DataFlow::AnalyzedNode left, DataFlow::AnalyzedNode right, string leftTypes,
|
||||
AstNode cmp, DataFlow::AnalyzedNode left, DataFlow::AnalyzedNode right, string leftTypes,
|
||||
string rightTypes
|
||||
) {
|
||||
comparisonOperands(cmp, left.asExpr(), right.asExpr()) and
|
||||
@@ -188,7 +188,7 @@ predicate isInitialParameterUse(Expr e) {
|
||||
predicate whitelist(Expr e) { isInitialParameterUse(e) }
|
||||
|
||||
from
|
||||
ASTNode cmp, DataFlow::AnalyzedNode left, DataFlow::AnalyzedNode right, string leftTypes,
|
||||
AstNode cmp, DataFlow::AnalyzedNode left, DataFlow::AnalyzedNode right, string leftTypes,
|
||||
string rightTypes, string leftExprDescription, string rightExprDescription, int leftTypeCount,
|
||||
int rightTypeCount, string leftTypeDescription, string rightTypeDescription
|
||||
where
|
||||
|
||||
@@ -41,7 +41,7 @@ where
|
||||
propName = any(AccessorMethodDeclaration amd).getName()
|
||||
) and
|
||||
// exclude DOM properties
|
||||
not isDOMProperty(e.(PropAccess).getPropertyName()) and
|
||||
not isDomProperty(e.(PropAccess).getPropertyName()) and
|
||||
// exclude self-assignments that have been inserted to satisfy the TypeScript JS-checker
|
||||
not e.getAssignment().getParent().(ExprStmt).getDocumentation().getATag().getTitle() = "type" and
|
||||
// exclude self-assignments in speculatively parsed template files
|
||||
|
||||
@@ -83,9 +83,9 @@ private predicate isBoundInMethod(MethodDeclaration method) {
|
||||
* Gets an event handler attribute (onClick, onTouch, ...).
|
||||
*/
|
||||
private DOM::AttributeDefinition getAnEventHandlerAttribute() {
|
||||
exists(ReactComponent c, JSXNode rendered, string attributeName |
|
||||
exists(ReactComponent c, JsxNode rendered, string attributeName |
|
||||
c.getRenderMethod().getAReturnedExpr().flow().getALocalSource().asExpr() = rendered and
|
||||
result = rendered.getABodyElement*().(JSXElement).getAttributeByName(attributeName) and
|
||||
result = rendered.getABodyElement*().(JsxElement).getAttributeByName(attributeName) and
|
||||
attributeName.regexpMatch("on[A-Z][a-zA-Z]+") // camelCased with 'on'-prefix
|
||||
)
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import javascript
|
||||
* A comparison construct, that is, either an equality test or a switch case
|
||||
* (which is implicitly compared to the switch statement's discriminant).
|
||||
*/
|
||||
class EqOrSwitch extends ASTNode {
|
||||
class EqOrSwitch extends AstNode {
|
||||
EqOrSwitch() {
|
||||
this instanceof EqualityTest or
|
||||
this instanceof Case
|
||||
|
||||
@@ -18,7 +18,7 @@ import javascript
|
||||
* Holds if `nd` is a use of deprecated language feature `type`, and `replacement`
|
||||
* is the recommended replacement.
|
||||
*/
|
||||
predicate deprecated_feature(ASTNode nd, string type, string replacement) {
|
||||
predicate deprecated_feature(AstNode nd, string type, string replacement) {
|
||||
exists(FunctionExpr fe | fe = nd and fe.getBody() instanceof Expr |
|
||||
type = "expression closures" and replacement = "arrow expressions"
|
||||
)
|
||||
@@ -38,6 +38,6 @@ predicate deprecated_feature(ASTNode nd, string type, string replacement) {
|
||||
replacement = "standard method definitions"
|
||||
}
|
||||
|
||||
from ASTNode depr, string type, string replacement
|
||||
from AstNode depr, string type, string replacement
|
||||
where deprecated_feature(depr, type, replacement)
|
||||
select depr, "Use " + replacement + " instead of " + type + "."
|
||||
|
||||
@@ -17,11 +17,10 @@ class CandidateTopLevel extends TopLevel {
|
||||
|
||||
/** A string literal in a toplevel that contains at least one template literal. */
|
||||
class CandidateStringLiteral extends StringLiteral {
|
||||
CandidateTopLevel tl;
|
||||
string v;
|
||||
|
||||
CandidateStringLiteral() {
|
||||
tl = this.getTopLevel() and
|
||||
this.getTopLevel() instanceof CandidateTopLevel and
|
||||
v = this.getStringValue()
|
||||
}
|
||||
|
||||
@@ -43,10 +42,10 @@ class CandidateStringLiteral extends StringLiteral {
|
||||
* Gets an ancestor node of this string literal in the AST that can be reached without
|
||||
* stepping over scope elements.
|
||||
*/
|
||||
ASTNode getIntermediate() {
|
||||
AstNode getIntermediate() {
|
||||
result = this
|
||||
or
|
||||
exists(ASTNode mid | mid = this.getIntermediate() |
|
||||
exists(AstNode mid | mid = this.getIntermediate() |
|
||||
not mid instanceof ScopeElement and
|
||||
result = mid.getParent()
|
||||
)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import javascript
|
||||
|
||||
from JSONValue v, File f
|
||||
from JsonValue v, File f
|
||||
where
|
||||
f = v.getFile() and
|
||||
f.getExtension().regexpMatch("(?i)jsx?") and
|
||||
|
||||
@@ -13,7 +13,7 @@ import javascript
|
||||
* (https://kangax.github.io/compat-table/es6/) and [ECMAScript next compatibility table]
|
||||
* (https://kangax.github.io/compat-table/esnext/).
|
||||
*/
|
||||
predicate isES20xxFeature(ASTNode nd, int version, string category) {
|
||||
predicate isES20xxFeature(AstNode nd, int version, string category) {
|
||||
version = 2015 and
|
||||
(
|
||||
exists(nd.(Parameter).getDefault()) and category = "default function parameters"
|
||||
|
||||
@@ -12,4 +12,4 @@
|
||||
import ES20xxFeatures
|
||||
|
||||
from File f
|
||||
select f, count(ASTNode nd | nd.getFile() = f and isES20xxFeature(nd, _, _)) as n order by n desc
|
||||
select f, count(AstNode nd | nd.getFile() = f and isES20xxFeature(nd, _, _)) as n order by n desc
|
||||
|
||||
@@ -64,7 +64,7 @@ predicate relatedModules(NodeModule m, NodeModule n) {
|
||||
n = m.getAnImportedModule() or m = n.getAnImportedModule()
|
||||
}
|
||||
|
||||
from NodeModule m, Require r, NodeModule imported, string msg, ASTNode linktarget, string linktext
|
||||
from NodeModule m, Require r, NodeModule imported, string msg, AstNode linktarget, string linktext
|
||||
where
|
||||
r = m.getAnImport() and
|
||||
imported = r.getImportedModule() and
|
||||
|
||||
@@ -16,10 +16,10 @@ import javascript
|
||||
* Gets the `package.json` of the nearest enclosing NPM package to which
|
||||
* file `f` belongs.
|
||||
*/
|
||||
PackageJSON getClosestPackageJSON(Folder f) {
|
||||
result = f.(NPMPackage).getPackageJSON()
|
||||
PackageJson getClosestPackageJson(Folder f) {
|
||||
result = f.(NpmPackage).getPackageJson()
|
||||
or
|
||||
not f instanceof NPMPackage and result = getClosestPackageJSON(f.getParentContainer())
|
||||
not f instanceof NpmPackage and result = getClosestPackageJson(f.getParentContainer())
|
||||
}
|
||||
|
||||
from Require r, string path, string mod
|
||||
@@ -35,14 +35,14 @@ where
|
||||
// import cannot be resolved statically
|
||||
not exists(r.getImportedModule()) and
|
||||
// no enclosing NPM package declares a dependency on `mod`
|
||||
forex(NPMPackage pkg, PackageJSON pkgJSON |
|
||||
pkg.getAModule() = r.getTopLevel() and pkgJSON = pkg.getPackageJSON()
|
||||
forex(NpmPackage pkg, PackageJson pkgJson |
|
||||
pkg.getAModule() = r.getTopLevel() and pkgJson = pkg.getPackageJson()
|
||||
|
|
||||
not pkgJSON.declaresDependency(mod, _) and
|
||||
not pkgJSON.getPeerDependencies().getADependency(mod, _) and
|
||||
not pkgJson.declaresDependency(mod, _) and
|
||||
not pkgJson.getPeerDependencies().getADependency(mod, _) and
|
||||
// exclude packages depending on `fbjs`, which automatically pulls in many otherwise
|
||||
// undeclared dependencies
|
||||
not pkgJSON.declaresDependency("fbjs", _)
|
||||
not pkgJson.declaresDependency("fbjs", _)
|
||||
)
|
||||
select r, "Module " + mod + " cannot be resolved, and is not declared as a dependency in $@.",
|
||||
getClosestPackageJSON(r.getFile().getParentContainer()), "package.json"
|
||||
getClosestPackageJson(r.getFile().getParentContainer()), "package.json"
|
||||
|
||||
@@ -16,19 +16,19 @@ import javascript
|
||||
* Holds if the NPM package `pkg` declares a dependency on package `name`,
|
||||
* and `dep` is the corresponding declaration in the `package.json` file.
|
||||
*/
|
||||
predicate declaresDependency(NPMPackage pkg, string name, JSONValue dep) {
|
||||
dep = pkg.getPackageJSON().getDependencies().getPropValue(name)
|
||||
predicate declaresDependency(NpmPackage pkg, string name, JsonValue dep) {
|
||||
dep = pkg.getPackageJson().getDependencies().getPropValue(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a path expression in a module belonging to `pkg`.
|
||||
*/
|
||||
PathExpr getAPathExpr(NPMPackage pkg) { result.getEnclosingModule() = pkg.getAModule() }
|
||||
PathExpr getAPathExpr(NpmPackage pkg) { result.getEnclosingModule() = pkg.getAModule() }
|
||||
|
||||
/**
|
||||
* Gets a URL-valued attribute in a module or HTML file belonging to `pkg`.
|
||||
*/
|
||||
DOM::AttributeDefinition getAURLAttribute(NPMPackage pkg) {
|
||||
DOM::AttributeDefinition getAUrlAttribute(NpmPackage pkg) {
|
||||
result.getFile() = pkg.getAFile() and
|
||||
DOM::isUrlValuedAttribute(result)
|
||||
}
|
||||
@@ -37,10 +37,10 @@ DOM::AttributeDefinition getAURLAttribute(NPMPackage pkg) {
|
||||
* Gets the name of a script in the 'scripts' object of `pkg`.
|
||||
* The script makes use of a declared `dependency` of `pkg`.
|
||||
*/
|
||||
string getPackageScriptNameWithDependency(NPMPackage pkg, string dependency) {
|
||||
exists(JSONObject scriptsObject, string scriptName, string script |
|
||||
string getPackageScriptNameWithDependency(NpmPackage pkg, string dependency) {
|
||||
exists(JsonObject scriptsObject, string scriptName, string script |
|
||||
declaresDependency(pkg, dependency, _) and
|
||||
scriptsObject = pkg.getPackageJSON().getPropValue("scripts") and
|
||||
scriptsObject = pkg.getPackageJson().getPropValue("scripts") and
|
||||
script = scriptsObject.getPropStringValue(scriptName) and
|
||||
script.regexpMatch(".*\\b\\Q" + dependency + "\\E\\b.*") and
|
||||
result = scriptName
|
||||
@@ -51,7 +51,7 @@ string getPackageScriptNameWithDependency(NPMPackage pkg, string dependency) {
|
||||
* Holds if the NPM package `pkg` declares a dependency on package `name`,
|
||||
* and uses it at least once.
|
||||
*/
|
||||
predicate usesDependency(NPMPackage pkg, string name) {
|
||||
predicate usesDependency(NpmPackage pkg, string name) {
|
||||
declaresDependency(pkg, name, _) and
|
||||
(
|
||||
// there is a path expression (e.g., in a `require` or `import`) that
|
||||
@@ -62,7 +62,7 @@ predicate usesDependency(NPMPackage pkg, string name) {
|
||||
)
|
||||
or
|
||||
// there is an HTML URL attribute that may reference `pkg`
|
||||
exists(DOM::AttributeDefinition attr | attr = getAURLAttribute(pkg) |
|
||||
exists(DOM::AttributeDefinition attr | attr = getAUrlAttribute(pkg) |
|
||||
// check whether the URL contains `node_modules/name`
|
||||
attr.getStringValue().regexpMatch(".*\\bnode_modules/\\Q" + name + "\\E(/.*)?")
|
||||
)
|
||||
@@ -85,7 +85,7 @@ predicate usesDependency(NPMPackage pkg, string name) {
|
||||
* view engine definitions, which (may) implicitly require the specified
|
||||
* engine as a module.
|
||||
*/
|
||||
predicate implicitRequire(NPMPackage pkg, string name) {
|
||||
predicate implicitRequire(NpmPackage pkg, string name) {
|
||||
// look for Express `set('view engine', ...)` calls
|
||||
exists(MethodCallExpr setViewEngine, string engine |
|
||||
Express::appCreation().flowsToExpr(setViewEngine.getReceiver()) and
|
||||
@@ -99,7 +99,7 @@ predicate implicitRequire(NPMPackage pkg, string name) {
|
||||
)
|
||||
}
|
||||
|
||||
from NPMPackage pkg, string name, JSONValue dep
|
||||
from NpmPackage pkg, string name, JsonValue dep
|
||||
where
|
||||
exists(pkg.getAModule()) and
|
||||
declaresDependency(pkg, name, dep) and
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
import javascript
|
||||
import semmle.javascript.security.dataflow.ExternalAPIUsedWithUntrustedDataQuery
|
||||
|
||||
from ExternalAPIUsedWithUntrustedData externalAPI
|
||||
select externalAPI, count(externalAPI.getUntrustedDataNode()) as numberOfUses,
|
||||
externalAPI.getNumberOfUntrustedSources() as numberOfUntrustedSources order by
|
||||
from ExternalApiUsedWithUntrustedData externalApi
|
||||
select externalApi, count(externalApi.getUntrustedDataNode()) as numberOfUses,
|
||||
externalApi.getNumberOfUntrustedSources() as numberOfUntrustedSources order by
|
||||
numberOfUntrustedSources desc
|
||||
|
||||
@@ -123,12 +123,13 @@ predicate isDerivedFromLength(DataFlow::Node length, DataFlow::Node operand) {
|
||||
*/
|
||||
class UnsafeIndexOfComparison extends EqualityTest {
|
||||
IndexOfCall indexOf;
|
||||
DataFlow::Node testedValue;
|
||||
|
||||
UnsafeIndexOfComparison() {
|
||||
this.hasOperands(indexOf.getAUse(), testedValue.asExpr()) and
|
||||
isDerivedFromLength(testedValue, indexOf.getReceiver()) and
|
||||
isDerivedFromLength(testedValue, indexOf.getArgument(0)) and
|
||||
exists(DataFlow::Node testedValue |
|
||||
this.hasOperands(indexOf.getAUse(), testedValue.asExpr()) and
|
||||
isDerivedFromLength(testedValue, indexOf.getReceiver()) and
|
||||
isDerivedFromLength(testedValue, indexOf.getArgument(0))
|
||||
) and
|
||||
// Ignore cases like `x.indexOf("/") === x.length - 1` that can only be bypassed if `x` is the empty string.
|
||||
// Sometimes strings are just known to be non-empty from the context, and it is unlikely to be a security issue,
|
||||
// since it's obviously not a domain name check.
|
||||
|
||||
@@ -23,7 +23,7 @@ newtype TRegExpPatternMistake =
|
||||
* by `mistake`.
|
||||
*/
|
||||
TIdentityEscapeInStringMistake(
|
||||
RegExpPatternSource src, string char, string mistake, ASTNode rawStringNode, int index
|
||||
RegExpPatternSource src, string char, string mistake, AstNode rawStringNode, int index
|
||||
) {
|
||||
char = getALikelyRegExpPatternMistake(src, mistake, rawStringNode, index)
|
||||
} or
|
||||
@@ -32,7 +32,7 @@ newtype TRegExpPatternMistake =
|
||||
* regular expression string `src`, indicating intent to use the
|
||||
* word-boundary assertion '\b'.
|
||||
*/
|
||||
TBackspaceInStringMistake(RegExpPatternSource src, ASTNode rawStringNode, int index) {
|
||||
TBackspaceInStringMistake(RegExpPatternSource src, AstNode rawStringNode, int index) {
|
||||
exists(string raw, string cooked |
|
||||
exists(StringLiteral lit | lit = rawStringNode |
|
||||
rawStringNode = src.asExpr() and
|
||||
@@ -91,7 +91,7 @@ class RegExpPatternMistake extends TRegExpPatternMistake {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = getMessage() }
|
||||
|
||||
abstract ASTNode getRawStringNode();
|
||||
abstract AstNode getRawStringNode();
|
||||
|
||||
abstract RegExpPatternSource getSrc();
|
||||
|
||||
@@ -109,7 +109,7 @@ class IdentityEscapeInStringMistake extends RegExpPatternMistake, TIdentityEscap
|
||||
string char;
|
||||
string mistake;
|
||||
int index;
|
||||
ASTNode rawStringNode;
|
||||
AstNode rawStringNode;
|
||||
|
||||
IdentityEscapeInStringMistake() {
|
||||
this = TIdentityEscapeInStringMistake(src, char, mistake, rawStringNode, index)
|
||||
@@ -123,7 +123,7 @@ class IdentityEscapeInStringMistake extends RegExpPatternMistake, TIdentityEscap
|
||||
|
||||
override RegExpPatternSource getSrc() { result = src }
|
||||
|
||||
override ASTNode getRawStringNode() { result = rawStringNode }
|
||||
override AstNode getRawStringNode() { result = rawStringNode }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,7 +133,7 @@ class IdentityEscapeInStringMistake extends RegExpPatternMistake, TIdentityEscap
|
||||
class BackspaceInStringMistake extends RegExpPatternMistake, TBackspaceInStringMistake {
|
||||
RegExpPatternSource src;
|
||||
int index;
|
||||
ASTNode rawStringNode;
|
||||
AstNode rawStringNode;
|
||||
|
||||
BackspaceInStringMistake() { this = TBackspaceInStringMistake(src, rawStringNode, index) }
|
||||
|
||||
@@ -145,7 +145,7 @@ class BackspaceInStringMistake extends RegExpPatternMistake, TBackspaceInStringM
|
||||
|
||||
override RegExpPatternSource getSrc() { result = src }
|
||||
|
||||
override ASTNode getRawStringNode() { result = rawStringNode }
|
||||
override AstNode getRawStringNode() { result = rawStringNode }
|
||||
}
|
||||
|
||||
from RegExpPatternMistake mistake
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* user to execute arbitrary code.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 6.1
|
||||
* @precision medium
|
||||
* @id js/unsafe-code-construction
|
||||
* @tags security
|
||||
|
||||
@@ -18,6 +18,6 @@
|
||||
|
||||
import semmle.javascript.security.BadTagFilterQuery
|
||||
|
||||
from HTMLMatchingRegExp regexp, string msg
|
||||
from HtmlMatchingRegExp regexp, string msg
|
||||
where msg = min(string m | isBadRegexpFilter(regexp, m) | m order by m.length(), m) // there might be multiple, we arbitrarily pick the shortest one
|
||||
select regexp, msg
|
||||
|
||||
@@ -69,7 +69,7 @@ DataFlow::Node getANodeModulePath(string path) {
|
||||
* Gets a folder that contains a `package.json` file.
|
||||
*/
|
||||
pragma[noinline]
|
||||
Folder getAPackageJSONFolder() { result = any(PackageJSON json).getFile().getParentContainer() }
|
||||
Folder getAPackageJsonFolder() { result = any(PackageJson json).getFile().getParentContainer() }
|
||||
|
||||
/**
|
||||
* Gets a reference to `dirname`, the home folder, the current working folder, or the root folder.
|
||||
@@ -82,7 +82,7 @@ Folder getAPackageJSONFolder() { result = any(PackageJSON json).getFile().getPar
|
||||
*/
|
||||
DataFlow::Node getALeakingFolder(string description) {
|
||||
exists(ModuleScope ms | result.asExpr() = ms.getVariable("__dirname").getAnAccess()) and
|
||||
result.getFile().getParentContainer() = getAPackageJSONFolder() and
|
||||
result.getFile().getParentContainer() = getAPackageJsonFolder() and
|
||||
(
|
||||
if result.getFile().getParentContainer().getRelativePath().trim() != ""
|
||||
then description = "the folder " + result.getFile().getParentContainer().getRelativePath()
|
||||
|
||||
@@ -13,26 +13,25 @@
|
||||
|
||||
import javascript
|
||||
|
||||
/**
|
||||
* Gets an options object for a TLS connection.
|
||||
*/
|
||||
DataFlow::ObjectLiteralNode tlsOptions() {
|
||||
exists(DataFlow::InvokeNode invk | result.flowsTo(invk.getAnArgument()) |
|
||||
invk instanceof ClientRequest
|
||||
or
|
||||
invk = DataFlow::moduleMember("https", "Agent").getAnInstantiation()
|
||||
or
|
||||
exists(DataFlow::NewNode new |
|
||||
new = DataFlow::moduleMember("tls", "TLSSocket").getAnInstantiation()
|
||||
|
|
||||
invk = new or
|
||||
invk = new.getAMethodCall("renegotiate")
|
||||
)
|
||||
or
|
||||
invk = DataFlow::moduleMember("tls", ["connect", "createServer"]).getACall()
|
||||
/** Gets options argument for a potential TLS connection */
|
||||
DataFlow::InvokeNode tlsInvocation() {
|
||||
result instanceof ClientRequest
|
||||
or
|
||||
result = DataFlow::moduleMember("https", "Agent").getAnInstantiation()
|
||||
or
|
||||
exists(DataFlow::NewNode new |
|
||||
new = DataFlow::moduleMember("tls", "TLSSocket").getAnInstantiation()
|
||||
|
|
||||
result = new or
|
||||
result = new.getAMethodCall("renegotiate")
|
||||
)
|
||||
or
|
||||
result = DataFlow::moduleMember("tls", ["connect", "createServer"]).getACall()
|
||||
}
|
||||
|
||||
/** Gets an options object for a TLS connection. */
|
||||
DataFlow::ObjectLiteralNode tlsOptions() { result.flowsTo(tlsInvocation().getAnArgument()) }
|
||||
|
||||
from DataFlow::PropWrite disable
|
||||
where
|
||||
exists(DataFlow::SourceNode env |
|
||||
@@ -41,6 +40,13 @@ where
|
||||
disable.getRhs().mayHaveStringValue("0")
|
||||
)
|
||||
or
|
||||
disable = tlsOptions().getAPropertyWrite("rejectUnauthorized") and
|
||||
(
|
||||
disable = tlsOptions().getAPropertyWrite("rejectUnauthorized")
|
||||
or
|
||||
// the same thing, but with API-nodes if they happen to be available
|
||||
exists(API::Node tlsInvk | tlsInvk.getAnInvocation() = tlsInvocation() |
|
||||
disable.getRhs() = tlsInvk.getAParameter().getMember("rejectUnauthorized").getARhs()
|
||||
)
|
||||
) and
|
||||
disable.getRhs().(AnalyzedNode).getTheBooleanValue() = false
|
||||
select disable, "Disabling certificate validation is strongly discouraged."
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import javascript
|
||||
|
||||
from PackageJSON pack, JSONString val
|
||||
from PackageJson pack, JsonString val
|
||||
where
|
||||
[pack.getDependencies(), pack.getDevDependencies()].getPropValue(_) = val and
|
||||
val.getValue().regexpMatch("(http|ftp)://.*")
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* @description The application does not verify the JWT payload with a cryptographic secret or public key.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 7.0
|
||||
* @precision high
|
||||
* @id js/jwt-missing-verification
|
||||
* @tags security
|
||||
|
||||
@@ -130,7 +130,7 @@ class AsyncCallback extends Function {
|
||||
*
|
||||
* This is the primary extension point for this query.
|
||||
*/
|
||||
abstract class LikelyExceptionThrower extends ASTNode { }
|
||||
abstract class LikelyExceptionThrower extends AstNode { }
|
||||
|
||||
/**
|
||||
* A `throw` statement.
|
||||
@@ -152,7 +152,7 @@ class CompilerConfusingExceptionThrower extends LikelyExceptionThrower {
|
||||
* - step 3. exception follows the call graph backwards until an async callee is encountered
|
||||
* - step 4. (at this point, the program crashes)
|
||||
*/
|
||||
query predicate edges(ASTNode pred, ASTNode succ) {
|
||||
query predicate edges(AstNode pred, AstNode succ) {
|
||||
exists(LikelyExceptionThrower thrower | main(_, _, _, thrower) |
|
||||
pred = thrower and
|
||||
succ = thrower.getContainer()
|
||||
@@ -174,7 +174,7 @@ query predicate edges(ASTNode pred, ASTNode succ) {
|
||||
/**
|
||||
* Holds if `node` is in the `edge/2` relation above.
|
||||
*/
|
||||
query predicate nodes(ASTNode node) {
|
||||
query predicate nodes(AstNode node) {
|
||||
edges(node, _) or
|
||||
edges(_, node)
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ predicate benignContext(Expr e) {
|
||||
e.getParent().(ExprStmt).getParent() instanceof CodeInAttribute
|
||||
or
|
||||
// and JSX-attributes.
|
||||
e = any(JSXAttribute attr).getValue()
|
||||
e = any(JsxAttribute attr).getValue()
|
||||
or
|
||||
exists(AwaitExpr await | await.getOperand() = e and benignContext(await))
|
||||
or
|
||||
|
||||
@@ -139,12 +139,12 @@ predicate whitelist(Expr e) {
|
||||
* The return value of `e` may have other uses besides the truthiness check,
|
||||
* but if the truthiness check always goes one way, it still indicates an error.
|
||||
*/
|
||||
predicate isConditional(ASTNode cond, Expr e) {
|
||||
predicate isConditional(AstNode cond, Expr e) {
|
||||
isExplicitConditional(cond, e) or
|
||||
e = cond.(LogicalBinaryExpr).getLeftOperand()
|
||||
}
|
||||
|
||||
from ASTNode cond, DataFlow::AnalyzedNode op, boolean cv, ASTNode sel, string msg
|
||||
from AstNode cond, DataFlow::AnalyzedNode op, boolean cv, AstNode sel, string msg
|
||||
where
|
||||
isConditional(cond, op.asExpr()) and
|
||||
cv = op.getTheBooleanValue() and
|
||||
|
||||
@@ -9,7 +9,7 @@ import javascript
|
||||
* `e` and checks its value for truthiness, and the return value of `e`
|
||||
* is not used for anything other than this truthiness check.
|
||||
*/
|
||||
predicate isExplicitConditional(ASTNode cond, Expr e) {
|
||||
predicate isExplicitConditional(AstNode cond, Expr e) {
|
||||
e = cond.(IfStmt).getCondition()
|
||||
or
|
||||
e = cond.(LoopStmt).getTest()
|
||||
|
||||
1
javascript/ql/src/change-notes/released/0.0.12.md
Normal file
1
javascript/ql/src/change-notes/released/0.0.12.md
Normal file
@@ -0,0 +1 @@
|
||||
## 0.0.12
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.0.11
|
||||
lastReleaseVersion: 0.0.12
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
|
||||
import definitions
|
||||
|
||||
from Locatable e, ASTNode def, string kind
|
||||
from Locatable e, AstNode def, string kind
|
||||
where def = definitionOf(e, kind)
|
||||
select e, def, kind
|
||||
|
||||
@@ -25,7 +25,7 @@ private string refKind(RefExpr r) {
|
||||
/**
|
||||
* Gets a class, function or object literal `va` may refer to.
|
||||
*/
|
||||
private ASTNode lookupDef(VarAccess va) {
|
||||
private AstNode lookupDef(VarAccess va) {
|
||||
exists(AbstractValue av | av = va.analyze().getAValue() |
|
||||
result = av.(AbstractClass).getClass() or
|
||||
result = av.(AbstractFunction).getFunction() or
|
||||
@@ -37,7 +37,7 @@ private ASTNode lookupDef(VarAccess va) {
|
||||
* Holds if `va` is of kind `kind` and `def` is the unique class,
|
||||
* function or object literal it refers to.
|
||||
*/
|
||||
private predicate variableDefLookup(VarAccess va, ASTNode def, string kind) {
|
||||
private predicate variableDefLookup(VarAccess va, AstNode def, string kind) {
|
||||
count(lookupDef(va)) = 1 and
|
||||
def = lookupDef(va) and
|
||||
kind = refKind(va)
|
||||
@@ -66,7 +66,7 @@ private predicate variableDeclLookup(VarAccess va, VarDecl decl, string kind) {
|
||||
* For example, in the statement `var a = require("./a")`, the path expression
|
||||
* `"./a"` imports a module `a` in the same folder.
|
||||
*/
|
||||
private predicate importLookup(ASTNode path, Module target, string kind) {
|
||||
private predicate importLookup(AstNode path, Module target, string kind) {
|
||||
kind = "I" and
|
||||
(
|
||||
exists(Import i |
|
||||
@@ -84,7 +84,7 @@ private predicate importLookup(ASTNode path, Module target, string kind) {
|
||||
/**
|
||||
* Gets a node that may write the property read by `prn`.
|
||||
*/
|
||||
private ASTNode getAWrite(DataFlow::PropRead prn) {
|
||||
private AstNode getAWrite(DataFlow::PropRead prn) {
|
||||
exists(DataFlow::AnalyzedNode base, DefiniteAbstractValue baseVal, string propName |
|
||||
base = prn.getBase() and
|
||||
propName = prn.getPropertyName() and
|
||||
@@ -112,7 +112,7 @@ private ASTNode getAWrite(DataFlow::PropRead prn) {
|
||||
* only such property write. Parameter `kind` is always bound to `"M"`
|
||||
* at the moment.
|
||||
*/
|
||||
private predicate propertyLookup(Expr prop, ASTNode write, string kind) {
|
||||
private predicate propertyLookup(Expr prop, AstNode write, string kind) {
|
||||
exists(DataFlow::PropRead prn | prop = prn.getPropertyNameExpr() |
|
||||
count(getAWrite(prn)) = 1 and
|
||||
write = getAWrite(prn) and
|
||||
@@ -123,7 +123,7 @@ private predicate propertyLookup(Expr prop, ASTNode write, string kind) {
|
||||
/**
|
||||
* Holds if `ref` is an identifier that refers to a type declared at `decl`.
|
||||
*/
|
||||
private predicate typeLookup(ASTNode ref, ASTNode decl, string kind) {
|
||||
private predicate typeLookup(AstNode ref, AstNode decl, string kind) {
|
||||
exists(TypeAccess typeAccess |
|
||||
ref = typeAccess.getIdentifier() and
|
||||
decl = typeAccess.getTypeName().getADefinition() and
|
||||
@@ -134,7 +134,7 @@ private predicate typeLookup(ASTNode ref, ASTNode decl, string kind) {
|
||||
/**
|
||||
* Holds if `ref` is the callee name of an invocation of `decl`.
|
||||
*/
|
||||
private predicate typedInvokeLookup(ASTNode ref, ASTNode decl, string kind) {
|
||||
private predicate typedInvokeLookup(AstNode ref, AstNode decl, string kind) {
|
||||
not variableDefLookup(ref, decl, _) and
|
||||
not propertyLookup(ref, decl, _) and
|
||||
exists(InvokeExpr invoke, Expr callee |
|
||||
@@ -148,7 +148,7 @@ private predicate typedInvokeLookup(ASTNode ref, ASTNode decl, string kind) {
|
||||
/**
|
||||
* Holds if `ref` is a JSDoc type annotation referring to a class defined at `decl`.
|
||||
*/
|
||||
private predicate jsdocTypeLookup(JSDocNamedTypeExpr ref, ASTNode decl, string kind) {
|
||||
private predicate jsdocTypeLookup(JSDocNamedTypeExpr ref, AstNode decl, string kind) {
|
||||
decl = ref.getClass().getAstNode() and
|
||||
kind = "T"
|
||||
}
|
||||
@@ -163,7 +163,7 @@ private predicate jsdocTypeLookup(JSDocNamedTypeExpr ref, ASTNode decl, string k
|
||||
* - `"I"` for imports
|
||||
*/
|
||||
cached
|
||||
ASTNode definitionOf(Locatable e, string kind) {
|
||||
AstNode definitionOf(Locatable e, string kind) {
|
||||
variableDefLookup(e, result, kind)
|
||||
or
|
||||
// prefer definitions over declarations
|
||||
|
||||
@@ -35,13 +35,14 @@ external predicate additionalSteps(
|
||||
* An additional source specified through the `additionalSources` predicate.
|
||||
*/
|
||||
private class AdditionalSourceFromSpec extends DataFlow::AdditionalSource {
|
||||
Portal portal;
|
||||
string flowLabel;
|
||||
string config;
|
||||
|
||||
AdditionalSourceFromSpec() {
|
||||
additionalSources(portal.toString(), flowLabel, config) and
|
||||
this = portal.getAnExitNode(_)
|
||||
exists(Portal portal |
|
||||
additionalSources(portal.toString(), flowLabel, config) and
|
||||
this = portal.getAnExitNode(_)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSourceFor(DataFlow::Configuration cfg, DataFlow::FlowLabel lbl) {
|
||||
@@ -53,13 +54,14 @@ private class AdditionalSourceFromSpec extends DataFlow::AdditionalSource {
|
||||
* An additional sink specified through the `additionalSinks` predicate.
|
||||
*/
|
||||
private class AdditionalSinkFromSpec extends DataFlow::AdditionalSink {
|
||||
Portal portal;
|
||||
string flowLabel;
|
||||
string config;
|
||||
|
||||
AdditionalSinkFromSpec() {
|
||||
additionalSinks(portal.toString(), flowLabel, config) and
|
||||
this = portal.getAnEntryNode(_)
|
||||
exists(Portal portal |
|
||||
additionalSinks(portal.toString(), flowLabel, config) and
|
||||
this = portal.getAnEntryNode(_)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSinkFor(DataFlow::Configuration cfg, DataFlow::FlowLabel lbl) {
|
||||
|
||||
@@ -23,6 +23,11 @@ module ResourceExhaustion {
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
super.isSanitizer(node) or
|
||||
node instanceof Sanitizer
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node src, DataFlow::Node dst) {
|
||||
isNumericFlowStep(src, dst)
|
||||
or
|
||||
|
||||
@@ -11,6 +11,6 @@ import definitions
|
||||
|
||||
external string selectedSourceFile();
|
||||
|
||||
from Locatable e, ASTNode def, string kind
|
||||
from Locatable e, AstNode def, string kind
|
||||
where def = definitionOf(e, kind) and e.getFile() = getFileBySourceArchiveName(selectedSourceFile())
|
||||
select e, def, kind
|
||||
|
||||
@@ -11,7 +11,7 @@ import definitions
|
||||
|
||||
external string selectedSourceFile();
|
||||
|
||||
from Locatable e, ASTNode def, string kind
|
||||
from Locatable e, AstNode def, string kind
|
||||
where
|
||||
def = definitionOf(e, kind) and def.getFile() = getFileBySourceArchiveName(selectedSourceFile())
|
||||
select e, def, kind
|
||||
|
||||
@@ -24,7 +24,7 @@ predicate exprWithoutEnclosingStmt(Expr e) {
|
||||
// Some expressions have non-expression parents that we want to skip over.
|
||||
exprWithoutEnclosingStmt(e.getParent().(Property).getObjectExpr()) or
|
||||
exprWithoutEnclosingStmt(e.getParent().(PropertyPattern).getObjectPattern()) or
|
||||
exprWithoutEnclosingStmt(e.getParent().(JSXAttribute).getElement())
|
||||
exprWithoutEnclosingStmt(e.getParent().(JsxAttribute).getElement())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,7 +65,7 @@ predicate ast_consistency(string clsname, string problem, string what) {
|
||||
not exists(l.getLocation()) and problem = "no location" and what = l.toString()
|
||||
)
|
||||
or
|
||||
exists(ASTNode nd | clsname = nd.getAQlClass() |
|
||||
exists(AstNode nd | clsname = nd.getAQlClass() |
|
||||
uniqueness_error(count(nd.getTopLevel()), "getTopLevel", problem) and
|
||||
what = "at " + nd.getLocation()
|
||||
)
|
||||
@@ -120,7 +120,7 @@ predicate location_consistency(string clsname, string problem, string what) {
|
||||
/**
|
||||
* Holds if function or toplevel `sc` is expected to have an associated control flow graph.
|
||||
*/
|
||||
predicate hasCFG(StmtContainer sc) { not exists(Error err | err.getFile() = sc.getFile()) }
|
||||
predicate hasCfg(StmtContainer sc) { not exists(Error err | err.getFile() = sc.getFile()) }
|
||||
|
||||
/**
|
||||
* Holds if a contract involving the CFG structure is violated, where `clsname`
|
||||
@@ -128,7 +128,7 @@ predicate hasCFG(StmtContainer sc) { not exists(Error err | err.getFile() = sc.g
|
||||
* the violation, and `what` gives location information.
|
||||
*/
|
||||
predicate cfg_consistency(string clsname, string problem, string what) {
|
||||
exists(StmtContainer cont | clsname = cont.getAQlClass() and hasCFG(cont) |
|
||||
exists(StmtContainer cont | clsname = cont.getAQlClass() and hasCfg(cont) |
|
||||
uniqueness_error(count(cont.getEntry()), "getEntry", problem) and
|
||||
what = "at " + cont.getLocation()
|
||||
or
|
||||
@@ -136,7 +136,7 @@ predicate cfg_consistency(string clsname, string problem, string what) {
|
||||
what = "at " + cont.getLocation()
|
||||
)
|
||||
or
|
||||
exists(ASTNode nd | clsname = nd.getAQlClass() and hasCFG(nd.getTopLevel()) |
|
||||
exists(AstNode nd | clsname = nd.getAQlClass() and hasCfg(nd.getTopLevel()) |
|
||||
uniqueness_error(count(nd.getFirstControlFlowNode()), "getFirstControlFlowNode", problem) and
|
||||
what = "at " + nd.getLocation()
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/javascript-queries
|
||||
version: 0.0.12-dev
|
||||
version: 0.0.13-dev
|
||||
groups:
|
||||
- javascript
|
||||
- queries
|
||||
|
||||
Reference in New Issue
Block a user