Merge remote-tracking branch 'origin/main' into smowton/admin/merge-rc317-into-main

This commit is contained in:
Chris Smowton
2025-03-19 16:01:29 +00:00
2476 changed files with 45571 additions and 29067 deletions

View File

@@ -0,0 +1,4 @@
---
category: majorAnalysis
---
* Added support for TypeScript 5.8.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added support for the `react-relay` library.

View File

@@ -0,0 +1,7 @@
---
category: feature
---
* Extraction now supports regular expressions with the `v` flag, using the new operators:
- Intersection `&&`
- Subtraction `--`
- `\q` quoted string

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Improved the modeling of the `markdown-table` package to ensure it handles nested arrays properly.

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* Added support for the `@tanstack/angular-query-experimental` package.
* Improved support for the `@angular/common/http` package, detecting outgoing HTTP requests in more cases.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added support for the `@tanstack/vue-query` package.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added taint-steps for `unescape()`.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added additional flow step for `unescape()` and `escape()`.

View File

@@ -0,0 +1,6 @@
extensions:
- addsTo:
pack: codeql/javascript-all
extensible: summaryModel
data:
- ["markdown-table", "", "Argument[0].ArrayElement.ArrayElement", "ReturnValue", "taint"]

View File

@@ -0,0 +1,15 @@
extensions:
- addsTo:
pack: codeql/javascript-all
extensible: sourceModel
data:
- ["react-relay", "Member[useFragment].ReturnValue", "response"]
- ["react-relay", "Member[useLazyLoadQuery].ReturnValue", "response"]
- ["react-relay", "Member[usePreloadedQuery].ReturnValue", "response"]
- ["react-relay", "Member[useClientQuery].ReturnValue", "response"]
- ["react-relay", "Member[useRefetchableFragment].ReturnValue.Member[0]", "response"]
- ["react-relay", "Member[usePaginationFragment].ReturnValue.Member[data]", "response"]
- ["react-relay", "Member[useMutation].ReturnValue.Member[0].Argument[0].Member[onCompleted].Parameter[0]", "response"]
- ["react-relay", "Member[useSubscription].Argument[0].Member[onNext].Parameter[0]", "response"]
- ["react-relay", "Member[fetchQuery].ReturnValue.Member[subscribe].Argument[0].Member[next].Parameter[0]", "response"]
- ["relay-runtime", "Member[readFragment].ReturnValue", "response"]

View File

@@ -0,0 +1,11 @@
extensions:
- addsTo:
pack: codeql/javascript-all
extensible: summaryModel
data:
- ["@tanstack/angular-query-experimental", "Member[injectQuery]", "Argument[0].ReturnValue.Member[queryFn].ReturnValue", "ReturnValue.Member[data].Awaited", "value"]
- ["@tanstack/angular-query", "Member[injectQuery]", "Argument[0].ReturnValue.Member[queryFn].ReturnValue", "ReturnValue.Member[data].Awaited", "value"]
- ["@tanstack/vue-query", "Member[useQuery]", "Argument[0].Member[queryFn].ReturnValue.Awaited", "ReturnValue.Member[data]", "value"]
- ["@tanstack/vue-query", "Member[useQueries]", "Argument[0].Member[queries].ArrayElement.Member[queryFn].ReturnValue.Awaited", "ReturnValue.ArrayElement.Member[data]", "value"]
- ["@tanstack/react-query", "Member[useQueries]", "Argument[0].Member[queries].ArrayElement.Member[queryFn].ReturnValue.Awaited", "ReturnValue.ArrayElement.Member[data]", "value"]
- ["@tanstack/react-query", "Member[useQuery]", "Argument[0].Member[queryFn].ReturnValue.Awaited", "ReturnValue.Member[data]", "value"]

View File

@@ -139,7 +139,6 @@ import semmle.javascript.frameworks.Webix
import semmle.javascript.frameworks.WebSocket
import semmle.javascript.frameworks.XmlParsers
import semmle.javascript.frameworks.xUnit
import semmle.javascript.frameworks.Tanstack
import semmle.javascript.linters.ESLint
import semmle.javascript.linters.JSLint
import semmle.javascript.linters.Linting

View File

