Merge branch 'main' into property-stringify

This commit is contained in:
tyage
2022-10-04 09:57:54 +01:00
committed by GitHub
404 changed files with 9236 additions and 4706 deletions

View File

@@ -93,6 +93,9 @@ module Actions {
/** Gets the value of the `if` field in this job, if any. */
JobIf getIf() { result.getJob() = this }
/** Gets the value of the `runs-on` field in this job. */
JobRunson getRunsOn() { result.getJob() = this }
}
/**
@@ -108,6 +111,19 @@ module Actions {
Job getJob() { result = job }
}
/**
* A `runs-on` within a job.
* See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idruns-on.
*/
class JobRunson extends YamlNode, YamlScalar {
Job job;
JobRunson() { job.lookup("runs-on") = this }
/** Gets the step this field belongs to. */
Job getJob() { result = job }
}
/**
* A step within an Actions job.
* See https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idsteps.

View File

@@ -70,7 +70,7 @@ class JsxElement extends JsxNode {
override string getAPrimaryQlClass() { result = "JsxElement" }
/**
* Holds if this JSX element is a HTML element.
* Holds if this JSX element is an HTML element.
* That is, the name starts with a lowercase letter.
*/
predicate isHtmlElement() { getName().regexpMatch("[a-z].*") }

View File

