mirror of
https://github.com/github/codeql.git
synced 2026-04-24 00:05:14 +02:00
Merge branch 'main' into seclab/dotjs
This commit is contained in:
@@ -192,7 +192,7 @@ export function augmentAst(ast: AugmentedSourceFile, code: string, project: Proj
|
||||
}
|
||||
|
||||
if (typeChecker != null) {
|
||||
if (isTypedNode(node)) {
|
||||
if (isTypedNode(node) && !typeTable.skipExtractingTypes) {
|
||||
let contextualType = isContextuallyTypedNode(node)
|
||||
? typeChecker.getContextualType(node)
|
||||
: null;
|
||||
|
||||
@@ -554,7 +554,7 @@ function handleOpenProjectCommand(command: OpenProjectCommand) {
|
||||
let program = project.program;
|
||||
let typeChecker = program.getTypeChecker();
|
||||
|
||||
let shouldReportDiagnostics = getEnvironmentVariable("SEMMLE_TYPESCRIPT_REPORT_DIAGNOSTICS", Boolean, false);
|
||||
let shouldReportDiagnostics = getEnvironmentVariable("SEMMLE_TYPESCRIPT_REPORT_DIAGNOSTICS", v => v.trim().toLowerCase() === "true", false);
|
||||
let diagnostics = shouldReportDiagnostics
|
||||
? program.getSemanticDiagnostics().filter(d => d.category === ts.DiagnosticCategory.Error)
|
||||
: [];
|
||||
@@ -807,7 +807,8 @@ function handleGetMetadataCommand(command: GetMetadataCommand) {
|
||||
|
||||
function reset() {
|
||||
state = new State();
|
||||
state.typeTable.restrictedExpansion = getEnvironmentVariable("SEMMLE_TYPESCRIPT_NO_EXPANSION", Boolean, true);
|
||||
state.typeTable.restrictedExpansion = getEnvironmentVariable("SEMMLE_TYPESCRIPT_NO_EXPANSION", v => v.trim().toLowerCase() === "true", true);
|
||||
state.typeTable.skipExtractingTypes = getEnvironmentVariable("CODEQL_EXTRACTOR_JAVASCRIPT_OPTION_SKIP_TYPES", v => v.trim().toLowerCase() === "true", false);
|
||||
}
|
||||
|
||||
function getEnvironmentVariable<T>(name: string, parse: (x: string) => T, defaultValue: T) {
|
||||
@@ -886,6 +887,7 @@ if (process.argv.length > 2) {
|
||||
if (argument === "--version") {
|
||||
console.log("parser-wrapper with TypeScript " + ts.version);
|
||||
} else if (pathlib.basename(argument) === "tsconfig.json") {
|
||||
reset();
|
||||
handleOpenProjectCommand({
|
||||
command: "open-project",
|
||||
tsConfig: argument,
|
||||
@@ -895,7 +897,7 @@ if (process.argv.length > 2) {
|
||||
virtualSourceRoot: null,
|
||||
});
|
||||
for (let sf of state.project.program.getSourceFiles()) {
|
||||
if (pathlib.basename(sf.fileName) === "lib.d.ts") continue;
|
||||
if (/lib\..*\.d\.ts/.test(pathlib.basename(sf.fileName)) || pathlib.basename(sf.fileName) === "lib.d.ts") continue;
|
||||
handleParseCommand({
|
||||
command: "parse",
|
||||
filename: sf.fileName,
|
||||
|
||||
@@ -383,6 +383,11 @@ export class TypeTable {
|
||||
*/
|
||||
public restrictedExpansion = false;
|
||||
|
||||
/**
|
||||
* If set to true, skip extracting types.
|
||||
*/
|
||||
public skipExtractingTypes = false;
|
||||
|
||||
private virtualSourceRoot: VirtualSourceRoot;
|
||||
|
||||
/**
|
||||
@@ -1240,8 +1245,15 @@ export class TypeTable {
|
||||
let indexOnStack = stack.length;
|
||||
stack.push(id);
|
||||
|
||||
/** Indicates if a type contains no type variables, is a type variable, or strictly contains type variables. */
|
||||
const enum TypeVarDepth {
|
||||
noTypeVar = 0,
|
||||
isTypeVar = 1,
|
||||
containsTypeVar = 2,
|
||||
}
|
||||
|
||||
for (let symbol of type.getProperties()) {
|
||||
let propertyType = this.tryGetTypeOfSymbol(symbol);
|
||||
let propertyType = typeTable.tryGetTypeOfSymbol(symbol);
|
||||
if (propertyType == null) continue;
|
||||
traverseType(propertyType);
|
||||
}
|
||||
@@ -1267,13 +1279,6 @@ export class TypeTable {
|
||||
|
||||
return lowlinkTable.get(id);
|
||||
|
||||
/** Indicates if a type contains no type variables, is a type variable, or strictly contains type variables. */
|
||||
const enum TypeVarDepth {
|
||||
noTypeVar = 0,
|
||||
isTypeVar = 1,
|
||||
containsTypeVar = 2,
|
||||
}
|
||||
|
||||
function traverseType(type: ts.Type): TypeVarDepth {
|
||||
if (isTypeVariable(type)) return TypeVarDepth.isTypeVar;
|
||||
let depth = TypeVarDepth.noTypeVar;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,10 @@
|
||||
## 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.
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* TypeScript 5.3 is now supported.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added models for the `sqlite` and `better-sqlite3` npm packages.
|
||||
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.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.8.3
|
||||
lastReleaseVersion: 0.8.4
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
name: codeql/javascript-all
|
||||
version: 0.8.4-dev
|
||||
version: 0.8.5-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}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -972,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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
import javascript
|
||||
private import AngularJS
|
||||
private import ServiceDefinitions
|
||||
|
||||
/**
|
||||
* Holds if `nd` is an `angular.injector()` value
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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`.
|
||||
@@ -137,7 +135,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 +181,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
|
||||
@@ -233,7 +231,7 @@ API::Node getAFuzzySuccessor(API::Node node) {
|
||||
* 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
|
||||
@@ -246,9 +244,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
|
||||
)
|
||||
}
|
||||
|
||||
@@ -338,7 +335,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 {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import semmle.javascript.security.TaintedObject
|
||||
import LoopBoundInjectionCustomizations::LoopBoundInjection
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
import javascript
|
||||
import semmle.javascript.security.TaintedObject
|
||||
import semmle.javascript.dependencies.Dependencies
|
||||
import semmle.javascript.dependencies.SemVer
|
||||
|
||||
module PrototypePollution {
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
import javascript
|
||||
import semmle.javascript.security.TaintedObject
|
||||
import semmle.javascript.dependencies.Dependencies
|
||||
import semmle.javascript.dependencies.SemVer
|
||||
import PrototypePollutionCustomizations::PrototypePollution
|
||||
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
## 0.8.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added django URLs to detected "safe" URL patterns in `js/unsafe-external-link`.
|
||||
|
||||
## 0.8.3
|
||||
|
||||
### Query Metadata Changes
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
## 0.8.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added django URLs to detected "safe" URL patterns in `js/unsafe-external-link`.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.8.3
|
||||
lastReleaseVersion: 0.8.4
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import meta.MetaMetrics
|
||||
private import Expressions.ExprHasNoEffect
|
||||
import meta.internal.TaintMetrics
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/javascript-queries
|
||||
version: 0.8.4-dev
|
||||
version: 0.8.5-dev
|
||||
groups:
|
||||
- javascript
|
||||
- queries
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import javascript
|
||||
import semmle.javascript.dependencies.Dependencies
|
||||
import semmle.javascript.dependencies.SemVer
|
||||
|
||||
class SampleVersionSink extends DataFlow::Node {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import javascript
|
||||
import testUtilities.ConsistencyChecking
|
||||
import semmle.javascript.frameworks.data.internal.AccessPathSyntax as AccessPathSyntax
|
||||
import semmle.javascript.frameworks.data.internal.ApiGraphModels as ApiGraphModels
|
||||
|
||||
class Steps extends ModelInput::SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
@@ -126,6 +126,6 @@ class SyntaxErrorTest extends ModelInput::SinkModelCsv {
|
||||
}
|
||||
}
|
||||
|
||||
query predicate syntaxErrors(AccessPathSyntax::AccessPath path) { path.hasSyntaxError() }
|
||||
query predicate syntaxErrors(ApiGraphModels::AccessPath path) { path.hasSyntaxError() }
|
||||
|
||||
query predicate warning = ModelOutput::getAWarning/0;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import javascript
|
||||
import semmle.javascript.frameworks.data.internal.AccessPathSyntax as AccessPathSyntax
|
||||
import semmle.javascript.frameworks.data.internal.ApiGraphModels as ApiGraphModels
|
||||
|
||||
private class InvalidTypeModel extends ModelInput::TypeModelCsv {
|
||||
|
||||
Reference in New Issue
Block a user