@@ -8,6 +8,10 @@
import javascript
private import semmle.javascript.dataflow.internal.FlowSteps as FlowSteps
private import semmle.javascript.dataflow.internal.PreCallGraphStep
private import semmle.javascript.dataflow.internal.StepSummary
private import semmle.javascript.dataflow.internal.sharedlib.SummaryTypeTracker as SummaryTypeTracker
private import semmle.javascript.dataflow.internal.Contents::Private as ContentPrivate
private import semmle.javascript.DynamicPropertyAccess
private import internal.CachedStages
/**
@@ -220,15 +224,53 @@ module API {
}
/**
* Gets a node representing a member of this API component where the name of the member is
* not known statically.
* DEPRECATED. Use either `getArrayElement()` or `getAMember()` instead.
*/
deprecated Node getUnknownMember() { result = this.getArrayElement() }
/**
* Gets an array element of unknown index.
*/
cached
Node getUnknownMember() {
Node getUnknownArrayElement() {
Stages::ApiStage::ref() and
result = this.getASuccessor(Label::unknownMember())
result = this.getASuccessor(Label::content(ContentPrivate::MkArrayElementUnknown()))
}
cached
private Node getContentRaw(DataFlow::Content content) {
Stages::ApiStage::ref() and
result = this.getASuccessor(Label::content(content))
}
/**
* Gets a representative for the `content` of this value.
*
* When possible, it is preferrable to use one of the specialized variants of this predicate, such as `getMember`.
*/
pragma[inline]
Node getContent(DataFlow::Content content) {
result = this.getContentRaw(content)
or
result = this.getMember(content.asPropertyName())
}
/**
* Gets a representative for the `contents` of this value.
*/
bindingset[contents]
pragma[inline_late]
private Node getContents(DataFlow::ContentSet contents) {
// We always use getAStoreContent when generating content edges, and we always use getAReadContent when querying the graph.
result = this.getContent(contents.getAReadContent())
}
/**
* Gets a node representing an arbitrary array element in the array represented by this node.
*/
cached
Node getArrayElement() { result = this.getContents(DataFlow::ContentSet::arrayElement()) }
/**
* Gets a node representing a member of this API component where the name of the member may
* or may not be known statically.
@@ -238,7 +280,7 @@ module API {
Stages::ApiStage::ref() and
result = this.getMember(_)
or
result = this.getUnknownMember()
result = this.getUnknownArrayElement()
}
/**
@@ -790,6 +832,11 @@ module API {
not DataFlow::PseudoProperties::isPseudoProperty(prop)
)
or
exists(DataFlow::ContentSet contents |
SummaryTypeTracker::basicStoreStep(rhs, pred.getALocalUse(), contents) and
lbl = Label::content(contents.getAStoreContent())
)
or
exists(DataFlow::FunctionNode fn |
fn = pred and
lbl = Label::return()
@@ -982,6 +1029,11 @@ module API {
// avoid generating member edges like "$arrayElement$"
not DataFlow::PseudoProperties::isPseudoProperty(prop)
)
or
exists(DataFlow::ContentSet contents |
SummaryTypeTracker::basicLoadStep(pred.getALocalUse(), ref, contents) and
lbl = Label::content(contents.getAStoreContent())
)
)
or
exists(DataFlow::Node def, DataFlow::FunctionNode fn |
@@ -1199,8 +1251,6 @@ module API {
t = useStep(nd, promisified, boundArgs, prop, result)
}
private import semmle.javascript.dataflow.internal.StepSummary
/**
* Holds if `nd`, which is a use of an API-graph node, flows in zero or more potentially
* inter-procedural steps to some intermediate node, and then from that intermediate node to
@@ -1458,8 +1508,21 @@ module API {
bindingset[result]
LabelMember member(string m) { result.getProperty() = m }
/** Gets the `member` edge label for the unknown member. */
LabelUnknownMember unknownMember() { any() }
/** Gets the `content` edge label for content `c`. */
LabelContent content(ContentPrivate::Content c) { result.getContent() = c }
/**
* Gets the edge label for an unknown member.
*
* Currently this is represented the same way as an unknown array element, but this may
* change in the future.
*/
ApiLabel unknownMember() { result = arrayElement() }
/**
* Gets the edge label for an unknown array element.
*/
LabelContent arrayElement() { result.getContent().isUnknownArrayElement() }
/**
* Gets a property name referred to by the given dynamic property access,
@@ -1482,6 +1545,11 @@ module API {
result = unique(string s | s = getAnIndirectPropName(ref))
}
pragma[nomagic]
private predicate isEnumeratedPropName(DataFlow::Node node) {
node.getAPredecessor*() instanceof EnumeratedPropName
}
/** Gets the `member` edge label for the given property reference. */
ApiLabel memberFromRef(DataFlow::PropRef pr) {
exists(string pn | pn = pr.getPropertyName() or pn = getIndirectPropName(pr) |
@@ -1493,7 +1561,9 @@ module API {
or
not exists(pr.getPropertyName()) and
not exists(getIndirectPropName(pr)) and
result = unknownMember()
// Avoid assignments in an extend-like pattern
not isEnumeratedPropName(pr.getPropertyNameExpr().flow()) and
result = arrayElement()
}
/** Gets the `instance` edge label. */
@@ -1516,10 +1586,10 @@ module API {
LabelForwardingFunction forwardingFunction() { any() }
/** Gets the `promised` edge label connecting a promise to its contained value. */
LabelPromised promised() { any() }
LabelContent promised() { result.getContent() = ContentPrivate::MkPromiseValue() }
/** Gets the `promisedError` edge label connecting a promise to its rejected value. */
LabelPromisedError promisedError() { any() }
LabelContent promisedError() { result.getContent() = ContentPrivate::MkPromiseError() }
/** Gets the label for an edge leading from a value `D` to any class that has `D` as a decorator. */
LabelDecoratedClass decoratedClass() { any() }
@@ -1542,18 +1612,12 @@ module API {
exists(Impl::MkModuleImport(mod))
} or
MkLabelInstance() or
MkLabelMember(string prop) {
exports(_, prop, _) or
exists(any(DataFlow::ClassNode c).getInstanceMethod(prop)) or
prop = "exports" or
prop = any(CanonicalName c).getName() or
prop = any(DataFlow::PropRef p).getPropertyName() or
exists(Impl::MkTypeUse(_, prop)) or
exists(any(Module m).getAnExportedValue(prop)) or
PreCallGraphStep::loadStep(_, _, prop) or
PreCallGraphStep::storeStep(_, _, prop)
MkLabelContent(DataFlow::Content content) or
MkLabelMember(string name) {
name instanceof PropertyName
or
exists(Impl::MkTypeUse(_, name))
} or
MkLabelUnknownMember() or
MkLabelParameter(int i) {
i =
[0 .. max(int args |
@@ -1564,8 +1628,6 @@ module API {
} or
MkLabelReceiver() or
MkLabelReturn() or
MkLabelPromised() or
MkLabelPromisedError() or
MkLabelDecoratedClass() or
MkLabelDecoratedMember() or
MkLabelDecoratedParameter() or
@@ -1585,13 +1647,13 @@ module API {
}
/** A label that gets a promised value. */
class LabelPromised extends ApiLabel, MkLabelPromised {
override string toString() { result = "getPromised()" }
deprecated class LabelPromised extends ApiLabel {
LabelPromised() { this = MkLabelContent(ContentPrivate::MkPromiseValue()) }
}
/** A label that gets a rejected promise. */
class LabelPromisedError extends ApiLabel, MkLabelPromisedError {
override string toString() { result = "getPromisedError()" }
deprecated class LabelPromisedError extends ApiLabel {
LabelPromisedError() { this = MkLabelContent(ContentPrivate::MkPromiseError()) }
}
/** A label that gets the return value of a function. */
@@ -1617,9 +1679,39 @@ module API {
override string toString() { result = "getInstance()" }
}
/** A label for a content. */
class LabelContent extends ApiLabel, MkLabelContent {
private DataFlow::Content content;
LabelContent() {
this = MkLabelContent(content) and
// Property names are represented by LabelMember to ensure additional property
// names from PreCallGraph step are included, as well as those from MkTypeUse.
not content instanceof ContentPrivate::MkPropertyContent
}
/** Gets the content associated with this label. */
DataFlow::Content getContent() { result = content }
private string specialisedToString() {
content instanceof ContentPrivate::MkPromiseValue and result = "getPromised()"
or
content instanceof ContentPrivate::MkPromiseError and result = "getPromisedError()"
or
content instanceof ContentPrivate::MkArrayElementUnknown and result = "getArrayElement()"
}
override string toString() {
result = this.specialisedToString()
or
not exists(this.specialisedToString()) and
result = "getContent(" + content + ")"
}
}
/** A label for the member named `prop`. */
class LabelMember extends ApiLabel, MkLabelMember {
string prop;
private string prop;
LabelMember() { this = MkLabelMember(prop) }
@@ -1630,10 +1722,8 @@ module API {
}
/** A label for a member with an unknown name. */
class LabelUnknownMember extends ApiLabel, MkLabelUnknownMember {
LabelUnknownMember() { this = MkLabelUnknownMember() }
override string toString() { result = "getUnknownMember()" }
deprecated class LabelUnknownMember extends LabelContent {
LabelUnknownMember() { this.getContent().isUnknownArrayElement() }
}
/** A label for parameter `i`. */

View File

@@ -140,22 +140,17 @@ module MembershipCandidate {
EnumerationRegExp() {
this.isRootTerm() and
RegExp::isFullyAnchoredTerm(this) and
exists(RegExpTerm child | this.getAChild*() = child |
child instanceof RegExpSequence or
child instanceof RegExpCaret or
child instanceof RegExpDollar or
child instanceof RegExpConstant or
child instanceof RegExpAlt or
child instanceof RegExpGroup
) and
// exclude "length matches" that match every string
not this.getAChild*() instanceof RegExpDot
not exists(RegExpTerm child | child.getRootTerm() = this |
child instanceof RegExpDot or
child instanceof RegExpCharacterClass or
child instanceof RegExpUnicodePropertyEscape
)
}
/**
* Gets a string matched by this regular expression.
*/
string getAMember() { result = this.getAChild*().getAMatchedString() }
string getAMember() { result = any(RegExpTerm t | t.getRootTerm() = this).getAMatchedString() }
}
/**

View File

@@ -4,6 +4,7 @@
import javascript
private import dataflow.internal.StepSummary
private import semmle.javascript.dataflow.internal.FlowSteps
/**
* A call to the `Promise` constructor, such as `new Promise((resolve, reject) => { ... })`.
@@ -397,6 +398,17 @@ module PromiseFlow {
value = call.getCallback(0).getExceptionalReturn() and
obj = call
)
or
exists(DataFlow::FunctionNode f | f.getFunction().isAsync() |
// ordinary return
prop = valueProp() and
value = f.getAReturn() and
obj = f.getReturnNode()
or
// exceptional return
prop = errorProp() and
localExceptionStepWithAsyncFlag(value, obj, true)
)
}
/**
@@ -525,30 +537,6 @@ private class PromiseTaintStep extends TaintTracking::LegacyTaintStep {
* Defines flow steps for return on async functions.
*/
private module AsyncReturnSteps {
private predicate valueProp = Promises::valueProp/0;
private predicate errorProp = Promises::errorProp/0;
private import semmle.javascript.dataflow.internal.FlowSteps
/**
* A data-flow step for ordinary and exceptional returns from async functions.
*/
private class AsyncReturn extends LegacyPreCallGraphStep {
override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
exists(DataFlow::FunctionNode f | f.getFunction().isAsync() |
// ordinary return
prop = valueProp() and
pred = f.getAReturn() and
succ = f.getReturnNode()
or
// exceptional return
prop = errorProp() and
localExceptionStepWithAsyncFlag(pred, succ, true)
)
}
}
/**
* A data-flow step for ordinary return from an async function in a taint configuration.
*/

View File

@@ -301,6 +301,51 @@ class RegExpAlt extends RegExpTerm, @regexp_alt {
override string getAPrimaryQlClass() { result = "RegExpAlt" }
}
/**
* An intersection term, that is, a term of the form `[[a]&&[ab]]`.
*
* Example:
*
* ```
* /[[abc]&&[bcd]]/v - which matches 'b' and 'c' only.
* ```
*/
class RegExpIntersection extends RegExpTerm, @regexp_intersection {
/** Gets an intersected term of this term. */
RegExpTerm getAnElement() { result = this.getAChild() }
/** Gets the number of intersected terms of this term. */
int getNumIntersectedTerm() { result = this.getNumChild() }
override predicate isNullable() { this.getAnElement().isNullable() }
override string getAPrimaryQlClass() { result = "RegExpIntersection" }
}
/**
* A subtraction term, that is, a term of the form `[[a]--[ab]]`.
*
* Example:
*
* ```
* /[[abc]--[bc]]/v - which matches 'a' only.
* ```
*/
class RegExpSubtraction extends RegExpTerm, @regexp_subtraction {
/** Gets the minuend (left operand) of this subtraction. */
RegExpTerm getFirstTerm() { result = this.getChild(0) }
/** Gets the number of subtractions terms of this term. */
int getNumSubtractedTerm() { result = this.getNumChild() - 1 }
/** Gets a subtrahend (right operand) of this subtraction. */
RegExpTerm getASubtractedTerm() { exists(int i | i > 0 and result = this.getChild(i)) }
override predicate isNullable() { none() }
override string getAPrimaryQlClass() { result = "RegExpSubtraction" }
}
/**
* A sequence term.
*
@@ -1142,6 +1187,28 @@ private class StringConcatRegExpPatternSource extends RegExpPatternSource {
override RegExpTerm getRegExpTerm() { result = this.asExpr().(AddExpr).asRegExp() }
}
/**
* A quoted string escape in a regular expression, using the `\q` syntax.
* The only operation supported inside a quoted string is alternation, using `|`.
*
* Example:
*
* ```
* \q{foo}
* \q{a|b|c}
* ```
*/
class RegExpQuotedString extends RegExpTerm, @regexp_quoted_string {
/** Gets the term representing the contents of this quoted string. */
RegExpTerm getTerm() { result = this.getAChild() }
override predicate isNullable() { none() }
override string getAMatchedString() { result = this.getTerm().getAMatchedString() }
override string getAPrimaryQlClass() { result = "RegExpQuotedString" }
}
module RegExp {
/** Gets the string `"?"` used to represent a regular expression whose flags are unknown. */
string unknownFlag() { result = "?" }

View File

@@ -188,27 +188,35 @@ module Routing {
)
}
/**
* Gets the path prefix needed to reach this node from the given ancestor, that is, the concatenation
* of all relative paths between this node and the ancestor.
*
* To restrict the size of the predicate, this is only available for the ancestors that are "fork" nodes,
* that is, a node that has siblings (i.e. multiple children).
*/
private string getPathFromFork(Node fork) {
private string getPathFromForkInternal(Node fork) {
this.isFork() and
this = fork and
result = ""
or
exists(Node parent | parent = this.getParent() |
not exists(parent.getRelativePath()) and
result = parent.getPathFromFork(fork)
result = parent.getPathFromForkInternal(fork)
or
result = parent.getPathFromFork(fork) + parent.getRelativePath() and
result = parent.getPathFromForkInternal(fork) + parent.getRelativePath() and
result.length() < 100
)
}
/**
* Gets the path prefix needed to reach this node from the given ancestor, that is, the concatenation
* of all relative paths between this node and the ancestor.
*
* To restrict the size of the predicate, this is only available for the ancestors that are "fork" nodes,
* that is, a node that has siblings (i.e. multiple children).
* And only a single (shortest) path is returned, even if there are multiple paths
* leading to this node.
*/
pragma[nomagic]
private string getPathFromFork(Node fork) {
result =
min(string res | res = this.getPathFromForkInternal(fork) | res order by res.length(), res)
}
/**
* Gets an HTTP method required to reach this node from the given ancestor, or `*` if any method
* can be used.

View File

@@ -773,6 +773,17 @@ class LocalTypeAccess extends @local_type_access, TypeAccess, Identifier, Lexica
*/
LocalTypeName getLocalTypeName() { result.getAnAccess() = this }
private TypeAliasDeclaration getAlias() {
this.getLocalTypeName().getADeclaration() = result.getIdentifier()
}
override TypeExpr getAnUnderlyingType() {
result = this.getAlias().getDefinition().getAnUnderlyingType()
or
not exists(this.getAlias()) and
result = this
}
override string getAPrimaryQlClass() { result = "LocalTypeAccess" }
}

View File

@@ -494,7 +494,8 @@ module TaintTracking {
succ = c and
c =
DataFlow::globalVarRef([
"encodeURI", "decodeURI", "encodeURIComponent", "decodeURIComponent"
"encodeURI", "decodeURI", "encodeURIComponent", "decodeURIComponent", "unescape",
"escape"
]).getACall() and
pred = c.getArgument(0)
)

View File

@@ -57,6 +57,16 @@ module Private {
this = getAPreciseArrayIndex().toString()
or
isAccessPathTokenPresent("Member", this)
or
this = any(ImportSpecifier spec).getImportedName()
or
this = any(ExportSpecifier n).getExportedName()
or
this = any(ExportNamedDeclaration d).getAnExportedDecl().getName()
or
this = any(MemberDefinition m).getName()
or
this = ["exports", "default"]
}
/** Gets the array index corresponding to this property name. */

View File

@@ -372,10 +372,11 @@ class CastNode extends DataFlow::Node {
cached
newtype TDataFlowCallable =
MkSourceCallable(StmtContainer container) or
MkLibraryCallable(LibraryCallable callable)
MkLibraryCallable(LibraryCallable callable) or
MkFileCallable(File file)
/**
* A callable entity. This is a wrapper around either a `StmtContainer` or a `LibraryCallable`.
* A callable entity. This is a wrapper around either a `StmtContainer`, `LibraryCallable`, or `File`.
*/
class DataFlowCallable extends TDataFlowCallable {
/** Gets a string representation of this callable. */
@@ -383,14 +384,21 @@ class DataFlowCallable extends TDataFlowCallable {
result = this.asSourceCallable().toString()
or
result = this.asLibraryCallable()
or
result = this.asFileCallable().toString()
}
/** Gets the location of this callable, if it is present in the source code. */
Location getLocation() { result = this.asSourceCallable().getLocation() }
Location getLocation() {
result = this.asSourceCallable().getLocation() or result = this.asFileCallable().getLocation()
}
/** Gets the corresponding `StmtContainer` if this is a source callable. */
StmtContainer asSourceCallable() { this = MkSourceCallable(result) }
/** Gets the corresponding `File` if this is a file representing a callable. */
File asFileCallable() { this = MkFileCallable(result) }
/** Gets the corresponding `StmtContainer` if this is a source callable. */
pragma[nomagic]
StmtContainer asSourceCallableNotExterns() {
@@ -537,6 +545,10 @@ DataFlowCallable nodeGetEnclosingCallable(Node node) {
result.asLibraryCallable() = node.(FlowSummaryDefaultExceptionalReturn).getSummarizedCallable()
or
node = TGenericSynthesizedNode(_, _, result)
or
node instanceof DataFlow::HtmlAttributeNode and result.asFileCallable() = node.getFile()
or
node instanceof DataFlow::XmlAttributeNode and result.asFileCallable() = node.getFile()
}
newtype TDataFlowType =

View File

@@ -81,7 +81,19 @@ module SsaDataflowInput implements DataFlowIntegrationInputSig {
class Guard extends js::ControlFlowNode {
Guard() { this = any(js::ConditionGuardNode g).getTest() }
predicate hasCfgNode(js::BasicBlock bb, int i) { this = bb.getNode(i) }
/**
* Holds if the control flow branching from `bb1` is dependent on this guard,
* and that the edge from `bb1` to `bb2` corresponds to the evaluation of this
* guard to `branch`.
*/
predicate controlsBranchEdge(js::BasicBlock bb1, js::BasicBlock bb2, boolean branch) {
exists(js::ConditionGuardNode g |
g.getTest() = this and
bb1 = this.getBasicBlock() and
bb2 = g.getBasicBlock() and
branch = g.getOutcome()
)
}
}
pragma[inline]
@@ -92,14 +104,6 @@ module SsaDataflowInput implements DataFlowIntegrationInputSig {
branch = g.getOutcome()
)
}
js::BasicBlock getAConditionalBasicBlockSuccessor(js::BasicBlock bb, boolean branch) {
exists(js::ConditionGuardNode g |
bb = g.getTest().getBasicBlock() and
result = g.getBasicBlock() and
branch = g.getOutcome()
)
}
}
import DataFlowIntegration<SsaDataflowInput>

View File

@@ -190,13 +190,16 @@ module Angular2 {
result.hasUnderlyingType("@angular/common/http", "HttpClient")
}
/** Gets a reference to an `HttpClient` object using the API graph. */
API::Node httpClientApiNode() { result = API::Node::ofType("@angular/common/http", "HttpClient") }
private class AngularClientRequest extends ClientRequest::Range, DataFlow::MethodCallNode {
int argumentOffset;
AngularClientRequest() {
this = httpClient().getAMethodCall("request") and argumentOffset = 1
this = httpClientApiNode().getMember("request").getACall() and argumentOffset = 1
or
this = httpClient().getAMethodCall() and
this = httpClientApiNode().getAMember().getACall() and
not this.getMethodName() = "request" and
argumentOffset = 0
}

View File

@@ -80,7 +80,7 @@ module D3 {
or
this = d3Selection().getMember("node").getReturn().asSource()
or
this = d3Selection().getMember("nodes").getReturn().getUnknownMember().asSource()
this = d3Selection().getMember("nodes").getReturn().getArrayElement().asSource()
}
}

View File

@@ -46,19 +46,6 @@ module Markdown {
}
}
/**
* A taint step for the `markdown-table` library.
*/
private class MarkdownTableStep extends MarkdownStep {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
exists(DataFlow::CallNode call | call = DataFlow::moduleImport("markdown-table").getACall() |
// TODO: needs a flow summary to ensure ArrayElement content is unfolded
succ = call and
pred = call.getArgument(0)
)
}
}
/**
* A taint step for the `showdown` library.
*/

View File

@@ -32,7 +32,7 @@ module Puppeteer {
or
result = [browser(), context()].getMember("newPage").getReturn().getPromised()
or
result = [browser(), context()].getMember("pages").getReturn().getPromised().getUnknownMember()
result = [browser(), context()].getMember("pages").getReturn().getPromised().getArrayElement()
or
result = target().getMember("page").getReturn().getPromised()
}
@@ -45,7 +45,7 @@ module Puppeteer {
or
result = [page(), browser()].getMember("target").getReturn()
or
result = context().getMember("targets").getReturn().getUnknownMember()
result = context().getMember("targets").getReturn().getArrayElement()
or
result = target().getMember("opener").getReturn()
}
@@ -58,7 +58,7 @@ module Puppeteer {
or
result = [page(), target()].getMember("browserContext").getReturn()
or
result = browser().getMember("browserContexts").getReturn().getUnknownMember()
result = browser().getMember("browserContexts").getReturn().getArrayElement()
or
result = browser().getMember("createIncognitoBrowserContext").getReturn().getPromised()
or

View File

@@ -221,7 +221,10 @@ private module Postgres {
/** Gets a value that is plugged into a raw placeholder variable, making it a sink for SQL injection. */
private DataFlow::Node getARawValue() {
result = this.getValues() and this.getARawParameterName() = "1" // Special case: if the argument is not an array or object, it's just plugged into $1
result = this.getValues() and
this.getARawParameterName() = "1" and // Special case: if the argument is not an array or object, it's just plugged into $1
not result instanceof DataFlow::ArrayCreationNode and
not result instanceof DataFlow::ObjectLiteralNode
or
exists(DataFlow::SourceNode values | values = this.getValues().getALocalSource() |
result = values.getAPropertyWrite(this.getARawParameterName()).getRhs()

View File

@@ -1,26 +0,0 @@
/**
* Provides classes and predicates modeling the Tanstack/react-query library.
*/
private import javascript
/**
* An additional flow step that propagates data from the return value of the query function,
* defined in a useQuery call from the '@tanstack/react-query' module, to the 'data' property.
*/
private class TanstackStep extends DataFlow::AdditionalFlowStep {
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
exists(API::CallNode useQuery |
useQuery = useQueryCall() and
node1 = useQuery.getParameter(0).getMember("queryFn").getReturn().getPromised().asSink() and
node2 = useQuery.getReturn().getMember("data").asSource()
)
}
}
/**
* Retrieves a call node representing a useQuery invocation from the '@tanstack/react-query' module.
*/
private API::CallNode useQueryCall() {
result = API::moduleImport("@tanstack/react-query").getMember("useQuery").getACall()
}

View File

@@ -421,3 +421,22 @@ private module ClosureLibraryUri {
}
}
}
private class QueryStringStringification extends DataFlow::SummarizedCallable {
QueryStringStringification() { this = "query-string stringification" }
override DataFlow::InvokeNode getACall() {
result =
API::moduleImport(["querystring", "query-string", "querystringify", "qs"])
.getMember("stringify")
.getACall() or
result = API::moduleImport("url-parse").getMember("qs").getMember("stringify").getACall() or
result = API::moduleImport("parseqs").getMember("encode").getACall()
}
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
preservesValue = false and
input = ["Argument[0]", "Argument[0].AnyMemberDeep"] and
output = "ReturnValue"
}
}

View File

@@ -104,8 +104,7 @@ module Vuex {
storeName = this.getNamespace() + localName
or
// mapGetters(['foo', 'bar'])
this.getLastParameter().getUnknownMember().getAValueReachingSink().getStringValue() =
localName and
this.getLastParameter().getArrayElement().getAValueReachingSink().getStringValue() = localName and
storeName = this.getNamespace() + localName
or
// mapGetters({foo: 'bar'})

View File

@@ -162,8 +162,8 @@ API::Node getExtraSuccessorFromNode(API::Node node, AccessPathTokenBase token) {
token.getName() = "Awaited" and
result = node.getPromised()
or
token.getName() = "ArrayElement" and
result = node.getMember(DataFlow::PseudoProperties::arrayElement())
token.getName() = ["ArrayElement", "Element"] and
result = node.getArrayElement()
or
token.getName() = "Element" and
result = node.getMember(DataFlow::PseudoProperties::arrayLikeElement())
@@ -172,11 +172,6 @@ API::Node getExtraSuccessorFromNode(API::Node node, AccessPathTokenBase token) {
token.getName() = "MapValue" and
result = node.getMember(DataFlow::PseudoProperties::mapValueAll())
or
// Currently we need to include the "unknown member" for ArrayElement and Element since
// API graphs do not use store/load steps for arrays
token.getName() = ["ArrayElement", "Element"] and
result = node.getUnknownMember()
or
token.getName() = "Parameter" and
token.getAnArgument() = "this" and
result = node.getReceiver()
@@ -373,7 +368,7 @@ bindingset[pred]
predicate apiGraphHasEdge(API::Node pred, string path, API::Node succ) {
exists(string name | succ = pred.getMember(name) and path = "Member[" + name + "]")
or
succ = pred.getUnknownMember() and path = "AnyMember"
succ = pred.getUnknownArrayElement() and path = "ArrayElement"
or
succ = pred.getInstance() and path = "Instance"
or

View File

@@ -297,13 +297,12 @@ module Stages {
exists(
API::moduleImport("foo")
.getMember("bar")
.getUnknownMember()
.getArrayElement()
.getAMember()
.getAParameter()
.getPromised()
.getReturn()
.getParameter(2)
.getUnknownMember()
.getInstance()
.getReceiver()
.getForwardingFunction()

View File

@@ -96,7 +96,8 @@ class ArrayConstructorSummary extends SummarizedCallable {
ArrayConstructorSummary() { this = "Array constructor" }
override DataFlow::InvokeNode getACallSimple() {
result = arrayConstructorRef().getAnInvocation()
result = arrayConstructorRef().getAnInvocation() and
result.getNumArgument() > 1
}
override predicate propagatesFlow(string input, string output, boolean preservesValue) {

View File

@@ -179,7 +179,6 @@ module ExternalApiUsedWithUntrustedData {
or
exists(string member |
node = base.getMember(member) and
not node = base.getUnknownMember() and
not isNumericString(member) and
not (member = "default" and base = API::moduleImport(_)) and
not member = "then" // use the 'promised' edges for .then callbacks
@@ -189,10 +188,7 @@ module ExternalApiUsedWithUntrustedData {
else result = basename + "['" + member.regexpReplaceAll("'", "\\'") + "']"
)
or
(
node = base.getUnknownMember() or
node = base.getMember(any(string s | isNumericString(s)))
) and
node = base.getArrayElement() and
result = basename + "[]"
or
// just collapse promises

View File

@@ -20,7 +20,11 @@ module ServerSideUrlRedirectConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
predicate isBarrier(DataFlow::Node node) {
node instanceof Sanitizer
or
node = HostnameSanitizerGuard::getABarrierNode()
}
predicate isBarrierOut(DataFlow::Node node) { hostnameSanitizingPrefixEdge(node, _) }
@@ -69,10 +73,12 @@ deprecated class Configuration extends TaintTracking::Configuration {
}
/**
* DEPRECATED. This is no longer used as a sanitizer guard.
*
* A call to a function called `isLocalUrl` or similar, which is
* considered to sanitize a variable for purposes of URL redirection.
*/
class LocalUrlSanitizingGuard extends DataFlow::CallNode {
deprecated class LocalUrlSanitizingGuard extends DataFlow::CallNode {
LocalUrlSanitizingGuard() { this.getCalleeName().regexpMatch("(?i)(is_?)?local_?url") }
/** DEPRECATED. Use `blocksExpr` instead. */

View File

@@ -892,7 +892,13 @@ module TaintedPath {
TaintTracking::uriStep(node1, node2)
or
exists(DataFlow::CallNode decode |
decode.getCalleeName() = "decodeURIComponent" or decode.getCalleeName() = "decodeURI"
decode =
DataFlow::globalVarRef([
"decodeURIComponent",
"decodeURI",
"escape",
"unescape"
]).getACall()
|
node1 = decode.getArgument(0) and
node2 = decode

View File

@@ -53,7 +53,7 @@ module Shared {
class UriEncodingSanitizer extends Sanitizer, DataFlow::CallNode {
UriEncodingSanitizer() {
exists(string name | this = DataFlow::globalVarRef(name).getACall() |
name = "encodeURI" or name = "encodeURIComponent"
name in ["encodeURI", "encodeURIComponent", "escape"]
)
}
}

View File

@@ -859,7 +859,10 @@ case @regexpterm.kind of
| 24 = @regexp_char_range
| 25 = @regexp_positive_lookbehind
| 26 = @regexp_negative_lookbehind
| 27 = @regexp_unicode_property_escape;
| 27 = @regexp_unicode_property_escape
| 28 = @regexp_quoted_string
| 29 = @regexp_intersection
| 30 = @regexp_subtraction;
regexp_parse_errors (unique int id: @regexp_parse_error,
int regexp: @regexpterm ref,

View File

@@ -1194,6 +1194,18 @@
<v>12</v>
</e>
<e>
<k>@regexp_quoted_string</k>
<v>12</v>
</e>
<e>
<k>@regexp_intersection</k>
<v>12</v>
</e>
<e>
<k>@regexp_subtraction</k>
<v>12</v>
</e>
<e>
<k>@regexp_parse_error</k>
<v>122</v>
</e>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Add support for quoted string, intersection and subtraction
compatibility: backwards

View File

@@ -4,14 +4,22 @@ private import codeql.util.test.InlineExpectationsTest
module Impl implements InlineExpectationsTestSig {
private import javascript
final private class LineCommentFinal = LineComment;
final class ExpectationComment = ExpectationCommentImpl;
class ExpectationComment extends LineCommentFinal {
string getContents() { result = this.getText() }
class Location = JS::Location;
abstract private class ExpectationCommentImpl extends Locatable {
abstract string getContents();
/** Gets this element's location. */
Location getLocation() { result = super.getLocation() }
}
class Location = JS::Location;
private class JSComment extends ExpectationCommentImpl instanceof Comment {
override string getContents() { result = super.getText() }
}
private class HtmlComment extends ExpectationCommentImpl instanceof HTML::CommentNode {
override string getContents() { result = super.getText() }
}
}

View File

@@ -0,0 +1,5 @@
---
category: fix
---
* Fixed a recently-introduced bug that caused `js/server-side-unvalidated-url-redirection` to ignore
valid hostname checks and report spurious alerts after such a check. The original behaviour has been restored.

View File

@@ -0,0 +1,7 @@
---
category: fix
---
* Fixed a bug that would in rare cases cause some regexp-based checks
to be seen as generic taint sanitisers, even though the underlying regexp
is not restrictive enough. The regexps are now analysed more precisely,
and unrestrictive regexp checks will no longer block taint flow.

View File

@@ -0,0 +1,6 @@
---
category: fix
---
* Fixed a bug, first introduced in `2.20.3`, that would prevent `v-html` attributes in Vue files
from being flagged by the `js/xss` query. The original behaviour has been restored and the `v-html`
attribute is once again functioning as a sink for the `js/xss` query.

View File

@@ -7,7 +7,7 @@ DataFlow::Node unverifiedDecode() {
verify
.getParameter(2)
.getMember("algorithms")
.getUnknownMember()
.getArrayElement()
.asSink()
.mayHaveStringValue("none") and
result = verify.getParameter(0).asSink()
@@ -32,7 +32,7 @@ DataFlow::Node verifiedDecode() {
not verify
.getParameter(2)
.getMember("algorithms")
.getUnknownMember()
.getArrayElement()
.asSink()
.mayHaveStringValue("none") or
not exists(verify.getParameter(2).getMember("algorithms"))

View File

@@ -72,7 +72,7 @@ module Execa {
override predicate isShellInterpreted(DataFlow::Node arg) {
// if shell: true then first and second args are sinks
// options can be third argument
arg = [this.getArgument(0), this.getParameter(1).getUnknownMember().asSink()] and
arg = [this.getArgument(0), this.getParameter(1).getArrayElement().asSink()] and
isExecaShellEnable(this.getParameter(2))
or
// options can be second argument

View File

@@ -4,7 +4,7 @@
* via default taint-tracking steps.
* @kind problem
* @problem.severity recommendation
* @tags meta
* @tags meta-expensive
* @id js/meta/alerts/tainted-nodes
* @precision very-low
*/

View File

@@ -0,0 +1,26 @@
import * as t from "testlib";
async function getData1() {
const data = await fetch("https://example.com/content");
return data.json(); /* def=moduleImport("testlib").getMember("exports").getMember("foo").getParameter(0).getReturn().getPromised() */
}
export function use1() {
t.foo(() => getData1());
}
async function getData2() {
const data = await fetch("https://example.com/content");
return data.json(); /* def=moduleImport("testlib").getMember("exports").getMember("foo").getParameter(0).getReturn().getPromised() */
}
export function use2() {
t.foo(getData2);
}
export function use3() {
t.foo(async () => {
const data = await fetch("https://example.com/content");
return data.json(); /* def=moduleImport("testlib").getMember("exports").getMember("foo").getParameter(0).getReturn().getPromised() */
});
}

View File

@@ -2,4 +2,4 @@ const MyStream = require('classes').MyStream;
var s = new MyStream();
for (let m of ["write"])
s[m]("Hello, world!"); /* use=moduleImport("classes").getMember("exports").getMember("MyStream").getInstance().getUnknownMember() */
s[m]("Hello, world!"); /* use=moduleImport("classes").getMember("exports").getMember("MyStream").getInstance().getArrayElement() */

View File

@@ -0,0 +1,66 @@
nodes
| tst.js:1:1:1:44 | [RegExpLiteral] /[[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]]/v | semmle.label | [RegExpLiteral] /[[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]]/v |
| tst.js:1:1:1:45 | [ExprStmt] /[[[ab1 ... a}]]/v; | semmle.label | [ExprStmt] /[[[ab1 ... a}]]/v; |
| tst.js:1:1:1:45 | [ExprStmt] /[[[ab1 ... a}]]/v; | semmle.order | 1 |
| tst.js:1:2:1:42 | [RegExpCharacterClass] [[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]] | semmle.label | [RegExpCharacterClass] [[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]] |
| tst.js:1:2:1:42 | [RegExpSubtraction] [[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]] | semmle.label | [RegExpSubtraction] [[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]] |
| tst.js:1:3:1:15 | [RegExpCharacterClass] [[ab1]&&[b1]] | semmle.label | [RegExpCharacterClass] [[ab1]&&[b1]] |
| tst.js:1:3:1:15 | [RegExpIntersection] [[ab1]&&[b1]] | semmle.label | [RegExpIntersection] [[ab1]&&[b1]] |
| tst.js:1:4:1:8 | [RegExpCharacterClass] [ab1] | semmle.label | [RegExpCharacterClass] [ab1] |
| tst.js:1:5:1:5 | [RegExpNormalConstant] a | semmle.label | [RegExpNormalConstant] a |
| tst.js:1:6:1:6 | [RegExpNormalConstant] b | semmle.label | [RegExpNormalConstant] b |
| tst.js:1:7:1:7 | [RegExpNormalConstant] 1 | semmle.label | [RegExpNormalConstant] 1 |
| tst.js:1:11:1:14 | [RegExpCharacterClass] [b1] | semmle.label | [RegExpCharacterClass] [b1] |
| tst.js:1:12:1:12 | [RegExpNormalConstant] b | semmle.label | [RegExpNormalConstant] b |
| tst.js:1:13:1:13 | [RegExpNormalConstant] 1 | semmle.label | [RegExpNormalConstant] 1 |
| tst.js:1:18:1:20 | [RegExpCharacterClass] [a] | semmle.label | [RegExpCharacterClass] [a] |
| tst.js:1:19:1:19 | [RegExpNormalConstant] a | semmle.label | [RegExpNormalConstant] a |
| tst.js:1:23:1:41 | [RegExpCharacterClass] [\\p{Number}\\q{z\|a}] | semmle.label | [RegExpCharacterClass] [\\p{Number}\\q{z\|a}] |
| tst.js:1:24:1:33 | [RegExpUnicodePropertyEscape] \\p{Number} | semmle.label | [RegExpUnicodePropertyEscape] \\p{Number} |
| tst.js:1:34:1:40 | [RegExpQuotedString] \\q{z\|a} | semmle.label | [RegExpQuotedString] \\q{z\|a} |
| tst.js:1:37:1:37 | [RegExpNormalConstant] z | semmle.label | [RegExpNormalConstant] z |
| tst.js:1:37:1:39 | [RegExpAlt] z\|a | semmle.label | [RegExpAlt] z\|a |
| tst.js:1:39:1:39 | [RegExpNormalConstant] a | semmle.label | [RegExpNormalConstant] a |
edges
| tst.js:1:1:1:44 | [RegExpLiteral] /[[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]]/v | tst.js:1:2:1:42 | [RegExpCharacterClass] [[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]] | semmle.label | 0 |
| tst.js:1:1:1:44 | [RegExpLiteral] /[[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]]/v | tst.js:1:2:1:42 | [RegExpCharacterClass] [[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]] | semmle.order | 0 |
| tst.js:1:1:1:45 | [ExprStmt] /[[[ab1 ... a}]]/v; | tst.js:1:1:1:44 | [RegExpLiteral] /[[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]]/v | semmle.label | 1 |
| tst.js:1:1:1:45 | [ExprStmt] /[[[ab1 ... a}]]/v; | tst.js:1:1:1:44 | [RegExpLiteral] /[[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]]/v | semmle.order | 1 |
| tst.js:1:2:1:42 | [RegExpCharacterClass] [[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]] | tst.js:1:2:1:42 | [RegExpSubtraction] [[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]] | semmle.label | 0 |
| tst.js:1:2:1:42 | [RegExpCharacterClass] [[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]] | tst.js:1:2:1:42 | [RegExpSubtraction] [[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]] | semmle.order | 0 |
| tst.js:1:2:1:42 | [RegExpSubtraction] [[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]] | tst.js:1:3:1:15 | [RegExpCharacterClass] [[ab1]&&[b1]] | semmle.label | 0 |
| tst.js:1:2:1:42 | [RegExpSubtraction] [[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]] | tst.js:1:3:1:15 | [RegExpCharacterClass] [[ab1]&&[b1]] | semmle.order | 0 |
| tst.js:1:2:1:42 | [RegExpSubtraction] [[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]] | tst.js:1:18:1:20 | [RegExpCharacterClass] [a] | semmle.label | 1 |
| tst.js:1:2:1:42 | [RegExpSubtraction] [[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]] | tst.js:1:18:1:20 | [RegExpCharacterClass] [a] | semmle.order | 1 |
| tst.js:1:2:1:42 | [RegExpSubtraction] [[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]] | tst.js:1:23:1:41 | [RegExpCharacterClass] [\\p{Number}\\q{z\|a}] | semmle.label | 2 |
| tst.js:1:2:1:42 | [RegExpSubtraction] [[[ab1]&&[b1]]--[a]--[\\p{Number}\\q{z\|a}]] | tst.js:1:23:1:41 | [RegExpCharacterClass] [\\p{Number}\\q{z\|a}] | semmle.order | 2 |
| tst.js:1:3:1:15 | [RegExpCharacterClass] [[ab1]&&[b1]] | tst.js:1:3:1:15 | [RegExpIntersection] [[ab1]&&[b1]] | semmle.label | 0 |
| tst.js:1:3:1:15 | [RegExpCharacterClass] [[ab1]&&[b1]] | tst.js:1:3:1:15 | [RegExpIntersection] [[ab1]&&[b1]] | semmle.order | 0 |
| tst.js:1:3:1:15 | [RegExpIntersection] [[ab1]&&[b1]] | tst.js:1:4:1:8 | [RegExpCharacterClass] [ab1] | semmle.label | 0 |
| tst.js:1:3:1:15 | [RegExpIntersection] [[ab1]&&[b1]] | tst.js:1:4:1:8 | [RegExpCharacterClass] [ab1] | semmle.order | 0 |
| tst.js:1:3:1:15 | [RegExpIntersection] [[ab1]&&[b1]] | tst.js:1:11:1:14 | [RegExpCharacterClass] [b1] | semmle.label | 1 |
| tst.js:1:3:1:15 | [RegExpIntersection] [[ab1]&&[b1]] | tst.js:1:11:1:14 | [RegExpCharacterClass] [b1] | semmle.order | 1 |
| tst.js:1:4:1:8 | [RegExpCharacterClass] [ab1] | tst.js:1:5:1:5 | [RegExpNormalConstant] a | semmle.label | 0 |
| tst.js:1:4:1:8 | [RegExpCharacterClass] [ab1] | tst.js:1:5:1:5 | [RegExpNormalConstant] a | semmle.order | 0 |
| tst.js:1:4:1:8 | [RegExpCharacterClass] [ab1] | tst.js:1:6:1:6 | [RegExpNormalConstant] b | semmle.label | 1 |
| tst.js:1:4:1:8 | [RegExpCharacterClass] [ab1] | tst.js:1:6:1:6 | [RegExpNormalConstant] b | semmle.order | 1 |
| tst.js:1:4:1:8 | [RegExpCharacterClass] [ab1] | tst.js:1:7:1:7 | [RegExpNormalConstant] 1 | semmle.label | 2 |
| tst.js:1:4:1:8 | [RegExpCharacterClass] [ab1] | tst.js:1:7:1:7 | [RegExpNormalConstant] 1 | semmle.order | 2 |
| tst.js:1:11:1:14 | [RegExpCharacterClass] [b1] | tst.js:1:12:1:12 | [RegExpNormalConstant] b | semmle.label | 0 |
| tst.js:1:11:1:14 | [RegExpCharacterClass] [b1] | tst.js:1:12:1:12 | [RegExpNormalConstant] b | semmle.order | 0 |
| tst.js:1:11:1:14 | [RegExpCharacterClass] [b1] | tst.js:1:13:1:13 | [RegExpNormalConstant] 1 | semmle.label | 1 |
| tst.js:1:11:1:14 | [RegExpCharacterClass] [b1] | tst.js:1:13:1:13 | [RegExpNormalConstant] 1 | semmle.order | 1 |
| tst.js:1:18:1:20 | [RegExpCharacterClass] [a] | tst.js:1:19:1:19 | [RegExpNormalConstant] a | semmle.label | 0 |
| tst.js:1:18:1:20 | [RegExpCharacterClass] [a] | tst.js:1:19:1:19 | [RegExpNormalConstant] a | semmle.order | 0 |
| tst.js:1:23:1:41 | [RegExpCharacterClass] [\\p{Number}\\q{z\|a}] | tst.js:1:24:1:33 | [RegExpUnicodePropertyEscape] \\p{Number} | semmle.label | 0 |
| tst.js:1:23:1:41 | [RegExpCharacterClass] [\\p{Number}\\q{z\|a}] | tst.js:1:24:1:33 | [RegExpUnicodePropertyEscape] \\p{Number} | semmle.order | 0 |
| tst.js:1:23:1:41 | [RegExpCharacterClass] [\\p{Number}\\q{z\|a}] | tst.js:1:34:1:40 | [RegExpQuotedString] \\q{z\|a} | semmle.label | 1 |
| tst.js:1:23:1:41 | [RegExpCharacterClass] [\\p{Number}\\q{z\|a}] | tst.js:1:34:1:40 | [RegExpQuotedString] \\q{z\|a} | semmle.order | 1 |
| tst.js:1:34:1:40 | [RegExpQuotedString] \\q{z\|a} | tst.js:1:37:1:39 | [RegExpAlt] z\|a | semmle.label | 0 |
| tst.js:1:34:1:40 | [RegExpQuotedString] \\q{z\|a} | tst.js:1:37:1:39 | [RegExpAlt] z\|a | semmle.order | 0 |
| tst.js:1:37:1:39 | [RegExpAlt] z\|a | tst.js:1:37:1:37 | [RegExpNormalConstant] z | semmle.label | 0 |
| tst.js:1:37:1:39 | [RegExpAlt] z\|a | tst.js:1:37:1:37 | [RegExpNormalConstant] z | semmle.order | 0 |
| tst.js:1:37:1:39 | [RegExpAlt] z\|a | tst.js:1:39:1:39 | [RegExpNormalConstant] a | semmle.label | 1 |
| tst.js:1:37:1:39 | [RegExpAlt] z\|a | tst.js:1:39:1:39 | [RegExpNormalConstant] a | semmle.order | 1 |
graphProperties
| semmle.graphKind | tree |

View File

@@ -0,0 +1 @@
import semmle.javascript.PrintAst

View File

@@ -0,0 +1 @@
/[[[ab1]&&[b1]]--[a]--[\p{Number}\q{z|a}]]/v;

View File

@@ -0,0 +1,91 @@
nodes
| tst.js:1:1:1:23 | [RegExpLiteral] /[[abc]&&[bcd]&&[cd]]/v | semmle.label | [RegExpLiteral] /[[abc]&&[bcd]&&[cd]]/v |
| tst.js:1:1:1:24 | [ExprStmt] /[[abc] ... cd]]/v; | semmle.label | [ExprStmt] /[[abc] ... cd]]/v; |
| tst.js:1:1:1:24 | [ExprStmt] /[[abc] ... cd]]/v; | semmle.order | 1 |
| tst.js:1:2:1:21 | [RegExpCharacterClass] [[abc]&&[bcd]&&[cd]] | semmle.label | [RegExpCharacterClass] [[abc]&&[bcd]&&[cd]] |
| tst.js:1:2:1:21 | [RegExpIntersection] [[abc]&&[bcd]&&[cd]] | semmle.label | [RegExpIntersection] [[abc]&&[bcd]&&[cd]] |
| tst.js:1:3:1:7 | [RegExpCharacterClass] [abc] | semmle.label | [RegExpCharacterClass] [abc] |
| tst.js:1:4:1:4 | [RegExpNormalConstant] a | semmle.label | [RegExpNormalConstant] a |
| tst.js:1:5:1:5 | [RegExpNormalConstant] b | semmle.label | [RegExpNormalConstant] b |
| tst.js:1:6:1:6 | [RegExpNormalConstant] c | semmle.label | [RegExpNormalConstant] c |
| tst.js:1:10:1:14 | [RegExpCharacterClass] [bcd] | semmle.label | [RegExpCharacterClass] [bcd] |
| tst.js:1:11:1:11 | [RegExpNormalConstant] b | semmle.label | [RegExpNormalConstant] b |
| tst.js:1:12:1:12 | [RegExpNormalConstant] c | semmle.label | [RegExpNormalConstant] c |
| tst.js:1:13:1:13 | [RegExpNormalConstant] d | semmle.label | [RegExpNormalConstant] d |
| tst.js:1:17:1:20 | [RegExpCharacterClass] [cd] | semmle.label | [RegExpCharacterClass] [cd] |
| tst.js:1:18:1:18 | [RegExpNormalConstant] c | semmle.label | [RegExpNormalConstant] c |
| tst.js:1:19:1:19 | [RegExpNormalConstant] d | semmle.label | [RegExpNormalConstant] d |
| tst.js:2:1:2:11 | [RegExpLiteral] /abc&&bcd/v | semmle.label | [RegExpLiteral] /abc&&bcd/v |
| tst.js:2:1:2:12 | [ExprStmt] /abc&&bcd/v; | semmle.label | [ExprStmt] /abc&&bcd/v; |
| tst.js:2:1:2:12 | [ExprStmt] /abc&&bcd/v; | semmle.order | 2 |
| tst.js:2:2:2:9 | [RegExpNormalConstant] abc&&bcd | semmle.label | [RegExpNormalConstant] abc&&bcd |
| tst.js:3:1:3:15 | [RegExpLiteral] /[abc]&&[bcd]/v | semmle.label | [RegExpLiteral] /[abc]&&[bcd]/v |
| tst.js:3:1:3:16 | [ExprStmt] /[abc]&&[bcd]/v; | semmle.label | [ExprStmt] /[abc]&&[bcd]/v; |
| tst.js:3:1:3:16 | [ExprStmt] /[abc]&&[bcd]/v; | semmle.order | 3 |
| tst.js:3:2:3:6 | [RegExpCharacterClass] [abc] | semmle.label | [RegExpCharacterClass] [abc] |
| tst.js:3:2:3:13 | [RegExpSequence] [abc]&&[bcd] | semmle.label | [RegExpSequence] [abc]&&[bcd] |
| tst.js:3:3:3:3 | [RegExpNormalConstant] a | semmle.label | [RegExpNormalConstant] a |
| tst.js:3:4:3:4 | [RegExpNormalConstant] b | semmle.label | [RegExpNormalConstant] b |
| tst.js:3:5:3:5 | [RegExpNormalConstant] c | semmle.label | [RegExpNormalConstant] c |
| tst.js:3:7:3:8 | [RegExpNormalConstant] && | semmle.label | [RegExpNormalConstant] && |
| tst.js:3:9:3:13 | [RegExpCharacterClass] [bcd] | semmle.label | [RegExpCharacterClass] [bcd] |
| tst.js:3:10:3:10 | [RegExpNormalConstant] b | semmle.label | [RegExpNormalConstant] b |
| tst.js:3:11:3:11 | [RegExpNormalConstant] c | semmle.label | [RegExpNormalConstant] c |
| tst.js:3:12:3:12 | [RegExpNormalConstant] d | semmle.label | [RegExpNormalConstant] d |
edges
| tst.js:1:1:1:23 | [RegExpLiteral] /[[abc]&&[bcd]&&[cd]]/v | tst.js:1:2:1:21 | [RegExpCharacterClass] [[abc]&&[bcd]&&[cd]] | semmle.label | 0 |
| tst.js:1:1:1:23 | [RegExpLiteral] /[[abc]&&[bcd]&&[cd]]/v | tst.js:1:2:1:21 | [RegExpCharacterClass] [[abc]&&[bcd]&&[cd]] | semmle.order | 0 |
| tst.js:1:1:1:24 | [ExprStmt] /[[abc] ... cd]]/v; | tst.js:1:1:1:23 | [RegExpLiteral] /[[abc]&&[bcd]&&[cd]]/v | semmle.label | 1 |
| tst.js:1:1:1:24 | [ExprStmt] /[[abc] ... cd]]/v; | tst.js:1:1:1:23 | [RegExpLiteral] /[[abc]&&[bcd]&&[cd]]/v | semmle.order | 1 |
| tst.js:1:2:1:21 | [RegExpCharacterClass] [[abc]&&[bcd]&&[cd]] | tst.js:1:2:1:21 | [RegExpIntersection] [[abc]&&[bcd]&&[cd]] | semmle.label | 0 |
| tst.js:1:2:1:21 | [RegExpCharacterClass] [[abc]&&[bcd]&&[cd]] | tst.js:1:2:1:21 | [RegExpIntersection] [[abc]&&[bcd]&&[cd]] | semmle.order | 0 |
| tst.js:1:2:1:21 | [RegExpIntersection] [[abc]&&[bcd]&&[cd]] | tst.js:1:3:1:7 | [RegExpCharacterClass] [abc] | semmle.label | 0 |
| tst.js:1:2:1:21 | [RegExpIntersection] [[abc]&&[bcd]&&[cd]] | tst.js:1:3:1:7 | [RegExpCharacterClass] [abc] | semmle.order | 0 |
| tst.js:1:2:1:21 | [RegExpIntersection] [[abc]&&[bcd]&&[cd]] | tst.js:1:10:1:14 | [RegExpCharacterClass] [bcd] | semmle.label | 1 |
| tst.js:1:2:1:21 | [RegExpIntersection] [[abc]&&[bcd]&&[cd]] | tst.js:1:10:1:14 | [RegExpCharacterClass] [bcd] | semmle.order | 1 |
| tst.js:1:2:1:21 | [RegExpIntersection] [[abc]&&[bcd]&&[cd]] | tst.js:1:17:1:20 | [RegExpCharacterClass] [cd] | semmle.label | 2 |
| tst.js:1:2:1:21 | [RegExpIntersection] [[abc]&&[bcd]&&[cd]] | tst.js:1:17:1:20 | [RegExpCharacterClass] [cd] | semmle.order | 2 |
| tst.js:1:3:1:7 | [RegExpCharacterClass] [abc] | tst.js:1:4:1:4 | [RegExpNormalConstant] a | semmle.label | 0 |
| tst.js:1:3:1:7 | [RegExpCharacterClass] [abc] | tst.js:1:4:1:4 | [RegExpNormalConstant] a | semmle.order | 0 |
| tst.js:1:3:1:7 | [RegExpCharacterClass] [abc] | tst.js:1:5:1:5 | [RegExpNormalConstant] b | semmle.label | 1 |
| tst.js:1:3:1:7 | [RegExpCharacterClass] [abc] | tst.js:1:5:1:5 | [RegExpNormalConstant] b | semmle.order | 1 |
| tst.js:1:3:1:7 | [RegExpCharacterClass] [abc] | tst.js:1:6:1:6 | [RegExpNormalConstant] c | semmle.label | 2 |
| tst.js:1:3:1:7 | [RegExpCharacterClass] [abc] | tst.js:1:6:1:6 | [RegExpNormalConstant] c | semmle.order | 2 |
| tst.js:1:10:1:14 | [RegExpCharacterClass] [bcd] | tst.js:1:11:1:11 | [RegExpNormalConstant] b | semmle.label | 0 |
| tst.js:1:10:1:14 | [RegExpCharacterClass] [bcd] | tst.js:1:11:1:11 | [RegExpNormalConstant] b | semmle.order | 0 |
| tst.js:1:10:1:14 | [RegExpCharacterClass] [bcd] | tst.js:1:12:1:12 | [RegExpNormalConstant] c | semmle.label | 1 |
| tst.js:1:10:1:14 | [RegExpCharacterClass] [bcd] | tst.js:1:12:1:12 | [RegExpNormalConstant] c | semmle.order | 1 |
| tst.js:1:10:1:14 | [RegExpCharacterClass] [bcd] | tst.js:1:13:1:13 | [RegExpNormalConstant] d | semmle.label | 2 |
| tst.js:1:10:1:14 | [RegExpCharacterClass] [bcd] | tst.js:1:13:1:13 | [RegExpNormalConstant] d | semmle.order | 2 |
| tst.js:1:17:1:20 | [RegExpCharacterClass] [cd] | tst.js:1:18:1:18 | [RegExpNormalConstant] c | semmle.label | 0 |
| tst.js:1:17:1:20 | [RegExpCharacterClass] [cd] | tst.js:1:18:1:18 | [RegExpNormalConstant] c | semmle.order | 0 |
| tst.js:1:17:1:20 | [RegExpCharacterClass] [cd] | tst.js:1:19:1:19 | [RegExpNormalConstant] d | semmle.label | 1 |
| tst.js:1:17:1:20 | [RegExpCharacterClass] [cd] | tst.js:1:19:1:19 | [RegExpNormalConstant] d | semmle.order | 1 |
| tst.js:2:1:2:11 | [RegExpLiteral] /abc&&bcd/v | tst.js:2:2:2:9 | [RegExpNormalConstant] abc&&bcd | semmle.label | 0 |
| tst.js:2:1:2:11 | [RegExpLiteral] /abc&&bcd/v | tst.js:2:2:2:9 | [RegExpNormalConstant] abc&&bcd | semmle.order | 0 |
| tst.js:2:1:2:12 | [ExprStmt] /abc&&bcd/v; | tst.js:2:1:2:11 | [RegExpLiteral] /abc&&bcd/v | semmle.label | 1 |
| tst.js:2:1:2:12 | [ExprStmt] /abc&&bcd/v; | tst.js:2:1:2:11 | [RegExpLiteral] /abc&&bcd/v | semmle.order | 1 |
| tst.js:3:1:3:15 | [RegExpLiteral] /[abc]&&[bcd]/v | tst.js:3:2:3:13 | [RegExpSequence] [abc]&&[bcd] | semmle.label | 0 |
| tst.js:3:1:3:15 | [RegExpLiteral] /[abc]&&[bcd]/v | tst.js:3:2:3:13 | [RegExpSequence] [abc]&&[bcd] | semmle.order | 0 |
| tst.js:3:1:3:16 | [ExprStmt] /[abc]&&[bcd]/v; | tst.js:3:1:3:15 | [RegExpLiteral] /[abc]&&[bcd]/v | semmle.label | 1 |
| tst.js:3:1:3:16 | [ExprStmt] /[abc]&&[bcd]/v; | tst.js:3:1:3:15 | [RegExpLiteral] /[abc]&&[bcd]/v | semmle.order | 1 |
| tst.js:3:2:3:6 | [RegExpCharacterClass] [abc] | tst.js:3:3:3:3 | [RegExpNormalConstant] a | semmle.label | 0 |
| tst.js:3:2:3:6 | [RegExpCharacterClass] [abc] | tst.js:3:3:3:3 | [RegExpNormalConstant] a | semmle.order | 0 |
| tst.js:3:2:3:6 | [RegExpCharacterClass] [abc] | tst.js:3:4:3:4 | [RegExpNormalConstant] b | semmle.label | 1 |
| tst.js:3:2:3:6 | [RegExpCharacterClass] [abc] | tst.js:3:4:3:4 | [RegExpNormalConstant] b | semmle.order | 1 |
| tst.js:3:2:3:6 | [RegExpCharacterClass] [abc] | tst.js:3:5:3:5 | [RegExpNormalConstant] c | semmle.label | 2 |
| tst.js:3:2:3:6 | [RegExpCharacterClass] [abc] | tst.js:3:5:3:5 | [RegExpNormalConstant] c | semmle.order | 2 |
| tst.js:3:2:3:13 | [RegExpSequence] [abc]&&[bcd] | tst.js:3:2:3:6 | [RegExpCharacterClass] [abc] | semmle.label | 0 |
| tst.js:3:2:3:13 | [RegExpSequence] [abc]&&[bcd] | tst.js:3:2:3:6 | [RegExpCharacterClass] [abc] | semmle.order | 0 |
| tst.js:3:2:3:13 | [RegExpSequence] [abc]&&[bcd] | tst.js:3:7:3:8 | [RegExpNormalConstant] && | semmle.label | 1 |
| tst.js:3:2:3:13 | [RegExpSequence] [abc]&&[bcd] | tst.js:3:7:3:8 | [RegExpNormalConstant] && | semmle.order | 1 |
| tst.js:3:2:3:13 | [RegExpSequence] [abc]&&[bcd] | tst.js:3:9:3:13 | [RegExpCharacterClass] [bcd] | semmle.label | 2 |
| tst.js:3:2:3:13 | [RegExpSequence] [abc]&&[bcd] | tst.js:3:9:3:13 | [RegExpCharacterClass] [bcd] | semmle.order | 2 |
| tst.js:3:9:3:13 | [RegExpCharacterClass] [bcd] | tst.js:3:10:3:10 | [RegExpNormalConstant] b | semmle.label | 0 |
| tst.js:3:9:3:13 | [RegExpCharacterClass] [bcd] | tst.js:3:10:3:10 | [RegExpNormalConstant] b | semmle.order | 0 |
| tst.js:3:9:3:13 | [RegExpCharacterClass] [bcd] | tst.js:3:11:3:11 | [RegExpNormalConstant] c | semmle.label | 1 |
| tst.js:3:9:3:13 | [RegExpCharacterClass] [bcd] | tst.js:3:11:3:11 | [RegExpNormalConstant] c | semmle.order | 1 |
| tst.js:3:9:3:13 | [RegExpCharacterClass] [bcd] | tst.js:3:12:3:12 | [RegExpNormalConstant] d | semmle.label | 2 |
| tst.js:3:9:3:13 | [RegExpCharacterClass] [bcd] | tst.js:3:12:3:12 | [RegExpNormalConstant] d | semmle.order | 2 |
graphProperties
| semmle.graphKind | tree |

View File

@@ -0,0 +1 @@
import semmle.javascript.PrintAst

View File

@@ -0,0 +1,6 @@
/[[abc]&&[bcd]&&[cd]]/v; // Valid use of intersection operator, matches b or c
/abc&&bcd/v; //Valid regex, but no intersection operation: Matches the literal string "abc&&bcd"
/[abc]&&[bcd]/v; // Valid regex, but incorrect intersection operation:
// - Matches a single character from [abc]
// - Then the literal "&&"
// - Then a single character from [bcd]

View File

@@ -0,0 +1,121 @@
nodes
| tst.js:1:1:1:12 | [RegExpLiteral] /[\\q{abc}]/v | semmle.label | [RegExpLiteral] /[\\q{abc}]/v |
| tst.js:1:1:1:13 | [ExprStmt] /[\\q{abc}]/v; | semmle.label | [ExprStmt] /[\\q{abc}]/v; |
| tst.js:1:1:1:13 | [ExprStmt] /[\\q{abc}]/v; | semmle.order | 1 |
| tst.js:1:2:1:10 | [RegExpCharacterClass] [\\q{abc}] | semmle.label | [RegExpCharacterClass] [\\q{abc}] |
| tst.js:1:3:1:9 | [RegExpQuotedString] \\q{abc} | semmle.label | [RegExpQuotedString] \\q{abc} |
| tst.js:1:6:1:8 | [RegExpNormalConstant] abc | semmle.label | [RegExpNormalConstant] abc |
| tst.js:2:1:2:20 | [RegExpLiteral] /[\\q{abc\|cbd\|dcb}]/v | semmle.label | [RegExpLiteral] /[\\q{abc\|cbd\|dcb}]/v |
| tst.js:2:1:2:21 | [ExprStmt] /[\\q{ab ... cb}]/v; | semmle.label | [ExprStmt] /[\\q{ab ... cb}]/v; |
| tst.js:2:1:2:21 | [ExprStmt] /[\\q{ab ... cb}]/v; | semmle.order | 2 |
| tst.js:2:2:2:18 | [RegExpCharacterClass] [\\q{abc\|cbd\|dcb}] | semmle.label | [RegExpCharacterClass] [\\q{abc\|cbd\|dcb}] |
| tst.js:2:3:2:17 | [RegExpQuotedString] \\q{abc\|cbd\|dcb} | semmle.label | [RegExpQuotedString] \\q{abc\|cbd\|dcb} |
| tst.js:2:6:2:8 | [RegExpNormalConstant] abc | semmle.label | [RegExpNormalConstant] abc |
| tst.js:2:6:2:16 | [RegExpAlt] abc\|cbd\|dcb | semmle.label | [RegExpAlt] abc\|cbd\|dcb |
| tst.js:2:10:2:12 | [RegExpNormalConstant] cbd | semmle.label | [RegExpNormalConstant] cbd |
| tst.js:2:14:2:16 | [RegExpNormalConstant] dcb | semmle.label | [RegExpNormalConstant] dcb |
| tst.js:3:1:3:11 | [RegExpLiteral] /[\\q{\\}}]/v | semmle.label | [RegExpLiteral] /[\\q{\\}}]/v |
| tst.js:3:1:3:12 | [ExprStmt] /[\\q{\\}}]/v; | semmle.label | [ExprStmt] /[\\q{\\}}]/v; |
| tst.js:3:1:3:12 | [ExprStmt] /[\\q{\\}}]/v; | semmle.order | 3 |
| tst.js:3:2:3:9 | [RegExpCharacterClass] [\\q{\\}}] | semmle.label | [RegExpCharacterClass] [\\q{\\}}] |
| tst.js:3:3:3:8 | [RegExpQuotedString] \\q{\\}} | semmle.label | [RegExpQuotedString] \\q{\\}} |
| tst.js:3:6:3:7 | [RegExpNormalConstant] \\} | semmle.label | [RegExpNormalConstant] \\} |
| tst.js:4:1:4:11 | [RegExpLiteral] /[\\q{\\{}]/v | semmle.label | [RegExpLiteral] /[\\q{\\{}]/v |
| tst.js:4:1:4:12 | [ExprStmt] /[\\q{\\{}]/v; | semmle.label | [ExprStmt] /[\\q{\\{}]/v; |
| tst.js:4:1:4:12 | [ExprStmt] /[\\q{\\{}]/v; | semmle.order | 4 |
| tst.js:4:2:4:9 | [RegExpCharacterClass] [\\q{\\{}] | semmle.label | [RegExpCharacterClass] [\\q{\\{}] |
| tst.js:4:3:4:8 | [RegExpQuotedString] \\q{\\{} | semmle.label | [RegExpQuotedString] \\q{\\{} |
| tst.js:4:6:4:7 | [RegExpNormalConstant] \\{ | semmle.label | [RegExpNormalConstant] \\{ |
| tst.js:5:1:5:18 | [RegExpLiteral] /[\\q{cc\|\\}a\|cc}]/v | semmle.label | [RegExpLiteral] /[\\q{cc\|\\}a\|cc}]/v |
| tst.js:5:1:5:19 | [ExprStmt] /[\\q{cc\|\\}a\|cc}]/v; | semmle.label | [ExprStmt] /[\\q{cc\|\\}a\|cc}]/v; |
| tst.js:5:1:5:19 | [ExprStmt] /[\\q{cc\|\\}a\|cc}]/v; | semmle.order | 5 |
| tst.js:5:2:5:16 | [RegExpCharacterClass] [\\q{cc\|\\}a\|cc}] | semmle.label | [RegExpCharacterClass] [\\q{cc\|\\}a\|cc}] |
| tst.js:5:3:5:15 | [RegExpQuotedString] \\q{cc\|\\}a\|cc} | semmle.label | [RegExpQuotedString] \\q{cc\|\\}a\|cc} |
| tst.js:5:6:5:7 | [RegExpNormalConstant] cc | semmle.label | [RegExpNormalConstant] cc |
| tst.js:5:6:5:14 | [RegExpAlt] cc\|\\}a\|cc | semmle.label | [RegExpAlt] cc\|\\}a\|cc |
| tst.js:5:9:5:11 | [RegExpNormalConstant] \\}a | semmle.label | [RegExpNormalConstant] \\}a |
| tst.js:5:13:5:14 | [RegExpNormalConstant] cc | semmle.label | [RegExpNormalConstant] cc |
| tst.js:6:1:6:12 | [RegExpLiteral] /[\\qq{a\|b}]/ | semmle.label | [RegExpLiteral] /[\\qq{a\|b}]/ |
| tst.js:6:1:6:13 | [ExprStmt] /[\\qq{a\|b}]/; | semmle.label | [ExprStmt] /[\\qq{a\|b}]/; |
| tst.js:6:1:6:13 | [ExprStmt] /[\\qq{a\|b}]/; | semmle.order | 6 |
| tst.js:6:2:6:11 | [RegExpCharacterClass] [\\qq{a\|b}] | semmle.label | [RegExpCharacterClass] [\\qq{a\|b}] |
| tst.js:6:3:6:4 | [RegExpIdentityEscape] \\q | semmle.label | [RegExpIdentityEscape] \\q |
| tst.js:6:5:6:5 | [RegExpNormalConstant] q | semmle.label | [RegExpNormalConstant] q |
| tst.js:6:6:6:6 | [RegExpNormalConstant] { | semmle.label | [RegExpNormalConstant] { |
| tst.js:6:7:6:7 | [RegExpNormalConstant] a | semmle.label | [RegExpNormalConstant] a |
| tst.js:6:8:6:8 | [RegExpNormalConstant] \| | semmle.label | [RegExpNormalConstant] \| |
| tst.js:6:9:6:9 | [RegExpNormalConstant] b | semmle.label | [RegExpNormalConstant] b |
| tst.js:6:10:6:10 | [RegExpNormalConstant] } | semmle.label | [RegExpNormalConstant] } |
edges
| tst.js:1:1:1:12 | [RegExpLiteral] /[\\q{abc}]/v | tst.js:1:2:1:10 | [RegExpCharacterClass] [\\q{abc}] | semmle.label | 0 |
| tst.js:1:1:1:12 | [RegExpLiteral] /[\\q{abc}]/v | tst.js:1:2:1:10 | [RegExpCharacterClass] [\\q{abc}] | semmle.order | 0 |
| tst.js:1:1:1:13 | [ExprStmt] /[\\q{abc}]/v; | tst.js:1:1:1:12 | [RegExpLiteral] /[\\q{abc}]/v | semmle.label | 1 |
| tst.js:1:1:1:13 | [ExprStmt] /[\\q{abc}]/v; | tst.js:1:1:1:12 | [RegExpLiteral] /[\\q{abc}]/v | semmle.order | 1 |
| tst.js:1:2:1:10 | [RegExpCharacterClass] [\\q{abc}] | tst.js:1:3:1:9 | [RegExpQuotedString] \\q{abc} | semmle.label | 0 |
| tst.js:1:2:1:10 | [RegExpCharacterClass] [\\q{abc}] | tst.js:1:3:1:9 | [RegExpQuotedString] \\q{abc} | semmle.order | 0 |
| tst.js:1:3:1:9 | [RegExpQuotedString] \\q{abc} | tst.js:1:6:1:8 | [RegExpNormalConstant] abc | semmle.label | 0 |
| tst.js:1:3:1:9 | [RegExpQuotedString] \\q{abc} | tst.js:1:6:1:8 | [RegExpNormalConstant] abc | semmle.order | 0 |
| tst.js:2:1:2:20 | [RegExpLiteral] /[\\q{abc\|cbd\|dcb}]/v | tst.js:2:2:2:18 | [RegExpCharacterClass] [\\q{abc\|cbd\|dcb}] | semmle.label | 0 |
| tst.js:2:1:2:20 | [RegExpLiteral] /[\\q{abc\|cbd\|dcb}]/v | tst.js:2:2:2:18 | [RegExpCharacterClass] [\\q{abc\|cbd\|dcb}] | semmle.order | 0 |
| tst.js:2:1:2:21 | [ExprStmt] /[\\q{ab ... cb}]/v; | tst.js:2:1:2:20 | [RegExpLiteral] /[\\q{abc\|cbd\|dcb}]/v | semmle.label | 1 |
| tst.js:2:1:2:21 | [ExprStmt] /[\\q{ab ... cb}]/v; | tst.js:2:1:2:20 | [RegExpLiteral] /[\\q{abc\|cbd\|dcb}]/v | semmle.order | 1 |
| tst.js:2:2:2:18 | [RegExpCharacterClass] [\\q{abc\|cbd\|dcb}] | tst.js:2:3:2:17 | [RegExpQuotedString] \\q{abc\|cbd\|dcb} | semmle.label | 0 |
| tst.js:2:2:2:18 | [RegExpCharacterClass] [\\q{abc\|cbd\|dcb}] | tst.js:2:3:2:17 | [RegExpQuotedString] \\q{abc\|cbd\|dcb} | semmle.order | 0 |
| tst.js:2:3:2:17 | [RegExpQuotedString] \\q{abc\|cbd\|dcb} | tst.js:2:6:2:16 | [RegExpAlt] abc\|cbd\|dcb | semmle.label | 0 |
| tst.js:2:3:2:17 | [RegExpQuotedString] \\q{abc\|cbd\|dcb} | tst.js:2:6:2:16 | [RegExpAlt] abc\|cbd\|dcb | semmle.order | 0 |
| tst.js:2:6:2:16 | [RegExpAlt] abc\|cbd\|dcb | tst.js:2:6:2:8 | [RegExpNormalConstant] abc | semmle.label | 0 |
| tst.js:2:6:2:16 | [RegExpAlt] abc\|cbd\|dcb | tst.js:2:6:2:8 | [RegExpNormalConstant] abc | semmle.order | 0 |
| tst.js:2:6:2:16 | [RegExpAlt] abc\|cbd\|dcb | tst.js:2:10:2:12 | [RegExpNormalConstant] cbd | semmle.label | 1 |
| tst.js:2:6:2:16 | [RegExpAlt] abc\|cbd\|dcb | tst.js:2:10:2:12 | [RegExpNormalConstant] cbd | semmle.order | 1 |
| tst.js:2:6:2:16 | [RegExpAlt] abc\|cbd\|dcb | tst.js:2:14:2:16 | [RegExpNormalConstant] dcb | semmle.label | 2 |
| tst.js:2:6:2:16 | [RegExpAlt] abc\|cbd\|dcb | tst.js:2:14:2:16 | [RegExpNormalConstant] dcb | semmle.order | 2 |
| tst.js:3:1:3:11 | [RegExpLiteral] /[\\q{\\}}]/v | tst.js:3:2:3:9 | [RegExpCharacterClass] [\\q{\\}}] | semmle.label | 0 |
| tst.js:3:1:3:11 | [RegExpLiteral] /[\\q{\\}}]/v | tst.js:3:2:3:9 | [RegExpCharacterClass] [\\q{\\}}] | semmle.order | 0 |
| tst.js:3:1:3:12 | [ExprStmt] /[\\q{\\}}]/v; | tst.js:3:1:3:11 | [RegExpLiteral] /[\\q{\\}}]/v | semmle.label | 1 |
| tst.js:3:1:3:12 | [ExprStmt] /[\\q{\\}}]/v; | tst.js:3:1:3:11 | [RegExpLiteral] /[\\q{\\}}]/v | semmle.order | 1 |
| tst.js:3:2:3:9 | [RegExpCharacterClass] [\\q{\\}}] | tst.js:3:3:3:8 | [RegExpQuotedString] \\q{\\}} | semmle.label | 0 |
| tst.js:3:2:3:9 | [RegExpCharacterClass] [\\q{\\}}] | tst.js:3:3:3:8 | [RegExpQuotedString] \\q{\\}} | semmle.order | 0 |
| tst.js:3:3:3:8 | [RegExpQuotedString] \\q{\\}} | tst.js:3:6:3:7 | [RegExpNormalConstant] \\} | semmle.label | 0 |
| tst.js:3:3:3:8 | [RegExpQuotedString] \\q{\\}} | tst.js:3:6:3:7 | [RegExpNormalConstant] \\} | semmle.order | 0 |
| tst.js:4:1:4:11 | [RegExpLiteral] /[\\q{\\{}]/v | tst.js:4:2:4:9 | [RegExpCharacterClass] [\\q{\\{}] | semmle.label | 0 |
| tst.js:4:1:4:11 | [RegExpLiteral] /[\\q{\\{}]/v | tst.js:4:2:4:9 | [RegExpCharacterClass] [\\q{\\{}] | semmle.order | 0 |
| tst.js:4:1:4:12 | [ExprStmt] /[\\q{\\{}]/v; | tst.js:4:1:4:11 | [RegExpLiteral] /[\\q{\\{}]/v | semmle.label | 1 |
| tst.js:4:1:4:12 | [ExprStmt] /[\\q{\\{}]/v; | tst.js:4:1:4:11 | [RegExpLiteral] /[\\q{\\{}]/v | semmle.order | 1 |
| tst.js:4:2:4:9 | [RegExpCharacterClass] [\\q{\\{}] | tst.js:4:3:4:8 | [RegExpQuotedString] \\q{\\{} | semmle.label | 0 |
| tst.js:4:2:4:9 | [RegExpCharacterClass] [\\q{\\{}] | tst.js:4:3:4:8 | [RegExpQuotedString] \\q{\\{} | semmle.order | 0 |
| tst.js:4:3:4:8 | [RegExpQuotedString] \\q{\\{} | tst.js:4:6:4:7 | [RegExpNormalConstant] \\{ | semmle.label | 0 |
| tst.js:4:3:4:8 | [RegExpQuotedString] \\q{\\{} | tst.js:4:6:4:7 | [RegExpNormalConstant] \\{ | semmle.order | 0 |
| tst.js:5:1:5:18 | [RegExpLiteral] /[\\q{cc\|\\}a\|cc}]/v | tst.js:5:2:5:16 | [RegExpCharacterClass] [\\q{cc\|\\}a\|cc}] | semmle.label | 0 |
| tst.js:5:1:5:18 | [RegExpLiteral] /[\\q{cc\|\\}a\|cc}]/v | tst.js:5:2:5:16 | [RegExpCharacterClass] [\\q{cc\|\\}a\|cc}] | semmle.order | 0 |
| tst.js:5:1:5:19 | [ExprStmt] /[\\q{cc\|\\}a\|cc}]/v; | tst.js:5:1:5:18 | [RegExpLiteral] /[\\q{cc\|\\}a\|cc}]/v | semmle.label | 1 |
| tst.js:5:1:5:19 | [ExprStmt] /[\\q{cc\|\\}a\|cc}]/v; | tst.js:5:1:5:18 | [RegExpLiteral] /[\\q{cc\|\\}a\|cc}]/v | semmle.order | 1 |
| tst.js:5:2:5:16 | [RegExpCharacterClass] [\\q{cc\|\\}a\|cc}] | tst.js:5:3:5:15 | [RegExpQuotedString] \\q{cc\|\\}a\|cc} | semmle.label | 0 |
| tst.js:5:2:5:16 | [RegExpCharacterClass] [\\q{cc\|\\}a\|cc}] | tst.js:5:3:5:15 | [RegExpQuotedString] \\q{cc\|\\}a\|cc} | semmle.order | 0 |
| tst.js:5:3:5:15 | [RegExpQuotedString] \\q{cc\|\\}a\|cc} | tst.js:5:6:5:14 | [RegExpAlt] cc\|\\}a\|cc | semmle.label | 0 |
| tst.js:5:3:5:15 | [RegExpQuotedString] \\q{cc\|\\}a\|cc} | tst.js:5:6:5:14 | [RegExpAlt] cc\|\\}a\|cc | semmle.order | 0 |
| tst.js:5:6:5:14 | [RegExpAlt] cc\|\\}a\|cc | tst.js:5:6:5:7 | [RegExpNormalConstant] cc | semmle.label | 0 |
| tst.js:5:6:5:14 | [RegExpAlt] cc\|\\}a\|cc | tst.js:5:6:5:7 | [RegExpNormalConstant] cc | semmle.order | 0 |
| tst.js:5:6:5:14 | [RegExpAlt] cc\|\\}a\|cc | tst.js:5:9:5:11 | [RegExpNormalConstant] \\}a | semmle.label | 1 |
| tst.js:5:6:5:14 | [RegExpAlt] cc\|\\}a\|cc | tst.js:5:9:5:11 | [RegExpNormalConstant] \\}a | semmle.order | 1 |
| tst.js:5:6:5:14 | [RegExpAlt] cc\|\\}a\|cc | tst.js:5:13:5:14 | [RegExpNormalConstant] cc | semmle.label | 2 |
| tst.js:5:6:5:14 | [RegExpAlt] cc\|\\}a\|cc | tst.js:5:13:5:14 | [RegExpNormalConstant] cc | semmle.order | 2 |
| tst.js:6:1:6:12 | [RegExpLiteral] /[\\qq{a\|b}]/ | tst.js:6:2:6:11 | [RegExpCharacterClass] [\\qq{a\|b}] | semmle.label | 0 |
| tst.js:6:1:6:12 | [RegExpLiteral] /[\\qq{a\|b}]/ | tst.js:6:2:6:11 | [RegExpCharacterClass] [\\qq{a\|b}] | semmle.order | 0 |
| tst.js:6:1:6:13 | [ExprStmt] /[\\qq{a\|b}]/; | tst.js:6:1:6:12 | [RegExpLiteral] /[\\qq{a\|b}]/ | semmle.label | 1 |
| tst.js:6:1:6:13 | [ExprStmt] /[\\qq{a\|b}]/; | tst.js:6:1:6:12 | [RegExpLiteral] /[\\qq{a\|b}]/ | semmle.order | 1 |
| tst.js:6:2:6:11 | [RegExpCharacterClass] [\\qq{a\|b}] | tst.js:6:3:6:4 | [RegExpIdentityEscape] \\q | semmle.label | 0 |
| tst.js:6:2:6:11 | [RegExpCharacterClass] [\\qq{a\|b}] | tst.js:6:3:6:4 | [RegExpIdentityEscape] \\q | semmle.order | 0 |
| tst.js:6:2:6:11 | [RegExpCharacterClass] [\\qq{a\|b}] | tst.js:6:5:6:5 | [RegExpNormalConstant] q | semmle.label | 1 |
| tst.js:6:2:6:11 | [RegExpCharacterClass] [\\qq{a\|b}] | tst.js:6:5:6:5 | [RegExpNormalConstant] q | semmle.order | 1 |
| tst.js:6:2:6:11 | [RegExpCharacterClass] [\\qq{a\|b}] | tst.js:6:6:6:6 | [RegExpNormalConstant] { | semmle.label | 2 |
| tst.js:6:2:6:11 | [RegExpCharacterClass] [\\qq{a\|b}] | tst.js:6:6:6:6 | [RegExpNormalConstant] { | semmle.order | 2 |
| tst.js:6:2:6:11 | [RegExpCharacterClass] [\\qq{a\|b}] | tst.js:6:7:6:7 | [RegExpNormalConstant] a | semmle.label | 3 |
| tst.js:6:2:6:11 | [RegExpCharacterClass] [\\qq{a\|b}] | tst.js:6:7:6:7 | [RegExpNormalConstant] a | semmle.order | 3 |
| tst.js:6:2:6:11 | [RegExpCharacterClass] [\\qq{a\|b}] | tst.js:6:8:6:8 | [RegExpNormalConstant] \| | semmle.label | 4 |
| tst.js:6:2:6:11 | [RegExpCharacterClass] [\\qq{a\|b}] | tst.js:6:8:6:8 | [RegExpNormalConstant] \| | semmle.order | 4 |
| tst.js:6:2:6:11 | [RegExpCharacterClass] [\\qq{a\|b}] | tst.js:6:9:6:9 | [RegExpNormalConstant] b | semmle.label | 5 |
| tst.js:6:2:6:11 | [RegExpCharacterClass] [\\qq{a\|b}] | tst.js:6:9:6:9 | [RegExpNormalConstant] b | semmle.order | 5 |
| tst.js:6:2:6:11 | [RegExpCharacterClass] [\\qq{a\|b}] | tst.js:6:10:6:10 | [RegExpNormalConstant] } | semmle.label | 6 |
| tst.js:6:2:6:11 | [RegExpCharacterClass] [\\qq{a\|b}] | tst.js:6:10:6:10 | [RegExpNormalConstant] } | semmle.order | 6 |
graphProperties
| semmle.graphKind | tree |