@@ -164,14 +164,27 @@ module ModelInput {
class TypeModel extends Unit {
/**
* Gets a data-flow node that is a source of the type `package;type`.
*
* This must not depend on API graphs, but ensures that an API node is generated for
* the source.
*/
DataFlow::Node getASource(string package, string type) { none() }
/**
* Gets a data flow node that is a sink of the type `package;type`,
* Gets a data-flow node that is a sink of the type `package;type`,
* usually because it is an argument passed to a parameter of that type.
*
* This must not depend on API graphs, but ensures that an API node is generated for
* the sink.
*/
DataFlow::Node getASink(string package, string type) { none() }
/**
* Gets an API node that is a source or sink of the type `package;type`.
*
* Unlike `getASource` and `getASink`, this may depend on API graphs.
*/
API::Node getAnApiNode(string package, string type) { none() }
}
/**
@@ -434,6 +447,8 @@ private API::Node getNodeFromType(string package, string type) {
or
result = any(TypeModelDefEntry e).getNodeForType(package, type)
or
result = any(TypeModel t).getAnApiNode(package, type)
or
result = Specific::getExtraNodeFromType(package, type)
}
@@ -529,7 +544,7 @@ private API::Node getNodeFromSubPath(API::Node base, AccessPath subPath) {
}
/** Gets the node identified by the given `(package, type, path)` tuple. */
API::Node getNodeFromPath(string package, string type, AccessPath path) {
private API::Node getNodeFromPath(string package, string type, AccessPath path) {
result = getNodeFromPath(package, type, path, path.getNumToken())
}
@@ -552,7 +567,9 @@ private predicate typeStep(API::Node pred, API::Node succ) {
*
* Unlike `getNodeFromPath`, the `path` may end with one or more call-site filters.
*/
Specific::InvokeNode getInvocationFromPath(string package, string type, AccessPath path, int n) {
private Specific::InvokeNode getInvocationFromPath(
string package, string type, AccessPath path, int n
) {
result = Specific::getAnInvocationOf(getNodeFromPath(package, type, path, n))
or
result = getInvocationFromPath(package, type, path, n - 1) and
@@ -560,7 +577,7 @@ Specific::InvokeNode getInvocationFromPath(string package, string type, AccessPa
}
/** Gets an invocation identified by the given `(package, type, path)` tuple. */
Specific::InvokeNode getInvocationFromPath(string package, string type, AccessPath path) {
private Specific::InvokeNode getInvocationFromPath(string package, string type, AccessPath path) {
result = getInvocationFromPath(package, type, path, path.getNumToken())
}
@@ -568,7 +585,7 @@ Specific::InvokeNode getInvocationFromPath(string package, string type, AccessPa
* Holds if `name` is a valid name for an access path token in the identifying access path.
*/
bindingset[name]
predicate isValidTokenNameInIdentifyingAccessPath(string name) {
private predicate isValidTokenNameInIdentifyingAccessPath(string name) {
name = ["Argument", "Parameter", "ReturnValue", "WithArity", "TypeVar"]
or
Specific::isExtraValidTokenNameInIdentifyingAccessPath(name)
@@ -579,7 +596,7 @@ predicate isValidTokenNameInIdentifyingAccessPath(string name) {
* in an identifying access path.
*/
bindingset[name]
predicate isValidNoArgumentTokenInIdentifyingAccessPath(string name) {
private predicate isValidNoArgumentTokenInIdentifyingAccessPath(string name) {
name = "ReturnValue"
or
Specific::isExtraValidNoArgumentTokenInIdentifyingAccessPath(name)
@@ -590,7 +607,7 @@ predicate isValidNoArgumentTokenInIdentifyingAccessPath(string name) {
* in an identifying access path.
*/
bindingset[name, argument]
predicate isValidTokenArgumentInIdentifyingAccessPath(string name, string argument) {
private predicate isValidTokenArgumentInIdentifyingAccessPath(string name, string argument) {
name = ["Argument", "Parameter"] and
argument.regexpMatch("(N-|-)?\\d+(\\.\\.((N-|-)?\\d+)?)?")
or
@@ -607,51 +624,61 @@ predicate isValidTokenArgumentInIdentifyingAccessPath(string name, string argume
* Module providing access to the imported models in terms of API graph nodes.
*/
module ModelOutput {
/**
* Holds if a CSV source model contributed `source` with the given `kind`.
*/
API::Node getASourceNode(string kind) {
exists(string package, string type, string path |
sourceModel(package, type, path, kind) and
result = getNodeFromPath(package, type, path)
)
cached
private module Cached {
/**
* Holds if a CSV source model contributed `source` with the given `kind`.
*/
cached
API::Node getASourceNode(string kind) {
exists(string package, string type, string path |
sourceModel(package, type, path, kind) and
result = getNodeFromPath(package, type, path)
)
}
/**
* Holds if a CSV sink model contributed `sink` with the given `kind`.
*/
cached
API::Node getASinkNode(string kind) {
exists(string package, string type, string path |
sinkModel(package, type, path, kind) and
result = getNodeFromPath(package, type, path)
)
}
/**
* Holds if a relevant CSV summary exists for these parameters.
*/
cached
predicate relevantSummaryModel(
string package, string type, string path, string input, string output, string kind
) {
isRelevantPackage(package) and
summaryModel(package, type, path, input, output, kind)
}
/**
* Holds if a `baseNode` is an invocation identified by the `package,type,path` part of a summary row.
*/
cached
predicate resolvedSummaryBase(
string package, string type, string path, Specific::InvokeNode baseNode
) {
summaryModel(package, type, path, _, _, _) and
baseNode = getInvocationFromPath(package, type, path)
}
/**
* Holds if `node` is seen as an instance of `(package,type)` due to a type definition
* contributed by a CSV model.
*/
cached
API::Node getATypeNode(string package, string type) { result = getNodeFromType(package, type) }
}
/**
* Holds if a CSV sink model contributed `sink` with the given `kind`.
*/
API::Node getASinkNode(string kind) {
exists(string package, string type, string path |
sinkModel(package, type, path, kind) and
result = getNodeFromPath(package, type, path)
)
}
/**
* Holds if a relevant CSV summary exists for these parameters.
*/
predicate relevantSummaryModel(
string package, string type, string path, string input, string output, string kind
) {
isRelevantPackage(package) and
summaryModel(package, type, path, input, output, kind)
}
/**
* Holds if a `baseNode` is an invocation identified by the `package,type,path` part of a summary row.
*/
predicate resolvedSummaryBase(
string package, string type, string path, Specific::InvokeNode baseNode
) {
summaryModel(package, type, path, _, _, _) and
baseNode = getInvocationFromPath(package, type, path)
}
/**
* Holds if `node` is seen as an instance of `(package,type)` due to a type definition
* contributed by a CSV model.
*/
API::Node getATypeNode(string package, string type) { result = getNodeFromType(package, type) }
import Cached
/**
* Gets an error message relating to an invalid CSV row in a model.

View File

@@ -87,7 +87,7 @@ predicate isBadRegexpFilter(HtmlMatchingRegExp regexp, string msg) {
not regexp.fillsCaptureGroup("<script>", group) and
msg =
"This regular expression only parses --> (capture group " + group +
") and not --!> as a HTML comment end tag."
") and not --!> as an HTML comment end tag."
)
or
regexp.matches("<!-- foo -->") and

View File

@@ -80,7 +80,7 @@ module HtmlSanitization {
}
/**
* Gets a HTML-relevant character that is replaced by `chain`.
* Gets an HTML-relevant character that is replaced by `chain`.
*/
private string getALikelyReplacedCharacter(StringReplaceCallSequence chain) {
result = "\"" and

View File

@@ -35,7 +35,7 @@ private DangerousPrefixSubstring getADangerousMatchedChar(EmptyReplaceRegExpTerm
or
result = t.getAMatchedString()
or
// A substring matched by some character class. This is only used to match the "word" part of a HTML tag (e.g. "iframe" in "<iframe").
// A substring matched by some character class. This is only used to match the "word" part of an HTML tag (e.g. "iframe" in "<iframe").
exists(NfaUtils::CharacterClass cc |
cc = NfaUtils::getCanonicalCharClass(t) and
cc.matches(result) and
@@ -101,12 +101,12 @@ private class RepetitionMatcher extends EmptyReplaceRegExpTerm {
predicate matchesDangerousPrefix(EmptyReplaceRegExpTerm t, string prefix, string kind) {
prefix = getADangerousMatchedPrefix(t) and
(
kind = "path injection" and
kind = "a path injection vulnerability" and
prefix = ["/..", "../"] and
// If the regex is matching explicit path components, it is unlikely that it's being used as a sanitizer.
not t.getSuccessor*().getAMatchedString().regexpMatch("(?is).*[a-z0-9_-].*")
or
kind = "HTML element injection" and
kind = "an HTML element injection vulnerability" and
(
// comments
prefix = "<!--" and
@@ -119,7 +119,7 @@ predicate matchesDangerousPrefix(EmptyReplaceRegExpTerm t, string prefix, string
)
)
or
kind = "HTML attribute injection" and
kind = "an HTML attribute injection vulnerability" and
prefix =
[
// ordinary event handler prefix
@@ -197,6 +197,6 @@ query predicate problems(
) {
exists(string kind |
isResult(replace, dangerous, prefix, kind) and
msg = "This string may still contain $@, which may cause a " + kind + " vulnerability."
msg = "This string may still contain $@, which may cause " + kind + "."
)
}

View File

@@ -213,6 +213,9 @@ module PasswordHeuristics {
normalized
.regexpMatch(".*(pass|test|sample|example|secret|root|admin|user|change|auth|fake|(my(token|password))|string|foo|bar|baz|qux|1234|3141|abcd).*")
)
or
// repeats the same char more than 10 times
password.regexpMatch(".*([a-zA-Z0-9])\\1{10,}.*")
}
/**

View File

@@ -26,7 +26,7 @@ module ImproperCodeSanitization {
abstract class Sanitizer extends DataFlow::Node { }
/**
* A call to a HTML sanitizer seen as a source for improper code sanitization
* A call to an HTML sanitizer seen as a source for improper code sanitization
*/
class HtmlSanitizerCallAsSource extends Source {
HtmlSanitizerCallAsSource() { this instanceof HtmlSanitizerCall }

View File

@@ -32,7 +32,7 @@ module UnsafeJQueryPlugin {
abstract class Sanitizer extends DataFlow::Node { }
/**
* An argument that may act as a HTML fragment rather than a CSS selector, as a sink for remote unsafe jQuery plugins.
* An argument that may act as an HTML fragment rather than a CSS selector, as a sink for remote unsafe jQuery plugins.
*/
class AmbiguousHtmlOrSelectorArgument extends DataFlow::Node,
DomBasedXss::JQueryHtmlOrSelectorArgument {
@@ -173,7 +173,7 @@ module UnsafeJQueryPlugin {
}
/**
* An argument that may act as a HTML fragment rather than a CSS selector, as a sink for remote unsafe jQuery plugins.
* An argument that may act as an HTML fragment rather than a CSS selector, as a sink for remote unsafe jQuery plugins.
*/
class AmbiguousHtmlOrSelectorArgumentAsSink extends Sink {
AmbiguousHtmlOrSelectorArgumentAsSink() {
@@ -182,7 +182,7 @@ module UnsafeJQueryPlugin {
}
/**
* A hint that a value is expected to be treated as a HTML fragment later.
* A hint that a value is expected to be treated as an HTML fragment later.
*/
class IntentionalHtmlFragmentHint extends Sanitizer {
IntentionalHtmlFragmentHint() {
@@ -191,7 +191,7 @@ module UnsafeJQueryPlugin {
}
/**
* Holds if there exists a jQuery plugin that likely expects `sink` to be treated as a HTML fragment.
* Holds if there exists a jQuery plugin that likely expects `sink` to be treated as an HTML fragment.
*/
predicate isLikelyIntentionalHtmlSink(DataFlow::Node sink) {
exists(
@@ -206,7 +206,7 @@ module UnsafeJQueryPlugin {
}
/**
* Gets a property-write that writes a HTML-like constant string to `prop`.
* Gets a property-write that writes an HTML-like constant string to `prop`.
*/
pragma[noinline]
private DataFlow::PropWrite getALikelyHtmlWrite(string prop) {

View File

@@ -65,7 +65,7 @@ module Shared {
private import semmle.javascript.security.dataflow.IncompleteHtmlAttributeSanitizationCustomizations::IncompleteHtmlAttributeSanitization as IncompleteHtml
/**
* A guard that checks if a string can contain quotes, which is a guard for strings that are inside a HTML attribute.
* A guard that checks if a string can contain quotes, which is a guard for strings that are inside an HTML attribute.
*/
abstract class QuoteGuard extends TaintTracking::SanitizerGuardNode, StringOps::Includes {
QuoteGuard() {