View File

@@ -0,0 +1 @@
import semmle.javascript.PrintAst

View File

@@ -0,0 +1,6 @@
/[\q{abc}]/v;
/[\q{abc|cbd|dcb}]/v;
/[\q{\}}]/v;
/[\q{\{}]/v;
/[\q{cc|\}a|cc}]/v;
/[\qq{a|b}]/; // Since v flag is not present matches 'q{a|b}'

View File

@@ -0,0 +1,103 @@
nodes
| tst.js:1:1:1:44 | [RegExpLiteral] /[\\p{Script_Extensions=Greek}--\\p{Letter}]/v | semmle.label | [RegExpLiteral] /[\\p{Script_Extensions=Greek}--\\p{Letter}]/v |
| tst.js:1:1:1:45 | [ExprStmt] /[\\p{Sc ... er}]/v; | semmle.label | [ExprStmt] /[\\p{Sc ... er}]/v; |
| tst.js:1:1:1:45 | [ExprStmt] /[\\p{Sc ... er}]/v; | semmle.order | 1 |
| tst.js:1:2:1:42 | [RegExpCharacterClass] [\\p{Script_Extensions=Greek}--\\p{Letter}] | semmle.label | [RegExpCharacterClass] [\\p{Script_Extensions=Greek}--\\p{Letter}] |
| tst.js:1:2:1:42 | [RegExpSubtraction] [\\p{Script_Extensions=Greek}--\\p{Letter}] | semmle.label | [RegExpSubtraction] [\\p{Script_Extensions=Greek}--\\p{Letter}] |
| tst.js:1:3:1:29 | [RegExpUnicodePropertyEscape] \\p{Script_Extensions=Greek} | semmle.label | [RegExpUnicodePropertyEscape] \\p{Script_Extensions=Greek} |
| tst.js:1:32:1:41 | [RegExpUnicodePropertyEscape] \\p{Letter} | semmle.label | [RegExpUnicodePropertyEscape] \\p{Letter} |
| tst.js:2:1:2:17 | [RegExpLiteral] /[[abc]--[cbd]]/v | semmle.label | [RegExpLiteral] /[[abc]--[cbd]]/v |
| tst.js:2:1:2:18 | [ExprStmt] /[[abc]--[cbd]]/v; | semmle.label | [ExprStmt] /[[abc]--[cbd]]/v; |
| tst.js:2:1:2:18 | [ExprStmt] /[[abc]--[cbd]]/v; | semmle.order | 2 |
| tst.js:2:2:2:15 | [RegExpCharacterClass] [[abc]--[cbd]] | semmle.label | [RegExpCharacterClass] [[abc]--[cbd]] |
| tst.js:2:2:2:15 | [RegExpSubtraction] [[abc]--[cbd]] | semmle.label | [RegExpSubtraction] [[abc]--[cbd]] |
| tst.js:2:3:2:7 | [RegExpCharacterClass] [abc] | semmle.label | [RegExpCharacterClass] [abc] |
| tst.js:2:4:2:4 | [RegExpNormalConstant] a | semmle.label | [RegExpNormalConstant] a |
| tst.js:2:5:2:5 | [RegExpNormalConstant] b | semmle.label | [RegExpNormalConstant] b |
| tst.js:2:6:2:6 | [RegExpNormalConstant] c | semmle.label | [RegExpNormalConstant] c |
| tst.js:2:10:2:14 | [RegExpCharacterClass] [cbd] | semmle.label | [RegExpCharacterClass] [cbd] |
| tst.js:2:11:2:11 | [RegExpNormalConstant] c | semmle.label | [RegExpNormalConstant] c |
| tst.js:2:12:2:12 | [RegExpNormalConstant] b | semmle.label | [RegExpNormalConstant] b |
| tst.js:2:13:2:13 | [RegExpNormalConstant] d | semmle.label | [RegExpNormalConstant] d |
| tst.js:3:1:3:24 | [RegExpLiteral] /[[abc]--[cbd]--[bde]]/v | semmle.label | [RegExpLiteral] /[[abc]--[cbd]--[bde]]/v |
| tst.js:3:1:3:25 | [ExprStmt] /[[abc] ... de]]/v; | semmle.label | [ExprStmt] /[[abc] ... de]]/v; |
| tst.js:3:1:3:25 | [ExprStmt] /[[abc] ... de]]/v; | semmle.order | 3 |
| tst.js:3:2:3:22 | [RegExpCharacterClass] [[abc]--[cbd]--[bde]] | semmle.label | [RegExpCharacterClass] [[abc]--[cbd]--[bde]] |
| tst.js:3:2:3:22 | [RegExpSubtraction] [[abc]--[cbd]--[bde]] | semmle.label | [RegExpSubtraction] [[abc]--[cbd]--[bde]] |
| tst.js:3:3:3:7 | [RegExpCharacterClass] [abc] | semmle.label | [RegExpCharacterClass] [abc] |
| tst.js:3:4:3:4 | [RegExpNormalConstant] a | semmle.label | [RegExpNormalConstant] a |
| tst.js:3:5:3:5 | [RegExpNormalConstant] b | semmle.label | [RegExpNormalConstant] b |
| tst.js:3:6:3:6 | [RegExpNormalConstant] c | semmle.label | [RegExpNormalConstant] c |
| tst.js:3:10:3:14 | [RegExpCharacterClass] [cbd] | semmle.label | [RegExpCharacterClass] [cbd] |
| tst.js:3:11:3:11 | [RegExpNormalConstant] c | semmle.label | [RegExpNormalConstant] c |
| tst.js:3:12:3:12 | [RegExpNormalConstant] b | semmle.label | [RegExpNormalConstant] b |
| tst.js:3:13:3:13 | [RegExpNormalConstant] d | semmle.label | [RegExpNormalConstant] d |
| tst.js:3:17:3:21 | [RegExpCharacterClass] [bde] | semmle.label | [RegExpCharacterClass] [bde] |
| tst.js:3:18:3:18 | [RegExpNormalConstant] b | semmle.label | [RegExpNormalConstant] b |
| tst.js:3:19:3:19 | [RegExpNormalConstant] d | semmle.label | [RegExpNormalConstant] d |
| tst.js:3:20:3:20 | [RegExpNormalConstant] e | semmle.label | [RegExpNormalConstant] e |
edges
| tst.js:1:1:1:44 | [RegExpLiteral] /[\\p{Script_Extensions=Greek}--\\p{Letter}]/v | tst.js:1:2:1:42 | [RegExpCharacterClass] [\\p{Script_Extensions=Greek}--\\p{Letter}] | semmle.label | 0 |
| tst.js:1:1:1:44 | [RegExpLiteral] /[\\p{Script_Extensions=Greek}--\\p{Letter}]/v | tst.js:1:2:1:42 | [RegExpCharacterClass] [\\p{Script_Extensions=Greek}--\\p{Letter}] | semmle.order | 0 |
| tst.js:1:1:1:45 | [ExprStmt] /[\\p{Sc ... er}]/v; | tst.js:1:1:1:44 | [RegExpLiteral] /[\\p{Script_Extensions=Greek}--\\p{Letter}]/v | semmle.label | 1 |
| tst.js:1:1:1:45 | [ExprStmt] /[\\p{Sc ... er}]/v; | tst.js:1:1:1:44 | [RegExpLiteral] /[\\p{Script_Extensions=Greek}--\\p{Letter}]/v | semmle.order | 1 |
| tst.js:1:2:1:42 | [RegExpCharacterClass] [\\p{Script_Extensions=Greek}--\\p{Letter}] | tst.js:1:2:1:42 | [RegExpSubtraction] [\\p{Script_Extensions=Greek}--\\p{Letter}] | semmle.label | 0 |
| tst.js:1:2:1:42 | [RegExpCharacterClass] [\\p{Script_Extensions=Greek}--\\p{Letter}] | tst.js:1:2:1:42 | [RegExpSubtraction] [\\p{Script_Extensions=Greek}--\\p{Letter}] | semmle.order | 0 |
| tst.js:1:2:1:42 | [RegExpSubtraction] [\\p{Script_Extensions=Greek}--\\p{Letter}] | tst.js:1:3:1:29 | [RegExpUnicodePropertyEscape] \\p{Script_Extensions=Greek} | semmle.label | 0 |
| tst.js:1:2:1:42 | [RegExpSubtraction] [\\p{Script_Extensions=Greek}--\\p{Letter}] | tst.js:1:3:1:29 | [RegExpUnicodePropertyEscape] \\p{Script_Extensions=Greek} | semmle.order | 0 |
| tst.js:1:2:1:42 | [RegExpSubtraction] [\\p{Script_Extensions=Greek}--\\p{Letter}] | tst.js:1:32:1:41 | [RegExpUnicodePropertyEscape] \\p{Letter} | semmle.label | 1 |
| tst.js:1:2:1:42 | [RegExpSubtraction] [\\p{Script_Extensions=Greek}--\\p{Letter}] | tst.js:1:32:1:41 | [RegExpUnicodePropertyEscape] \\p{Letter} | semmle.order | 1 |
| tst.js:2:1:2:17 | [RegExpLiteral] /[[abc]--[cbd]]/v | tst.js:2:2:2:15 | [RegExpCharacterClass] [[abc]--[cbd]] | semmle.label | 0 |
| tst.js:2:1:2:17 | [RegExpLiteral] /[[abc]--[cbd]]/v | tst.js:2:2:2:15 | [RegExpCharacterClass] [[abc]--[cbd]] | semmle.order | 0 |
| tst.js:2:1:2:18 | [ExprStmt] /[[abc]--[cbd]]/v; | tst.js:2:1:2:17 | [RegExpLiteral] /[[abc]--[cbd]]/v | semmle.label | 1 |
| tst.js:2:1:2:18 | [ExprStmt] /[[abc]--[cbd]]/v; | tst.js:2:1:2:17 | [RegExpLiteral] /[[abc]--[cbd]]/v | semmle.order | 1 |
| tst.js:2:2:2:15 | [RegExpCharacterClass] [[abc]--[cbd]] | tst.js:2:2:2:15 | [RegExpSubtraction] [[abc]--[cbd]] | semmle.label | 0 |
| tst.js:2:2:2:15 | [RegExpCharacterClass] [[abc]--[cbd]] | tst.js:2:2:2:15 | [RegExpSubtraction] [[abc]--[cbd]] | semmle.order | 0 |
| tst.js:2:2:2:15 | [RegExpSubtraction] [[abc]--[cbd]] | tst.js:2:3:2:7 | [RegExpCharacterClass] [abc] | semmle.label | 0 |
| tst.js:2:2:2:15 | [RegExpSubtraction] [[abc]--[cbd]] | tst.js:2:3:2:7 | [RegExpCharacterClass] [abc] | semmle.order | 0 |
| tst.js:2:2:2:15 | [RegExpSubtraction] [[abc]--[cbd]] | tst.js:2:10:2:14 | [RegExpCharacterClass] [cbd] | semmle.label | 1 |
| tst.js:2:2:2:15 | [RegExpSubtraction] [[abc]--[cbd]] | tst.js:2:10:2:14 | [RegExpCharacterClass] [cbd] | semmle.order | 1 |
| tst.js:2:3:2:7 | [RegExpCharacterClass] [abc] | tst.js:2:4:2:4 | [RegExpNormalConstant] a | semmle.label | 0 |
| tst.js:2:3:2:7 | [RegExpCharacterClass] [abc] | tst.js:2:4:2:4 | [RegExpNormalConstant] a | semmle.order | 0 |
| tst.js:2:3:2:7 | [RegExpCharacterClass] [abc] | tst.js:2:5:2:5 | [RegExpNormalConstant] b | semmle.label | 1 |
| tst.js:2:3:2:7 | [RegExpCharacterClass] [abc] | tst.js:2:5:2:5 | [RegExpNormalConstant] b | semmle.order | 1 |
| tst.js:2:3:2:7 | [RegExpCharacterClass] [abc] | tst.js:2:6:2:6 | [RegExpNormalConstant] c | semmle.label | 2 |
| tst.js:2:3:2:7 | [RegExpCharacterClass] [abc] | tst.js:2:6:2:6 | [RegExpNormalConstant] c | semmle.order | 2 |
| tst.js:2:10:2:14 | [RegExpCharacterClass] [cbd] | tst.js:2:11:2:11 | [RegExpNormalConstant] c | semmle.label | 0 |
| tst.js:2:10:2:14 | [RegExpCharacterClass] [cbd] | tst.js:2:11:2:11 | [RegExpNormalConstant] c | semmle.order | 0 |
| tst.js:2:10:2:14 | [RegExpCharacterClass] [cbd] | tst.js:2:12:2:12 | [RegExpNormalConstant] b | semmle.label | 1 |
| tst.js:2:10:2:14 | [RegExpCharacterClass] [cbd] | tst.js:2:12:2:12 | [RegExpNormalConstant] b | semmle.order | 1 |
| tst.js:2:10:2:14 | [RegExpCharacterClass] [cbd] | tst.js:2:13:2:13 | [RegExpNormalConstant] d | semmle.label | 2 |
| tst.js:2:10:2:14 | [RegExpCharacterClass] [cbd] | tst.js:2:13:2:13 | [RegExpNormalConstant] d | semmle.order | 2 |
| tst.js:3:1:3:24 | [RegExpLiteral] /[[abc]--[cbd]--[bde]]/v | tst.js:3:2:3:22 | [RegExpCharacterClass] [[abc]--[cbd]--[bde]] | semmle.label | 0 |
| tst.js:3:1:3:24 | [RegExpLiteral] /[[abc]--[cbd]--[bde]]/v | tst.js:3:2:3:22 | [RegExpCharacterClass] [[abc]--[cbd]--[bde]] | semmle.order | 0 |
| tst.js:3:1:3:25 | [ExprStmt] /[[abc] ... de]]/v; | tst.js:3:1:3:24 | [RegExpLiteral] /[[abc]--[cbd]--[bde]]/v | semmle.label | 1 |
| tst.js:3:1:3:25 | [ExprStmt] /[[abc] ... de]]/v; | tst.js:3:1:3:24 | [RegExpLiteral] /[[abc]--[cbd]--[bde]]/v | semmle.order | 1 |
| tst.js:3:2:3:22 | [RegExpCharacterClass] [[abc]--[cbd]--[bde]] | tst.js:3:2:3:22 | [RegExpSubtraction] [[abc]--[cbd]--[bde]] | semmle.label | 0 |
| tst.js:3:2:3:22 | [RegExpCharacterClass] [[abc]--[cbd]--[bde]] | tst.js:3:2:3:22 | [RegExpSubtraction] [[abc]--[cbd]--[bde]] | semmle.order | 0 |
| tst.js:3:2:3:22 | [RegExpSubtraction] [[abc]--[cbd]--[bde]] | tst.js:3:3:3:7 | [RegExpCharacterClass] [abc] | semmle.label | 0 |
| tst.js:3:2:3:22 | [RegExpSubtraction] [[abc]--[cbd]--[bde]] | tst.js:3:3:3:7 | [RegExpCharacterClass] [abc] | semmle.order | 0 |
| tst.js:3:2:3:22 | [RegExpSubtraction] [[abc]--[cbd]--[bde]] | tst.js:3:10:3:14 | [RegExpCharacterClass] [cbd] | semmle.label | 1 |
| tst.js:3:2:3:22 | [RegExpSubtraction] [[abc]--[cbd]--[bde]] | tst.js:3:10:3:14 | [RegExpCharacterClass] [cbd] | semmle.order | 1 |
| tst.js:3:2:3:22 | [RegExpSubtraction] [[abc]--[cbd]--[bde]] | tst.js:3:17:3:21 | [RegExpCharacterClass] [bde] | semmle.label | 2 |
| tst.js:3:2:3:22 | [RegExpSubtraction] [[abc]--[cbd]--[bde]] | tst.js:3:17:3:21 | [RegExpCharacterClass] [bde] | semmle.order | 2 |
| tst.js:3:3:3:7 | [RegExpCharacterClass] [abc] | tst.js:3:4:3:4 | [RegExpNormalConstant] a | semmle.label | 0 |
| tst.js:3:3:3:7 | [RegExpCharacterClass] [abc] | tst.js:3:4:3:4 | [RegExpNormalConstant] a | semmle.order | 0 |
| tst.js:3:3:3:7 | [RegExpCharacterClass] [abc] | tst.js:3:5:3:5 | [RegExpNormalConstant] b | semmle.label | 1 |
| tst.js:3:3:3:7 | [RegExpCharacterClass] [abc] | tst.js:3:5:3:5 | [RegExpNormalConstant] b | semmle.order | 1 |
| tst.js:3:3:3:7 | [RegExpCharacterClass] [abc] | tst.js:3:6:3:6 | [RegExpNormalConstant] c | semmle.label | 2 |
| tst.js:3:3:3:7 | [RegExpCharacterClass] [abc] | tst.js:3:6:3:6 | [RegExpNormalConstant] c | semmle.order | 2 |
| tst.js:3:10:3:14 | [RegExpCharacterClass] [cbd] | tst.js:3:11:3:11 | [RegExpNormalConstant] c | semmle.label | 0 |
| tst.js:3:10:3:14 | [RegExpCharacterClass] [cbd] | tst.js:3:11:3:11 | [RegExpNormalConstant] c | semmle.order | 0 |
| tst.js:3:10:3:14 | [RegExpCharacterClass] [cbd] | tst.js:3:12:3:12 | [RegExpNormalConstant] b | semmle.label | 1 |
| tst.js:3:10:3:14 | [RegExpCharacterClass] [cbd] | tst.js:3:12:3:12 | [RegExpNormalConstant] b | semmle.order | 1 |
| tst.js:3:10:3:14 | [RegExpCharacterClass] [cbd] | tst.js:3:13:3:13 | [RegExpNormalConstant] d | semmle.label | 2 |
| tst.js:3:10:3:14 | [RegExpCharacterClass] [cbd] | tst.js:3:13:3:13 | [RegExpNormalConstant] d | semmle.order | 2 |
| tst.js:3:17:3:21 | [RegExpCharacterClass] [bde] | tst.js:3:18:3:18 | [RegExpNormalConstant] b | semmle.label | 0 |
| tst.js:3:17:3:21 | [RegExpCharacterClass] [bde] | tst.js:3:18:3:18 | [RegExpNormalConstant] b | semmle.order | 0 |
| tst.js:3:17:3:21 | [RegExpCharacterClass] [bde] | tst.js:3:19:3:19 | [RegExpNormalConstant] d | semmle.label | 1 |
| tst.js:3:17:3:21 | [RegExpCharacterClass] [bde] | tst.js:3:19:3:19 | [RegExpNormalConstant] d | semmle.order | 1 |
| tst.js:3:17:3:21 | [RegExpCharacterClass] [bde] | tst.js:3:20:3:20 | [RegExpNormalConstant] e | semmle.label | 2 |
| tst.js:3:17:3:21 | [RegExpCharacterClass] [bde] | tst.js:3:20:3:20 | [RegExpNormalConstant] e | semmle.order | 2 |
graphProperties
| semmle.graphKind | tree |

View File

@@ -0,0 +1 @@
import semmle.javascript.PrintAst

View File

@@ -0,0 +1,3 @@
/[\p{Script_Extensions=Greek}--\p{Letter}]/v;
/[[abc]--[cbd]]/v;
/[[abc]--[cbd]--[bde]]/v;

View File

@@ -238,6 +238,7 @@ flow
| promise.js:18:22:18:29 | source() | promise.js:24:10:24:10 | e |
| promise.js:33:21:33:28 | source() | promise.js:38:10:38:10 | e |
| promise.js:43:20:43:27 | source() | promise.js:43:8:43:28 | Promise ... urce()) |
| regexp-sanitiser.js:2:19:2:26 | source() | regexp-sanitiser.js:4:14:4:18 | taint |
| rxjs.js:3:1:3:8 | source() | rxjs.js:10:14:10:17 | data |
| rxjs.js:13:1:13:8 | source() | rxjs.js:17:23:17:23 | x |
| rxjs.js:13:1:13:8 | source() | rxjs.js:18:23:18:23 | x |

View File

@@ -161,6 +161,7 @@ flow
| partialCalls.js:4:17:4:24 | source() | partialCalls.js:30:14:30:20 | x.value |
| partialCalls.js:4:17:4:24 | source() | partialCalls.js:41:10:41:18 | id(taint) |
| partialCalls.js:4:17:4:24 | source() | partialCalls.js:51:14:51:14 | x |
| regexp-sanitiser.js:2:19:2:26 | source() | regexp-sanitiser.js:4:14:4:18 | taint |
| sanitizer-function.js:12:17:12:24 | source() | sanitizer-function.js:14:10:14:14 | taint |
| sanitizer-function.js:12:17:12:24 | source() | sanitizer-function.js:17:14:17:18 | taint |
| sanitizer-function.js:12:17:12:24 | source() | sanitizer-function.js:21:14:21:18 | taint |

View File

@@ -0,0 +1,6 @@
function foo() {
const taint = source();
if (/^asd[\s\S]*$/.test(taint)) {
sink(taint); // NOT OK
}
}

View File

@@ -2,9 +2,6 @@ nodes
| badTypes.ts:5:1:5:29 | [InterfaceDeclaration,TypeDefinition] interfa ... is.B {} | semmle.label | [InterfaceDeclaration,TypeDefinition] interfa ... is.B {} |
| badTypes.ts:5:1:5:29 | [InterfaceDeclaration,TypeDefinition] interfa ... is.B {} | semmle.order | 1 |
| badTypes.ts:5:11:5:11 | [Identifier] A | semmle.label | [Identifier] A |
| badTypes.ts:5:21:5:24 | [ThisVarTypeAccess] this | semmle.label | [ThisVarTypeAccess] this |
| badTypes.ts:5:21:5:26 | [TypeAccess] this.B | semmle.label | [TypeAccess] this.B |
| badTypes.ts:5:26:5:26 | [Identifier] B | semmle.label | [Identifier] B |
| badTypes.ts:6:1:6:24 | [TypeAliasDeclaration,TypeDefinition] type T ... ar.bar; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type T ... ar.bar; |
| badTypes.ts:6:1:6:24 | [TypeAliasDeclaration,TypeDefinition] type T ... ar.bar; | semmle.order | 2 |
| badTypes.ts:6:6:6:6 | [Identifier] T | semmle.label | [Identifier] T |
@@ -2171,12 +2168,6 @@ nodes
edges
| badTypes.ts:5:1:5:29 | [InterfaceDeclaration,TypeDefinition] interfa ... is.B {} | badTypes.ts:5:11:5:11 | [Identifier] A | semmle.label | 1 |
| badTypes.ts:5:1:5:29 | [InterfaceDeclaration,TypeDefinition] interfa ... is.B {} | badTypes.ts:5:11:5:11 | [Identifier] A | semmle.order | 1 |
| badTypes.ts:5:1:5:29 | [InterfaceDeclaration,TypeDefinition] interfa ... is.B {} | badTypes.ts:5:21:5:26 | [TypeAccess] this.B | semmle.label | 2 |
| badTypes.ts:5:1:5:29 | [InterfaceDeclaration,TypeDefinition] interfa ... is.B {} | badTypes.ts:5:21:5:26 | [TypeAccess] this.B | semmle.order | 2 |
| badTypes.ts:5:21:5:26 | [TypeAccess] this.B | badTypes.ts:5:21:5:24 | [ThisVarTypeAccess] this | semmle.label | 1 |
| badTypes.ts:5:21:5:26 | [TypeAccess] this.B | badTypes.ts:5:21:5:24 | [ThisVarTypeAccess] this | semmle.order | 1 |
| badTypes.ts:5:21:5:26 | [TypeAccess] this.B | badTypes.ts:5:26:5:26 | [Identifier] B | semmle.label | 2 |
| badTypes.ts:5:21:5:26 | [TypeAccess] this.B | badTypes.ts:5:26:5:26 | [Identifier] B | semmle.order | 2 |
| badTypes.ts:6:1:6:24 | [TypeAliasDeclaration,TypeDefinition] type T ... ar.bar; | badTypes.ts:6:6:6:6 | [Identifier] T | semmle.label | 1 |
| badTypes.ts:6:1:6:24 | [TypeAliasDeclaration,TypeDefinition] type T ... ar.bar; | badTypes.ts:6:6:6:6 | [Identifier] T | semmle.order | 1 |
| badTypes.ts:6:1:6:24 | [TypeAliasDeclaration,TypeDefinition] type T ... ar.bar; | badTypes.ts:6:10:6:23 | [TypeofTypeExpr] typeof var.bar | semmle.label | 2 |

View File

@@ -864,8 +864,6 @@ getTypeDefinitionType
| type_definitions.ts:21:1:21:20 | type Alias<T> = T[]; | Alias<T> |
getTypeExprType
| badTypes.ts:5:11:5:11 | A | A |
| badTypes.ts:5:21:5:26 | this.B | any |
| badTypes.ts:5:26:5:26 | B | any |
| badTypes.ts:6:6:6:6 | T | any |
| badTypes.ts:6:10:6:23 | typeof var.bar | any |
| badTypes.ts:6:17:6:19 | var | any |

View File

@@ -1,5 +1,7 @@
| connect.js:6:5:6:11 | req.url | url |
| connect.js:7:5:7:21 | req.cookies.get() | cookie |
| express-typed.ts:4:5:4:12 | req.body | body |
| express-typed.ts:10:5:10:12 | req.body | body |
| express.js:12:5:12:19 | req.param("p1") | parameter |
| express.js:13:5:13:17 | req.params.p2 | parameter |
| express.js:14:5:14:16 | req.query.p3 | parameter |

View File

@@ -0,0 +1,11 @@
import { Request } from "express";
export function f1(req: Request) {
req.body;
}
type Alias = Request & { foo: string };
export function f2(req: Alias) {
req.body;
}

View File

@@ -81,6 +81,10 @@ taintFlow
| test.js:272:6:272:40 | new MyS ... ource() | test.js:272:6:272:40 | new MyS ... ource() |
| test.js:274:6:274:39 | testlib ... eName() | test.js:274:6:274:39 | testlib ... eName() |
| test.js:277:8:277:31 | "danger ... .danger | test.js:277:8:277:31 | "danger ... .danger |
| test.js:284:8:284:16 | source[0] | test.js:284:8:284:16 | source[0] |
| test.js:285:8:285:19 | source.pop() | test.js:285:8:285:19 | source.pop() |
| test.js:286:18:286:18 | e | test.js:286:28:286:28 | e |
| test.js:287:14:287:14 | e | test.js:287:24:287:24 | e |
isSink
| test.js:54:18:54:25 | source() | test-sink |
| test.js:55:22:55:29 | source() | test-sink |

View File

@@ -10,6 +10,7 @@ extensions:
- ['testlib', 'Member[MethodDecorator].DecoratedMember.Parameter[0]', 'test-source']
- ['testlib', 'Member[ParamDecoratorSource].DecoratedParameter', 'test-source']
- ['testlib', 'Member[getSource].ReturnValue', 'test-source']
- ['testlib', 'Member[getSourceArray].ReturnValue.ArrayElement', 'test-source']
- ['(testlib)', 'Member[parenthesizedPackageName].ReturnValue', 'test-source']
- ['danger-constant', 'Member[danger]', 'test-source']

View File

@@ -278,3 +278,11 @@ function dangerConstant() {
sink("danger-constant".safe); // OK
sink("danger-constant"); // OK
}
function arraySource() {
const source = testlib.getSourceArray();
sink(source[0]); // NOT OK
sink(source.pop()); // NOT OK
source.forEach(e => sink(e)); // NOT OK
source.map(e => sink(e)); // NOT OK
}

View File

@@ -1 +1,2 @@
AngularJS/DeadAngularJSEventListener.ql
query: AngularJS/DeadAngularJSEventListener.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,50 +1,50 @@
angular.module('myModule', [])
.controller('MyController', function($scope) {
$scope.$on('destroy', cleanup); // BAD
$scope.$on('destroy', cleanup); // $ Alert
})
.controller('MyController', ["$scope", function(s) {
s.$on('destroy', cleanup); // BAD
s.$on('destroy', cleanup); // $ Alert
}])
.controller('MyController', function($scope) {
var destroy = 'destroy';
$scope.$on(destroy, cleanup); // BAD
$scope.$on(destroy, cleanup); // $ Alert
})
.controller('MyController', function($scope) {
$scope.$on('$destroy', cleanup); // GOOD
$scope.$on('$destroy', cleanup);
})
.controller('MyController', function($scope) {
$scope.$emit('foo');
$scope.$on('foo', cleanup); // GOOD
$scope.$on('foo', cleanup);
})
.controller('MyController', function($scope) {
$scope.$on('bar', cleanup); // BAD
$scope.$on('bar', cleanup); // $ Alert
})
.controller('MyController', function($scope) {
$scope.$on('$locationChangeStart', cleanup); // OK
$scope.$on('$locationChangeStart', cleanup);
})
.controller('MyController', function($scope) {
$scope.$on('lib1.foo', cleanup); // OK
$scope.$on('lib1.foo', cleanup);
})
.controller('MyController', function($scope) {
$scope.$on('lib2:foo', cleanup); // OK
$scope.$on('lib2:foo', cleanup);
})
.controller('MyController', function($scope) {
$scope.$on('onClick', cleanup); // OK
$scope.$on('onClick', cleanup);
})
.controller('MyController', function($scope) {
function f($scope){
$scope.$emit('probablyFromUserCode1')
}
$scope.$on('probablyFromUserCode1', cleanup); // OK
$scope.$on('probablyFromUserCode1', cleanup);
})
.controller('MyController', function($scope) {
function f($scope){
var scope = $scope;
scope.$emit('probablyFromUserCode2')
}
$scope.$on('probablyFromUserCode2', cleanup); // OK
$scope.$on('probablyFromUserCode2', cleanup);
})
.controller('MyController', function($scope) {
$scope.$on('event-from-AngularJS-expression', cleanup); // GOOD
$scope.$on('event-from-AngularJS-expression', cleanup);
})
;

View File

@@ -1 +1,2 @@
AngularJS/DependencyMismatch.ql
query: AngularJS/DependencyMismatch.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,36 +1,36 @@
angular.module('app1', [])
.run(['dep1', 'dep2', 'dep3', function(dep1, dep3, dep2) {}]); // NOT OK
.run(['dep1', 'dep2', 'dep3', function(dep1, dep3, dep2) {}]); // $ Alert
angular.module('app2')
.directive('mydirective', [ '$compile', function($compile, $http) { // NOT OK
.directive('mydirective', [ '$compile', function($compile, $http) { // $ Alert
// ...
}]);
angular.module('app1', [])
.run(['dep1', 'dep2', 'dep3', function(dep1, dep2, dep3) {}]); // OK
.run(['dep1', 'dep2', 'dep3', function(dep1, dep2, dep3) {}]);
angular.module('app2')
.directive('mydirective', [ '$compile', '$http', function($compile, $http) { // OK
.directive('mydirective', [ '$compile', '$http', function($compile, $http) {
// ...
}]);
angular.module('app3', [])
.run(function(dep1, dep3) {}); // OK
.run(function(dep1, dep3) {});
angular.module('app4')
.directive('mydirective', function($compile, $http) { // OK
.directive('mydirective', function($compile, $http) {
// ...
});
angular.module('app5')
.directive('mydirective', [ 'fully.qualified.name', function(name) { // OK
.directive('mydirective', [ 'fully.qualified.name', function(name) {
// ...
}])
angular.module('app6')
.directive('mydirective', function() {
return {
link: function (scope, element, attrs) { // OK
link: function (scope, element, attrs) {
}
};
});

View File

@@ -1,17 +1,17 @@
angular.module('app', [])
.config(function($sceProvider) {
$sceProvider.enabled(false); // BAD
$sceProvider.enabled(false); // $ Alert
})
.config(['otherProvider', function($sceProvider) {
$sceProvider.enabled(false); // OK
$sceProvider.enabled(false);
}])
.config(['$sceProvider', function(x) {
x.enabled(false); // BAD
x.enabled(false); // $ Alert
}])
.config(function($sceProvider) {
$sceProvider.enabled(true); // OK
$sceProvider.enabled(true);
})
.config(function($sceProvider) {
var x = false;
$sceProvider.enabled(x); // BAD
$sceProvider.enabled(x); // $ Alert
});

View File

@@ -1 +1,2 @@
AngularJS/DisablingSce.ql
query: AngularJS/DisablingSce.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
AngularJS/DoubleCompilation.ql
query: AngularJS/DoubleCompilation.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -11,7 +11,7 @@ angular.module('app').directive('addMouseover', function($compile) {
attrs.$set('addMouseover', null); // To stop infinite compile loop
element.append(newEl);
$compile(element)(scope); // Double compilation
$compile(element)(scope); // $ Alert - Double compilation
}
}
})

View File

@@ -1 +1,2 @@
AngularJS/IncompatibleService.ql
query: AngularJS/IncompatibleService.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -11,68 +11,68 @@ angular.module('myModule', [])
;
angular.module('myModule2', [])
.controller('c0', function(factoryId){}) // OK
.controller('c1', function(serviceId){}) // OK
.controller('c2', function(valueId){}) // OK
.controller('c3', function(constantId){}) // OK
.controller('c4', function(providerId){}) // OK
.controller('c5', function($http){}) // OK
.controller('c6', function($provider){}) // NOT OK
.controller('c7', function($scope){}) // OK
.controller('c8', function($compile){}) // OK
.controller('c9', function(UNKNOWN){}) // OK
.controller('c10', function(providerIdProvider){}) // NOT OK
.controller('c11', function(providerIdProvider, UNKNOWN){}) // NOT OK, but only one error
.controller('c12', function($provide){}) // OK (special case)
.controller('c13', function(providerId2Provider){}) // NOT OK
.controller('c0', function(factoryId){})
.controller('c1', function(serviceId){})
.controller('c2', function(valueId){})
.controller('c3', function(constantId){})
.controller('c4', function(providerId){})
.controller('c5', function($http){})
.controller('c6', function($provider){}) // $ Alert
.controller('c7', function($scope){})
.controller('c8', function($compile){})
.controller('c9', function(UNKNOWN){})
.controller('c10', function(providerIdProvider){}) // $ Alert
.controller('c11', function(providerIdProvider, UNKNOWN){}) // $ Alert - but only one error
.controller('c12', function($provide){}) // OK - special case
.controller('c13', function(providerId2Provider){}) // $ Alert
.factory('s0', function(factoryId){}) // OK
.factory('s1', function(serviceId){}) // OK
.factory('s2', function(valueId){}) // OK
.factory('s3', function(constantId){}) // OK
.factory('s4', function(providerId){}) // OK
.factory('s5', function($http){}) // OK
.factory('s6', function($provider){}) // NOT OK
.factory('s7', function($scope){}) // NOT OK
.factory('s8', function($compile){}) // OK
.factory('s9', function(UNKNOWN){}) // OK
.factory('s10', function(providerIdProvider){}) // NOT OK
.factory('s11', function(providerIdProvider, UNKNOWN){}) // NOT OK, but only one error
.factory('s12', function($provide){}) // OK (special case)
.factory('s13', function(providerId2Provider){}) // NOT OK
.factory('s0', function(factoryId){})
.factory('s1', function(serviceId){})
.factory('s2', function(valueId){})
.factory('s3', function(constantId){})
.factory('s4', function(providerId){})
.factory('s5', function($http){})
.factory('s6', function($provider){}) // $ Alert
.factory('s7', function($scope){}) // $ Alert
.factory('s8', function($compile){})
.factory('s9', function(UNKNOWN){})
.factory('s10', function(providerIdProvider){}) // $ Alert
.factory('s11', function(providerIdProvider, UNKNOWN){}) // $ Alert - but only one error
.factory('s12', function($provide){}) // OK - special case
.factory('s13', function(providerId2Provider){}) // $ Alert
.run(function(factoryId){}) // OK
.run(function(serviceId){}) // OK
.run(function(valueId){}) // OK
.run(function(constantId){}) // OK
.run(function(providerId){}) // OK
.run(function($http){}) // OK
.run(function($provider){}) // NOT OK
.run(function($scope){}) // NOT OK
.run(function($compile){}) // OK
.run(function(UNKNOWN){}) // OK
.run(function(providerIdProvider){}) // NOT OK
.run(function(providerIdProvider, UNKNOWN){}) // NOT OK, but only one error
.run(function($provide){}) // OK (special case)
.run(function(providerId2Provider){}) // NOT OK
.run(function(factoryId){})
.run(function(serviceId){})
.run(function(valueId){})
.run(function(constantId){})
.run(function(providerId){})
.run(function($http){})
.run(function($provider){}) // $ Alert
.run(function($scope){}) // $ Alert
.run(function($compile){})
.run(function(UNKNOWN){})
.run(function(providerIdProvider){}) // $ Alert
.run(function(providerIdProvider, UNKNOWN){}) // $ Alert - but only one error
.run(function($provide){}) // OK - special case
.run(function(providerId2Provider){}) // $ Alert
.config(function(factoryId){}) // NOT OK
.config(function(serviceId){}) // NOT OK
.config(function(valueId){}) // NOT OK
.config(function(constantId){}) // OK
.config(function(providerId){}) // NOT OK
.config(function($http){}) // NOT OK
.config(function($provider){}) // OK
.config(function($scope){}) // NOT OK
.config(function($compile){}) // OK
.config(function(UNKNOWN){}) // OK
.config(function(providerIdProvider){}) // OK
.config(function(providerId, UNKNOWN){}) // NOT OK, but only one error
.config(function($provide){}) // OK (special case)
.config(function(valueId2){}) // NOT OK
.config(function(factoryId){}) // $ Alert
.config(function(serviceId){}) // $ Alert
.config(function(valueId){}) // $ Alert
.config(function(constantId){})
.config(function(providerId){}) // $ Alert
.config(function($http){}) // $ Alert
.config(function($provider){})
.config(function($scope){}) // $ Alert
.config(function($compile){})
.config(function(UNKNOWN){})
.config(function(providerIdProvider){})
.config(function(providerId, UNKNOWN){}) // $ Alert - but only one error
.config(function($provide){}) // OK - special case
.config(function(valueId2){}) // $ Alert
// service: same restrcitions as .factory
.service('s14', function(factoryId){}) // OK
.service('s15', function($provider){}) // NOT OK
.service('s14', function(factoryId){})
.service('s15', function($provider){}) // $ Alert
;

View File

@@ -1 +1,2 @@
AngularJS/InsecureUrlWhitelist.ql
query: AngularJS/InsecureUrlWhitelist.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,24 +1,24 @@
angular.module('myApp', [])
.config(function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist([
"**://example.com/*", // BAD (exploit: http://evil.com/?ignore=://example.org/a or javascript:alert(1);://example.org/a)
"*://example.org/*", // BAD (exploit: javascript://example.org/a%0A%0Dalert(1) using a linebreak to end the comment starting with "//"!)
"https://**.example.com/*", // BAD (exploit: https://evil.com/?ignore=://example.com/a)
"https://example.**", // BAD (exploit: https://example.evil.com or http://example.:foo@evil.com)
"https://example.*", // BAD (exploit: https://example.UnexpectedTLD)
"**://example.com/*", // $ RelatedLocation - (exploit: http://evil.com/?ignore=://example.org/a or javascript:alert(1);://example.org/a)
"*://example.org/*", // $ RelatedLocation - (exploit: javascript://example.org/a%0A%0Dalert(1) using a linebreak to end the comment starting with "//"!)
"https://**.example.com/*", // $ RelatedLocation - exploit: https://evil.com/?ignore=://example.com/a
"https://example.**", // $ RelatedLocation - exploit: https://example.evil.com or http://example.:foo@evil.com
"https://example.*", // $ RelatedLocation - exploit: https://example.UnexpectedTLD
"https://example.com", // OK
"https://example.com/**", // OK
"https://example.com/*", // OK
"https://example.com/foo/*", // OK
"https://example.com/foo/**", // OK
"https://example.com/foo/*/bar", // OK
"https://example.com/foo/**/bar", // OK
"https://example.com/?**", // OK
"https://example.com/?**://example.com", // OK
"https://example.com",
"https://example.com/**",
"https://example.com/*",
"https://example.com/foo/*",
"https://example.com/foo/**",
"https://example.com/foo/*/bar",
"https://example.com/foo/**/bar",
"https://example.com/?**",
"https://example.com/?**://example.com",
"https://*.example.com",
// not flagged:
/http:\/\/www.example.org/g // BAD (exploit http://wwwaexample.org (dots are not escaped))
]);
/http:\/\/www.example.org/g // $ MISSING: RelatedLocation - (exploit http://wwwaexample.org (dots are not escaped))
]); // $ Alert
});

View File

@@ -1 +1,2 @@
AngularJS/MissingExplicitInjection.ql
query: AngularJS/MissingExplicitInjection.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,27 +1,27 @@
(function(){
function injected1(name){} // NOT OK
function injected1(name){} // $ Alert
angular.module('app1').controller('controller1', injected1);
function injected2(name){} // OK
function injected2(name){}
injected2.$inject = ['name'];
angular.module('app2').controller('controller2', injected2);
function injected3(name){} // OK
function injected3(name){}
angular.module('app3').controller('controller3', ['name', injected3]);
angular.module('app4').controller('controller4', function(){}); // OK
angular.module('app4').controller('controller4', function(){});
angular.module('app5').controller('controller5', function(name){}); // NOT OK
angular.module('app5').controller('controller5', function(name){}); // $ Alert
function injected6(){} // OK
function injected6(){}
angular.module('app6').controller('controller6', injected6);
function notInjected7(name){} // OK
function notInjected7(name){}
var obj7 = {
controller: notInjected7
};
function injected8(name){} // OK (false negative: we do not track through properties)
function injected8(name){} // OK - false negative: we do not track through properties
var obj8 = {
controller: injected8
};
@@ -29,14 +29,14 @@
var $injector = angular.injector();
function injected9(name){} // NOT OK
function injected9(name){} // $ Alert
$injector.invoke(injected9)
function injected10(name){} // OK
function injected10(name){}
injected10.$inject = ['name'];
$injector.invoke(injected10)
function injected11(name){} // OK
function injected11(name){}
$injector.invoke(['name', injected11])
})();

View File

@@ -2,5 +2,5 @@
| repeated-injection.js:6:5:6:31 | functio ... name){} | This function has $@ defined in multiple places. | repeated-injection.js:8:54:8:73 | ['name', $Injected2] | dependency injections |
| repeated-injection.js:10:5:10:31 | functio ... name){} | This function has $@ defined in multiple places. | repeated-injection.js:11:5:11:22 | $Injected3.$inject | dependency injections |
| repeated-injection.js:10:5:10:31 | functio ... name){} | This function has $@ defined in multiple places. | repeated-injection.js:12:5:12:22 | $Injected3.$inject | dependency injections |
| repeated-injection.js:33:5:33:84 | functio ... )\\n } | This function has $@ defined in multiple places. | repeated-injection.js:35:5:35:23 | $Injected10.$inject | dependency injections |
| repeated-injection.js:33:5:33:84 | functio ... )\\n } | This function has $@ defined in multiple places. | repeated-injection.js:36:56:36:76 | ['name' ... cted10] | dependency injections |
| repeated-injection.js:33:5:33:85 | functio ... n\\n } | This function has $@ defined in multiple places. | repeated-injection.js:35:5:35:23 | $Injected10.$inject | dependency injections |
| repeated-injection.js:33:5:33:85 | functio ... n\\n } | This function has $@ defined in multiple places. | repeated-injection.js:36:56:36:76 | ['name' ... cted10] | dependency injections |

View File

@@ -1 +1,2 @@
AngularJS/RepeatedInjection.ql
query: AngularJS/RepeatedInjection.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,36 +1,36 @@
(function(){
function $Injected1(name){} // OK
function $Injected1(name){}
$Injected1.$inject = ['name'];
angular.module('app1').controller('controller1', $Injected1);
function $Injected2(name){} // NOT OK
function $Injected2(name){} // $ Alert
$Injected2.$inject = ['name'];
angular.module('app2').controller('controller2', ['name', $Injected2]);
function $Injected3(name){} // NOT OK
function $Injected3(name){} // $ Alert
$Injected3.$inject = ['name'];
$Injected3.$inject = ['name'];
angular.module('app3').controller('controller3', $Injected3);
function not$Injected4(name){} // OK
function not$Injected4(name){}
angular.module('app4').controller('controller4', not$Injected4);
function not$Injected5(name){} // OK
function not$Injected5(name){}
angular.module('app5').controller('controller5', ['name', not$Injected5]);
function $Injected6(name){} // OK (because it never becomes registered)
function $Injected6(name){} // OK - because it never becomes registered
$Injected6.$inject = ['name'];
$Injected6.$inject = ['name'];
function not$Injected7(name){} // OK
function not$Injected7(name){}
angular.module('app7').controller('controller7', ['name', not$Injected7]);
angular.module('app7').controller('controller7', ['name', not$Injected7]);
angular.module('app7').controller('controller7', not$Injected7);
angular.module('app8').controller('controller8', function inline8(name){}); // OK
angular.module('app8').controller('controller8', function inline8(name){});
angular.module('app9').controller('controller9', ['name', function inline9(name){}]); // OK
angular.module('app9').controller('controller9', ['name', function inline9(name){}]);
function $Injected10(name){ // NOT OK (alert formatting for multi-line function)
function $Injected10(name){ // $ Alert - alert formatting for multi-line function
}
$Injected10.$inject = ['name'];
angular.module('app10').controller('controller10', ['name', $Injected10]);

View File

@@ -2,4 +2,4 @@
| unused-angular-dependency.js:14:14:14:39 | ["unuse ... n() {}] | This function has 0 parameters, but 1 dependency is injected into it. |
| unused-angular-dependency.js:16:14:16:53 | ["used2 ... d2) {}] | This function has 1 parameter, but 2 dependencies are injected into it. |
| unused-angular-dependency.js:17:14:17:52 | ["unuse ... n() {}] | This function has 0 parameters, but 2 dependencies are injected into it. |
| unused-angular-dependency.js:18:14:18:105 | ["used2 ... }] | This function has 1 parameter, but 2 dependencies are injected into it. |
| unused-angular-dependency.js:18:14:18:106 | ["used2 ... }] | This function has 1 parameter, but 2 dependencies are injected into it. |

View File

@@ -1 +1,2 @@
AngularJS/UnusedAngularDependency.ql
query: AngularJS/UnusedAngularDependency.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,28 +1,28 @@
(function(){
function f1(used2, unused5) {used2;} // OK (suppressed by js/unused-parameter)
function f1(used2, unused5) {used2;} // OK - suppressed by js/unused-parameter
// this function avoid suppression from js/unused-parameter by explicitly targeting one its weaknesses
function f2(unused7, used3) {used3;} // NOT OK
function f2(unused7, used3) {used3;} // $ Alert
this.f2 = f2;
angular.module('app1', [])
.run(function() {})
.run(function(unused1) {}) // OK (suppressed by js/unused-parameter)
.run(function(unused2, unused3) {}) // OK (suppressed by js/unused-parameter)
.run(function(used1, unused4) {used1;}) // OK (suppressed by js/unused-parameter)
.run(function(unused1) {}) // OK - suppressed by js/unused-parameter
.run(function(unused2, unused3) {}) // OK - suppressed by js/unused-parameter
.run(function(used1, unused4) {used1;}) // OK - suppressed by js/unused-parameter
.run(f1)
.run(["unused6", function() {}]) // NOT OK
.run(["unused6", function() {}]) // $ Alert
.run(f2)
.run(["used2", "unused9", function(used2) {}]) // NOT OK
.run(["unused10", "unused11", function() {}]) // NOT OK
.run(["used2", "unused12", function(used2) { // NOT OK (alert formatting for multi-line function)
.run(["used2", "unused9", function(used2) {}]) // $ Alert
.run(["unused10", "unused11", function() {}]) // $ Alert
.run(["used2", "unused12", function(used2) { // $ Alert - alert formatting for multi-line function
}])
;
})();
angular.module('app2')
.directive('mydirective', function() {
return {
link: function (scope, element, attrs) { // OK
link: function (scope, element, attrs) {
}
};
});

View File

@@ -1,5 +1,5 @@
| tst2.html:3:6:3:24 | href={{help_url}} | Use 'ng-href' instead of 'href'. |
| tst.html:8:6:8:24 | href={{help_url}} | Use 'ng-href' instead of 'href'. |
| tst.html:10:40:10:83 | srcset=#/resources/pics-large/{{item._id}} | Use 'ng-srcset' instead of 'srcset'. |
| tst.html:11:10:11:52 | src=#/resources/pics-default/{{item._id}} | Use 'ng-src' instead of 'src'. |
| tst_fragment.html:3:6:3:24 | href={{help_url}} | Use 'ng-href' instead of 'href'. |
| tst2.html:2:6:2:24 | href={{help_url}} | Use 'ng-href' instead of 'href'. |
| tst.html:7:6:7:24 | href={{help_url}} | Use 'ng-href' instead of 'href'. |
| tst.html:9:40:9:83 | srcset=#/resources/pics-large/{{item._id}} | Use 'ng-srcset' instead of 'srcset'. |
| tst.html:10:10:10:52 | src=#/resources/pics-default/{{item._id}} | Use 'ng-src' instead of 'src'. |
| tst_fragment.html:2:6:2:24 | href={{help_url}} | Use 'ng-href' instead of 'href'. |

View File

@@ -1 +1,2 @@
AngularJS/UseNgSrc.ql
query: AngularJS/UseNgSrc.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -4,13 +4,12 @@
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
</head>
<body>
<!-- BAD -->
<a href="{{help_url}}">Help</a>
<a href="{{help_url}}">Help</a> <!-- $ Alert -->
<picture>
<source media="(min-width: 650px)" srcset="#/resources/pics-large/{{item._id}}">
<img src="#/resources/pics-default/{{item._id}}">
<source media="(min-width: 650px)" srcset="#/resources/pics-large/{{item._id}}"> <!-- $ Alert -->
<img src="#/resources/pics-default/{{item._id}}"> <!-- $ Alert -->
</picture>
<!-- GOOD -->
<a ng-href="{{help_url}}">Help</a>
<picture>
<source media="(min-width: 650px)" ng-srcset="#/resources/pics-large/{{item._id}}">

View File

@@ -1,4 +1,3 @@
<div x-ng-bind="I am here to make this seem like an AngularJS template">
<!-- BAD -->
<a href="{{help_url}}">Help</a>
<a href="{{help_url}}">Help</a> <!-- $ Alert -->
</div>

View File

@@ -1,4 +1,3 @@
<body ng-app>
<!-- BAD -->
<a href="{{help_url}}">Help</a>
<a href="{{help_url}}">Help</a> <!-- $ Alert -->
</body>

View File

@@ -1 +1 @@
Comments/CommentedOutCode.ql
query: Comments/CommentedOutCode.ql

View File

@@ -1 +1 @@
Comments/TodoComments.ql
query: Comments/TodoComments.ql

Some files were not shown because too many files have changed in this diff Show More