mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
JS: Remove ML-powered queries
This commit is contained in:
5
.gitattributes
vendored
5
.gitattributes
vendored
@@ -67,11 +67,6 @@ go/extractor/opencsv/CSVReader.java -text
|
||||
# for those testing dbscheme files.
|
||||
*/ql/lib/upgrades/initial/*.dbscheme -text
|
||||
|
||||
# Generated test files - these are synced from the standard JavaScript libraries using
|
||||
# `javascript/ql/experimental/adaptivethreatmodeling/test/update_endpoint_test_files.py`.
|
||||
javascript/ql/experimental/adaptivethreatmodeling/test/endpoint_large_scale/autogenerated/**/*.js linguist-generated=true -merge
|
||||
javascript/ql/experimental/adaptivethreatmodeling/test/endpoint_large_scale/autogenerated/**/*.ts linguist-generated=true -merge
|
||||
|
||||
# Auto-generated modeling for Python
|
||||
python/ql/lib/semmle/python/frameworks/data/internal/subclass-capture/*.yml linguist-generated=true
|
||||
|
||||
|
||||
5
.github/labeler.yml
vendored
5
.github/labeler.yml
vendored
@@ -15,7 +15,7 @@ Java:
|
||||
- change-notes/**/*java.*
|
||||
|
||||
JS:
|
||||
- any: [ 'javascript/**/*', '!javascript/ql/experimental/adaptivethreatmodeling/**/*' ]
|
||||
- any: [ 'javascript/**/*' ]
|
||||
- change-notes/**/*javascript*
|
||||
|
||||
Kotlin:
|
||||
@@ -46,6 +46,3 @@ documentation:
|
||||
# Since these are all shared files that need to be synced, just pick _one_ copy of each.
|
||||
"DataFlow Library":
|
||||
- "shared/dataflow/**/*"
|
||||
|
||||
"ATM":
|
||||
- javascript/ql/experimental/adaptivethreatmodeling/**/*
|
||||
|
||||
@@ -12,9 +12,6 @@
|
||||
/java/ql/test-kotlin1/ @github/codeql-kotlin
|
||||
/java/ql/test-kotlin2/ @github/codeql-kotlin
|
||||
|
||||
# ML-powered queries
|
||||
/javascript/ql/experimental/adaptivethreatmodeling/ @github/codeql-ml-powered-queries-reviewers
|
||||
|
||||
# CodeQL tools and associated docs
|
||||
/docs/codeql/codeql-cli/ @github/codeql-cli-reviewers
|
||||
/docs/codeql/codeql-for-visual-studio-code/ @github/codeql-vscode-reviewers
|
||||
@@ -37,9 +34,7 @@ MODULE.bazel @github/codeql-ci-reviewers
|
||||
|
||||
# Workflows
|
||||
/.github/workflows/ @github/codeql-ci-reviewers
|
||||
/.github/workflows/atm-* @github/codeql-ml-powered-queries-reviewers
|
||||
/.github/workflows/go-* @github/codeql-go
|
||||
/.github/workflows/js-ml-tests.yml @github/codeql-ml-powered-queries-reviewers
|
||||
/.github/workflows/ql-for-ql-* @github/codeql-ql-for-ql-reviewers
|
||||
/.github/workflows/ruby-* @github/codeql-ruby
|
||||
/.github/workflows/swift.yml @github/codeql-swift
|
||||
|
||||
@@ -11,16 +11,6 @@ provide:
|
||||
- "cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml"
|
||||
- "go/ql/config/legacy-support/qlpack.yml"
|
||||
- "go/build/codeql-extractor-go/codeql-extractor.yml"
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml"
|
||||
# This pack is explicitly excluded from the workspace since most users
|
||||
# will want to use a version of this pack from the package cache. Internal
|
||||
# users can uncomment the following line and place a custom ML model
|
||||
# in the corresponding pack to test a custom ML model within their local
|
||||
# checkout.
|
||||
# - "javascript/ql/experimental/adaptivethreatmodeling/model/qlpack.yml"
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml"
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml"
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/test/qlpack.yml"
|
||||
- "csharp/ql/campaigns/Solorigate/lib/qlpack.yml"
|
||||
- "csharp/ql/campaigns/Solorigate/src/qlpack.yml"
|
||||
- "csharp/ql/campaigns/Solorigate/test/qlpack.yml"
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
# Adaptive Threat Modeling for JavaScript
|
||||
|
||||
This directory contains CodeQL libraries and queries that power adaptive threat modeling for JavaScript.
|
||||
All APIs are experimental and may change in the future.
|
||||
|
||||
Only internal users can run these queries directly. External users can run these queries when performing
|
||||
JavaScript analysis on Code Scanning. For more information, see
|
||||
[Code scanning finds more vulnerabilities using machine learning](https://github.blog/2022-02-17-code-scanning-finds-vulnerabilities-using-machine-learning/).
|
||||
@@ -1,168 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* Configures boosting for adaptive threat modeling (ATM).
|
||||
*/
|
||||
|
||||
private import javascript as JS
|
||||
import EndpointTypes
|
||||
import EndpointCharacteristics as EndpointCharacteristics
|
||||
import AdaptiveThreatModeling::ATM::ResultsInfo as AtmResultsInfo
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* A configuration class for defining known endpoints and endpoint filters for adaptive threat
|
||||
* modeling (ATM). Each boosted query must define its own extension of this abstract class.
|
||||
*
|
||||
* A configuration defines a set of known sources (`isKnownSource`) and sinks (`isKnownSink`).
|
||||
* It must also define a sink endpoint filter (`isEffectiveSink`) that filters candidate sinks
|
||||
* predicted by the machine learning model to a set of effective sinks.
|
||||
*
|
||||
* To get started with ATM, you can copy-paste an implementation of the relevant predicates from a
|
||||
* `DataFlow::Configuration` or `TaintTracking::Configuration` class for a standard security query.
|
||||
* For example, for SQL injection you can start by defining the `isKnownSource` and `isKnownSink`
|
||||
* predicates in the ATM configuration by copying and pasting the implementations of `isSource` and
|
||||
* `isSink` from `SqlInjection::Configuration`.
|
||||
*
|
||||
* Note that if the security query configuration defines additional edges beyond the standard data
|
||||
* flow edges, such as `NosqlInjection::Configuration`, you may need to replace the definition of
|
||||
* `isAdditionalFlowStep` with a more generalised definition of additional edges. See
|
||||
* `NosqlInjectionATM.qll` for an example of doing this.
|
||||
*/
|
||||
abstract class AtmConfig extends JS::TaintTracking::Configuration {
|
||||
bindingset[this]
|
||||
AtmConfig() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant taint source. When sources are not boosted, `isSource` is equivalent to
|
||||
* `isKnownSource` (i.e there are no "effective" sources to be classified by an ML model).
|
||||
*/
|
||||
override predicate isSource(JS::DataFlow::Node source) { this.isKnownSource(source) }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a known taint sink or an "effective" sink (a candidate to be classified by an ML model).
|
||||
*/
|
||||
override predicate isSink(JS::DataFlow::Node sink) {
|
||||
this.isKnownSink(sink) or this.isEffectiveSink(sink)
|
||||
}
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Holds if `source` is a known source of flow.
|
||||
*/
|
||||
predicate isKnownSource(JS::DataFlow::Node source) { none() }
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Holds if `sink` is a known sink of flow.
|
||||
*/
|
||||
final predicate isKnownSink(JS::DataFlow::Node sink) {
|
||||
// If the list of characteristics includes positive indicators with maximal confidence for this class, then it's a
|
||||
// known sink for the class.
|
||||
exists(EndpointCharacteristics::EndpointCharacteristic characteristic |
|
||||
characteristic.appliesToEndpoint(sink) and
|
||||
characteristic
|
||||
.hasImplications(this.getASinkEndpointType(), true, characteristic.maximalConfidence())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Holds if the candidate source `candidateSource` predicted by the machine learning model should be
|
||||
* an effective source, i.e. one considered as a possible source of flow in the boosted query.
|
||||
*/
|
||||
predicate isEffectiveSource(JS::DataFlow::Node candidateSource) { none() }
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Holds if the candidate sink `candidateSink` predicted by the machine learning model should be
|
||||
* an effective sink, i.e. one considered as a possible sink of flow in the boosted query.
|
||||
*/
|
||||
predicate isEffectiveSink(JS::DataFlow::Node candidateSink) {
|
||||
not exists(this.getAReasonSinkExcluded(candidateSink))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of characteristics that cause `candidateSink` to be excluded as an effective sink.
|
||||
*/
|
||||
final EndpointCharacteristics::EndpointCharacteristic getAReasonSinkExcluded(
|
||||
JS::DataFlow::Node candidateSink
|
||||
) {
|
||||
// An endpoint is an effective sink (sink candidate) if none of its characteristics give much indication whether or
|
||||
// not it is a sink. Historically, we used endpoint filters, and scored endpoints that are filtered out neither by
|
||||
// a standard endpoint filter nor by an endpoint filter specific to this sink type. To replicate this behavior, we
|
||||
// have given the endpoint filter characteristics medium confidence, and we exclude endpoints that have a
|
||||
// medium-confidence characteristic that indicates that they are not sinks, either in general or for this sink type.
|
||||
exists(EndpointCharacteristics::EndpointCharacteristic filter, float confidence |
|
||||
filter.appliesToEndpoint(candidateSink) and
|
||||
confidence >= filter.mediumConfidence() and
|
||||
// TODO: Experiment with excluding all endpoints that have a medium- or high-confidence characteristic that
|
||||
// implies they're not sinks, rather than using only medium-confidence characteristics, by deleting the following
|
||||
// line.
|
||||
confidence < filter.highConfidence() and
|
||||
(
|
||||
// Exclude endpoints that have a characteristic that implies they're not sinks for _any_ sink type.
|
||||
filter.hasImplications(any(NegativeType negative), true, confidence)
|
||||
or
|
||||
// Exclude endpoints that have a characteristic that implies they're not sinks for _this particular_ sink type.
|
||||
filter.hasImplications(this.getASinkEndpointType(), false, confidence)
|
||||
) and
|
||||
result = filter
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Get an endpoint type for the sources of this query. A query may have multiple applicable
|
||||
* endpoint types for its sources.
|
||||
*/
|
||||
EndpointType getASourceEndpointType() { none() }
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Get an endpoint type for the sinks of this query. A query may have multiple applicable
|
||||
* endpoint types for its sinks.
|
||||
*/
|
||||
abstract EndpointType getASinkEndpointType();
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Specifies the default cut-off value that controls how many alerts are produced.
|
||||
* The cut-off value must be in the range [0,1].
|
||||
* A cut-off value of 0 only produces alerts that are likely true-positives.
|
||||
* A cut-off value of 1 produces all alerts including those that are likely false-positives.
|
||||
*/
|
||||
float getScoreCutoff() { result = 0.0 }
|
||||
|
||||
/**
|
||||
* Holds if there's an ATM alert (a flow path from `source` to `sink` with ML-determined likelihood `score`) according
|
||||
* to this ML-boosted configuration, whereas the unboosted base query does not contain this source and sink
|
||||
* combination.
|
||||
*/
|
||||
predicate hasBoostedFlowPath(
|
||||
JS::DataFlow::PathNode source, JS::DataFlow::PathNode sink, float score
|
||||
) {
|
||||
this.hasFlowPath(source, sink) and
|
||||
not AtmResultsInfo::isFlowLikelyInBaseQuery(source.getNode(), sink.getNode()) and
|
||||
score = AtmResultsInfo::getScoreForFlow(source.getNode(), sink.getNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if if `sink` is an effective sink with flow from `source` which gets used as a sink candidate for scoring
|
||||
* with the ML model.
|
||||
*/
|
||||
predicate isSinkCandidateWithFlow(JS::DataFlow::PathNode sink) {
|
||||
exists(JS::DataFlow::PathNode source |
|
||||
this.hasFlowPath(source, sink) and
|
||||
not AtmResultsInfo::isFlowLikelyInBaseQuery(source.getNode(), sink.getNode())
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* Provides information about the results of boosted queries for use in adaptive threat modeling (ATM).
|
||||
*/
|
||||
|
||||
private import javascript::DataFlow as DataFlow
|
||||
import ATMConfig
|
||||
private import BaseScoring
|
||||
private import EndpointScoring as EndpointScoring
|
||||
|
||||
module ATM {
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* This module contains informational predicates about the results returned by adaptive threat
|
||||
* modeling (ATM).
|
||||
*/
|
||||
module ResultsInfo {
|
||||
/**
|
||||
* Indicates whether the flow from source to sink represents a result with
|
||||
* sufficiently high likelihood of being a true-positive.
|
||||
*/
|
||||
pragma[inline]
|
||||
private predicate shouldResultBeIncluded(DataFlow::Node source, DataFlow::Node sink) {
|
||||
any(ScoringResults results).shouldResultBeIncluded(source, sink)
|
||||
}
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Returns the score for the flow between the source `source` and the `sink` sink in the
|
||||
* boosted query.
|
||||
*/
|
||||
pragma[inline]
|
||||
float getScoreForFlow(DataFlow::Node source, DataFlow::Node sink) {
|
||||
any(DataFlow::Configuration cfg).hasFlow(source, sink) and
|
||||
shouldResultBeIncluded(source, sink) and
|
||||
result = unique(float s | s = any(ScoringResults results).getScoreForFlow(source, sink))
|
||||
}
|
||||
|
||||
/**
|
||||
* Pad a score returned from `getKnownScoreForFlow` to a particular length by adding a decimal
|
||||
* point if one does not already exist, and "0"s after that decimal point.
|
||||
*
|
||||
* Note that this predicate must itself define an upper bound on `length`, so that it has a
|
||||
* finite number of results. Currently this is defined as 12.
|
||||
*/
|
||||
private string paddedScore(float score, int length) {
|
||||
// In this definition, we must restrict the values that `length` and `score` can take on so
|
||||
// that the predicate has a finite number of results.
|
||||
(score = getScoreForFlow(_, _) or score = 0) and
|
||||
length = result.length() and
|
||||
(
|
||||
// We need to make sure the padded score contains a "." so lexically sorting the padded
|
||||
// scores is equivalent to numerically sorting the scores.
|
||||
score.toString().charAt(_) = "." and
|
||||
result = score.toString()
|
||||
or
|
||||
not score.toString().charAt(_) = "." and
|
||||
result = score.toString() + "."
|
||||
)
|
||||
or
|
||||
result = paddedScore(score, length - 1) + "0" and
|
||||
length <= 12
|
||||
}
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Return a string representing the score of the flow between `source` and `sink` in the
|
||||
* boosted query.
|
||||
*
|
||||
* The returned string is a fixed length, such that lexically sorting the strings returned by
|
||||
* this predicate gives the same sort order as numerically sorting the scores of the flows.
|
||||
*/
|
||||
pragma[inline]
|
||||
string getScoreStringForFlow(DataFlow::Node source, DataFlow::Node sink) {
|
||||
exists(float score |
|
||||
score = getScoreForFlow(source, sink) and
|
||||
(
|
||||
// A length of 12 is equivalent to 10 decimal places.
|
||||
score.toString().length() >= 12 and
|
||||
result = score.toString().substring(0, 12)
|
||||
or
|
||||
score.toString().length() < 12 and
|
||||
result = paddedScore(score, 12)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Indicates whether the flow from source to sink is likely to be reported by the base security
|
||||
* query.
|
||||
*
|
||||
* Currently this is a heuristic: it ignores potential differences in the definitions of
|
||||
* additional flow steps.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate isFlowLikelyInBaseQuery(DataFlow::Node source, DataFlow::Node sink) {
|
||||
getCfg().isKnownSource(source) and getCfg().isKnownSink(sink)
|
||||
}
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Get additional information about why ATM included the flow from source to sink as an alert.
|
||||
*/
|
||||
pragma[inline]
|
||||
string getAdditionalAlertInfo(DataFlow::Node source, DataFlow::Node sink) {
|
||||
exists(string sourceOrigins, string sinkOrigins |
|
||||
sourceOrigins = concat(any(ScoringResults results).getASourceOrigin(source), ", ") and
|
||||
sinkOrigins = concat(any(ScoringResults results).getASinkOrigin(sink), ", ") and
|
||||
result =
|
||||
"[Source origins: " +
|
||||
any(string s | if sourceOrigins != "" then s = sourceOrigins else s = "unknown") +
|
||||
"; sink origins: " +
|
||||
any(string s | if sinkOrigins != "" then s = sinkOrigins else s = "unknown") + "]"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* Provides shared scoring functionality for use in adaptive threat modeling (ATM).
|
||||
*/
|
||||
|
||||
private import javascript
|
||||
private import ATMConfig
|
||||
|
||||
external predicate availableMlModels(
|
||||
string modelChecksum, string modelLanguage, string modelName, string modelType
|
||||
);
|
||||
|
||||
/** Get the ATM configuration. */
|
||||
AtmConfig getCfg() { any() }
|
||||
|
||||
/**
|
||||
* A string containing scoring information produced by a scoring model.
|
||||
*
|
||||
* Scoring models include embedding models and endpoint scoring models.
|
||||
*/
|
||||
abstract class ScoringResults extends string {
|
||||
bindingset[this]
|
||||
ScoringResults() { any() }
|
||||
|
||||
/**
|
||||
* Get ATM's confidence that a path between `source` and `sink` represents a security
|
||||
* vulnerability. This will be a number between 0.0 and 1.0.
|
||||
*/
|
||||
abstract float getScoreForFlow(DataFlow::Node source, DataFlow::Node sink);
|
||||
|
||||
/**
|
||||
* Get a string representing why ATM included the given source in the dataflow analysis.
|
||||
*
|
||||
* In general, there may be multiple reasons why ATM included the given source, in which case
|
||||
* this predicate should have multiple results.
|
||||
*/
|
||||
abstract string getASourceOrigin(DataFlow::Node source);
|
||||
|
||||
/**
|
||||
* Get a string representing why ATM included the given sink in the dataflow analysis.
|
||||
*
|
||||
* In general, there may be multiple reasons why ATM included the given sink, in which case this
|
||||
* predicate should have multiple results.
|
||||
*/
|
||||
abstract string getASinkOrigin(DataFlow::Node sink);
|
||||
|
||||
/**
|
||||
* Indicates whether the flow from source to sink represents a result with
|
||||
* sufficiently high likelihood of being a true-positive.
|
||||
*/
|
||||
pragma[inline]
|
||||
abstract predicate shouldResultBeIncluded(DataFlow::Node source, DataFlow::Node sink);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,676 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* Extracts data about the database for use in adaptive threat modeling (ATM).
|
||||
*/
|
||||
|
||||
import javascript
|
||||
private import FeaturizationConfig
|
||||
private import FunctionBodyFeatures as FunctionBodyFeatures
|
||||
|
||||
/**
|
||||
* Gets the value of the token-based feature named `featureName` for the endpoint `endpoint`.
|
||||
*
|
||||
* This is a single string containing a space-separated list of tokens.
|
||||
*/
|
||||
private string getTokenFeature(DataFlow::Node endpoint, string featureName) {
|
||||
// Performance optimization: Restrict feature extraction to endpoints we've explicitly asked to featurize.
|
||||
endpoint = any(FeaturizationConfig cfg).getAnEndpointToFeaturize() and
|
||||
exists(EndpointFeature f | f.getName() = featureName and result = f.getValue(endpoint)) and
|
||||
featureName = getASupportedFeatureName()
|
||||
}
|
||||
|
||||
private module FunctionNames {
|
||||
/**
|
||||
* Get the name of the function.
|
||||
*
|
||||
* We attempt to assign unnamed entities approximate names if they are passed to a likely
|
||||
* external library function. If we can't assign them an approximate name, we give them the name
|
||||
* `""`, so that these entities are included in `AdaptiveThreatModeling.qll`.
|
||||
*
|
||||
* For entities which have multiple names, we choose the lexically smallest name.
|
||||
*/
|
||||
string getNameToFeaturize(Function function) {
|
||||
if exists(function.getName())
|
||||
then result = min(function.getName())
|
||||
else
|
||||
if exists(getApproximateNameForFunction(function))
|
||||
then result = getApproximateNameForFunction(function)
|
||||
else result = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call `call` has `function` is its `argumentIndex`th argument.
|
||||
*/
|
||||
private predicate functionUsedAsArgumentToCall(
|
||||
Function function, DataFlow::CallNode call, int argumentIndex
|
||||
) {
|
||||
DataFlow::localFlowStep*(call.getArgument(argumentIndex), function.flow())
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a generated name for the function. This name is generated such that
|
||||
* entities with the same names have similar behavior.
|
||||
*/
|
||||
private string getApproximateNameForFunction(Function function) {
|
||||
count(DataFlow::CallNode call, int index | functionUsedAsArgumentToCall(function, call, index)) =
|
||||
1 and
|
||||
exists(DataFlow::CallNode call, string basePart |
|
||||
functionUsedAsArgumentToCall(function, call, _) and
|
||||
(
|
||||
if count(getReceiverName(call)) = 1
|
||||
then basePart = getReceiverName(call) + "."
|
||||
else basePart = ""
|
||||
) and
|
||||
result = basePart + call.getCalleeName() + "#functionalargument"
|
||||
)
|
||||
}
|
||||
|
||||
private string getReceiverName(DataFlow::CallNode call) {
|
||||
result = call.getReceiver().asExpr().(VarAccess).getName()
|
||||
}
|
||||
}
|
||||
|
||||
/** Get a name of a supported generic token-based feature. */
|
||||
string getASupportedFeatureName() { result = any(EndpointFeature f).getName() }
|
||||
|
||||
/**
|
||||
* Generic token-based features for ATM.
|
||||
*
|
||||
* This predicate holds if the generic token-based feature named `featureName` has the value
|
||||
* `featureValue` for the endpoint `endpoint`.
|
||||
*/
|
||||
predicate tokenFeatures(DataFlow::Node endpoint, string featureName, string featureValue) {
|
||||
// Performance optimization: Restrict feature extraction to endpoints we've explicitly asked to featurize.
|
||||
endpoint = any(FeaturizationConfig cfg).getAnEndpointToFeaturize() and
|
||||
featureValue = getTokenFeature(endpoint, featureName)
|
||||
}
|
||||
|
||||
/**
|
||||
* See EndpointFeature
|
||||
*/
|
||||
private newtype TEndpointFeature =
|
||||
TEnclosingFunctionName() or
|
||||
TReceiverName() or
|
||||
TEnclosingFunctionBody() or
|
||||
TFileImports() or
|
||||
TCalleeImports() or
|
||||
TCalleeFlexibleAccessPath() or
|
||||
TInputAccessPathFromCallee() or
|
||||
TInputArgumentIndex() or
|
||||
TContextFunctionInterfaces() or
|
||||
TContextSurroundingFunctionParameters() or
|
||||
TAssignedToPropName() or
|
||||
TStringConcatenatedWith()
|
||||
|
||||
/**
|
||||
* An implementation of an endpoint feature: defines feature-name/value tuples for use in ML.
|
||||
*/
|
||||
abstract class EndpointFeature extends TEndpointFeature {
|
||||
/**
|
||||
* Gets the name of the feature. Used by the ML model.
|
||||
* Names are coupled to models: changing the name of a feature requires retraining the model.
|
||||
*/
|
||||
abstract string getName();
|
||||
|
||||
/**
|
||||
* Gets the value of the feature. Used by the ML model.
|
||||
* Models are trained based on feature values, so changing the value of a feature requires retraining the model.
|
||||
*/
|
||||
abstract string getValue(DataFlow::Node endpoint);
|
||||
|
||||
string toString() { result = this.getName() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The feature for the name of the function that encloses the endpoint.
|
||||
*/
|
||||
class EnclosingFunctionName extends EndpointFeature, TEnclosingFunctionName {
|
||||
override string getName() { result = "enclosingFunctionName" }
|
||||
|
||||
override string getValue(DataFlow::Node endpoint) {
|
||||
result =
|
||||
FunctionNames::getNameToFeaturize(FunctionBodyFeatures::getRepresentativeFunctionForEndpoint(endpoint))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The feature for the name of the receiver of the call, e.g. in a call `Artist.findOne(...)`, this is `Artist`.
|
||||
*/
|
||||
class ReceiverName extends EndpointFeature, TReceiverName {
|
||||
override string getName() { result = "receiverName" }
|
||||
|
||||
override string getValue(DataFlow::Node endpoint) {
|
||||
result =
|
||||
strictconcat(DataFlow::CallNode call, string component |
|
||||
endpoint = call.getAnArgument() and
|
||||
component = call.getReceiver().asExpr().(VarRef).getName()
|
||||
|
|
||||
component, " "
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The feature for the natural language tokens from the function that encloses the endpoint in
|
||||
* the order that they appear in the source code.
|
||||
*/
|
||||
class EnclosingFunctionBody extends EndpointFeature, TEnclosingFunctionBody {
|
||||
override string getName() { result = "enclosingFunctionBody" }
|
||||
|
||||
override string getValue(DataFlow::Node endpoint) {
|
||||
endpoint = any(FeaturizationConfig cfg).getAnEndpointToFeaturize() and
|
||||
result =
|
||||
FunctionBodyFeatures::getBodyTokensFeature(FunctionBodyFeatures::getRepresentativeFunctionForEndpoint(endpoint))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The feature for the imports defined in the file containing an endpoint.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```javascript
|
||||
* import { findOne } from 'mongoose';
|
||||
* import * as _ from 'lodash';
|
||||
* const pg = require('pg');
|
||||
*
|
||||
* // ...
|
||||
* ```
|
||||
*
|
||||
* In this file, all endpoints will have the value `lodash mongoose pg` for the feature `fileImports`.
|
||||
*/
|
||||
class FileImports extends EndpointFeature, TFileImports {
|
||||
override string getName() { result = "fileImports" }
|
||||
|
||||
override string getValue(DataFlow::Node endpoint) {
|
||||
result = SyntacticUtilities::getImportPathsForFile(endpoint.getFile())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The feature for the function parameters of the functions that enclose an endpoint.
|
||||
*
|
||||
* ### Example
|
||||
* ```javascript
|
||||
* function f(a, b) {
|
||||
* // ...
|
||||
* const g = (c, d) => x.foo(endpoint);
|
||||
* // ^^^^^^^^
|
||||
* }
|
||||
* ```
|
||||
* In the above example, the feature for the marked endpoint has value '(a, b)\n(c, d)'.
|
||||
* The line breaks act as a separator between the parameters of different functions but
|
||||
* will be treated by tokenization as if they were spaces.
|
||||
*/
|
||||
class ContextSurroundingFunctionParameters extends EndpointFeature,
|
||||
TContextSurroundingFunctionParameters
|
||||
{
|
||||
override string getName() { result = "contextSurroundingFunctionParameters" }
|
||||
|
||||
Function getRelevantFunction(DataFlow::Node endpoint) {
|
||||
result = endpoint.asExpr().getEnclosingFunction*()
|
||||
}
|
||||
|
||||
override string getValue(DataFlow::Node endpoint) {
|
||||
result =
|
||||
concat(string functionParameterLine, Function f |
|
||||
f = this.getRelevantFunction(endpoint) and
|
||||
functionParameterLine = SyntacticUtilities::getFunctionParametersFeatureComponent(f)
|
||||
|
|
||||
functionParameterLine, "\n"
|
||||
order by
|
||||
f.getLocation().getStartLine(), f.getLocation().getStartColumn()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The feature that gives the name of any properties an endpoint is assigned to (if any).
|
||||
*
|
||||
* ### Example
|
||||
* ```javascript
|
||||
* const div = document.createElement('div');
|
||||
* div.innerHTML = endpoint; // feature value is 'innerHTML'
|
||||
*
|
||||
* foo({x: endpoint}); // feature value is 'x'
|
||||
* ```
|
||||
*/
|
||||
class AssignedToPropName extends EndpointFeature, TAssignedToPropName {
|
||||
override string getName() { result = "assignedToPropName" }
|
||||
|
||||
override string getValue(DataFlow::Node endpoint) {
|
||||
exists(DataFlow::PropWrite w | w.getRhs().asExpr().getUnderlyingValue().flow() = endpoint |
|
||||
result = w.getPropertyName()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The feature that shows the text an endpoint is being concatenated with.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```javascript
|
||||
* const x = 'foo' + endpoint + 'bar'; // feature value is `'foo' -endpoint- 'bar'
|
||||
* ```
|
||||
*/
|
||||
class StringConcatenatedWith extends EndpointFeature, TStringConcatenatedWith {
|
||||
override string getName() { result = "stringConcatenatedWith" }
|
||||
|
||||
override string getValue(DataFlow::Node endpoint) {
|
||||
exists(StringOps::ConcatenationRoot root |
|
||||
root.getALeaf() = endpoint and
|
||||
result =
|
||||
concat(StringOps::ConcatenationLeaf p |
|
||||
p.getRoot() = root and
|
||||
(
|
||||
p.getStartLine() < endpoint.getStartLine()
|
||||
or
|
||||
p.getStartLine() = endpoint.getStartLine() and
|
||||
p.getStartColumn() < endpoint.getStartColumn()
|
||||
)
|
||||
|
|
||||
SyntacticUtilities::renderStringConcatOperand(p), " + "
|
||||
order by
|
||||
p.getStartLine(), p.getStartColumn()
|
||||
) + " -endpoint- " +
|
||||
concat(StringOps::ConcatenationLeaf p |
|
||||
p.getRoot() = root and
|
||||
(
|
||||
p.getStartLine() > endpoint.getStartLine()
|
||||
or
|
||||
p.getStartLine() = endpoint.getStartLine() and
|
||||
p.getStartColumn() > endpoint.getStartColumn()
|
||||
)
|
||||
|
|
||||
SyntacticUtilities::renderStringConcatOperand(p), " + "
|
||||
order by
|
||||
p.getStartLine(), p.getStartColumn()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The feature for the imports used in the callee of an invocation.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```javascript
|
||||
* import * as _ from 'lodash';
|
||||
*
|
||||
* // ...
|
||||
* _.deepClone(someObject);
|
||||
* // ^^^^^^^^^^ will have the value `lodash` for the feature `calleeImports`.
|
||||
* ```
|
||||
*/
|
||||
class CalleeImports extends EndpointFeature, TCalleeImports {
|
||||
override string getName() { result = "calleeImports" }
|
||||
|
||||
override string getValue(DataFlow::Node endpoint) {
|
||||
not result = SyntacticUtilities::getUnknownSymbol() and
|
||||
exists(DataFlow::InvokeNode invk |
|
||||
(
|
||||
invk.getAnArgument() = endpoint or
|
||||
SyntacticUtilities::getANestedInitializerValue(invk.getAnArgument()
|
||||
.asExpr()
|
||||
.getUnderlyingValue()).flow() = endpoint
|
||||
) and
|
||||
result =
|
||||
concat(string importPath |
|
||||
importPath = SyntacticUtilities::getCalleeImportPath(invk.getCalleeNode())
|
||||
|
|
||||
importPath, " " order by importPath
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The feature for the interfaces of all named functions in the same file as the endpoint.
|
||||
*
|
||||
* ### Example
|
||||
* ```javascript
|
||||
* // Will return: "f(a, b, c)\ng(x, y, z)\nh(u, v)" for this file.
|
||||
* function f(a, b, c) { ... }
|
||||
*
|
||||
* function g(x, y, z) {
|
||||
* function h(u, v) { ... }
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class ContextFunctionInterfaces extends EndpointFeature, TContextFunctionInterfaces {
|
||||
override string getName() { result = "contextFunctionInterfaces" }
|
||||
|
||||
override string getValue(DataFlow::Node endpoint) {
|
||||
result = SyntacticUtilities::getFunctionInterfacesForFile(endpoint.getFile())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntactic utilities for feature value computation.
|
||||
*/
|
||||
private module SyntacticUtilities {
|
||||
/**
|
||||
* Renders an operand in a string concatenation by surrounding a constant in quotes, and
|
||||
* by using `getSimpleAccessPath` for everything else.
|
||||
*/
|
||||
string renderStringConcatOperand(DataFlow::Node operand) {
|
||||
if exists(unique(string v | operand.mayHaveStringValue(v)))
|
||||
then result = "'" + any(string v | operand.mayHaveStringValue(v)) + "'"
|
||||
else result = getSimpleAccessPath(operand)
|
||||
}
|
||||
|
||||
/** Gets all the imports defined in the file containing the endpoint. */
|
||||
string getImportPathsForFile(File file) {
|
||||
result =
|
||||
concat(string importPath |
|
||||
importPath = SyntacticUtilities::getImportPathForFile(file)
|
||||
|
|
||||
importPath, " " order by importPath
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets an import located in `file`. */
|
||||
string getImportPathForFile(File file) {
|
||||
result = any(Import imp | imp.getFile() = file).getImportedPath().getValue()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the feature component for the parameters of a function.
|
||||
*
|
||||
* ```javascript
|
||||
* function f(a, b, c) { // will return "(a, b, c)" for this function
|
||||
* return a + b + c;
|
||||
* }
|
||||
*
|
||||
* async function g(a) { // will return "(a)" for this function
|
||||
* return 2*a
|
||||
* };
|
||||
*
|
||||
* const h = (b) => 3*b; // will return "(b)" for this function
|
||||
* ```
|
||||
*/
|
||||
string getFunctionParametersFeatureComponent(Function f) {
|
||||
result =
|
||||
"(" +
|
||||
concat(string parameter, int i |
|
||||
parameter = getParameterNameOrUnknown(f.getParameter(i))
|
||||
|
|
||||
parameter, ", " order by i
|
||||
) + ")"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function interfaces of all named functions in a file, concatenated together.
|
||||
*
|
||||
* ```javascript
|
||||
* // Will return: "f(a, b, c)\ng(x, y, z)\nh(u, v)" for this file.
|
||||
* function f(a, b, c) { ... }
|
||||
*
|
||||
* function g(x, y, z) {
|
||||
* function h(u, v) { ... }
|
||||
* ...
|
||||
* }
|
||||
*/
|
||||
string getFunctionInterfacesForFile(File file) {
|
||||
result =
|
||||
concat(Function func, string line |
|
||||
func.getFile() = file and
|
||||
line = func.getName() + getFunctionParametersFeatureComponent(func)
|
||||
|
|
||||
line, "\n" order by line
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a property initializer value in an object literal or one of its nested object literals.
|
||||
*/
|
||||
Expr getANestedInitializerValue(ObjectExpr o) {
|
||||
exists(Expr init | init = o.getAProperty().getInit().getUnderlyingValue() |
|
||||
result = [init, getANestedInitializerValue(init)]
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a simple access path for how a callee can refer to a value that appears in an argument to a call.
|
||||
*
|
||||
* Supports:
|
||||
* - direct arguments
|
||||
* - properties of (nested) objects that are arguments
|
||||
*
|
||||
* Unknown cases and property names result in `?`.
|
||||
*/
|
||||
string getSimpleParameterAccessPath(DataFlow::Node node) {
|
||||
if exists(DataFlow::CallNode call | node = call.getArgument(_))
|
||||
then exists(DataFlow::CallNode call, int i | node = call.getArgument(i) | result = i + "")
|
||||
else result = getSimplePropertyAccessPath(node)
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a simple access path for how a user can refer to a value that appears in an (nested) object.
|
||||
*
|
||||
* Supports:
|
||||
* - properties of (nested) objects
|
||||
*
|
||||
* Unknown cases and property names result in `?`.
|
||||
*/
|
||||
string getSimplePropertyAccessPath(DataFlow::Node node) {
|
||||
if exists(ObjectExpr o | o.getAProperty().getInit().getUnderlyingValue() = node.asExpr())
|
||||
then
|
||||
exists(DataFlow::PropWrite w |
|
||||
w.getRhs() = node and
|
||||
result = getSimpleParameterAccessPath(w.getBase()) + "." + getPropertyNameOrUnknown(w)
|
||||
)
|
||||
else result = getUnknownSymbol()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the imported package path that this node depends on, if any.
|
||||
*
|
||||
* Otherwise, returns '?'.
|
||||
*
|
||||
* XXX Be careful with using this in your features, as it might teach the model
|
||||
* a fixed list of "dangerous" libraries that could lead to bad generalization.
|
||||
*/
|
||||
string getCalleeImportPath(DataFlow::Node node) {
|
||||
exists(DataFlow::Node src | src = node.getALocalSource() |
|
||||
if src instanceof DataFlow::ModuleImportNode
|
||||
then result = src.(DataFlow::ModuleImportNode).getPath()
|
||||
else
|
||||
if src instanceof DataFlow::PropRead
|
||||
then result = getCalleeImportPath(src.(DataFlow::PropRead).getBase())
|
||||
else
|
||||
if src instanceof DataFlow::InvokeNode
|
||||
then result = getCalleeImportPath(src.(DataFlow::InvokeNode).getCalleeNode())
|
||||
else
|
||||
if src.asExpr() instanceof AwaitExpr
|
||||
then result = getCalleeImportPath(src.asExpr().(AwaitExpr).getOperand().flow())
|
||||
else result = getUnknownSymbol()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a simple access path for a node.
|
||||
*
|
||||
* Supports:
|
||||
* - variable reads (including `this` and `super`)
|
||||
* - imports
|
||||
* - await
|
||||
* - property reads
|
||||
* - invocations
|
||||
*
|
||||
* Unknown cases and property names results in `?`.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* - The node `x.foo` will have the simple access path `x.foo`.
|
||||
* - In the following file, the simple access path will be `import("./foo").bar.baz`:
|
||||
*
|
||||
* ```javascript
|
||||
* import * as lib from "./foo"
|
||||
* console.log(lib.bar.baz());
|
||||
* // ^^^^^^^^^^^ node
|
||||
*/
|
||||
string getSimpleAccessPath(DataFlow::Node node) {
|
||||
exists(Expr e | e = node.asExpr().getUnderlyingValue() |
|
||||
if
|
||||
e instanceof SuperAccess or
|
||||
e instanceof ThisAccess or
|
||||
e instanceof VarAccess or
|
||||
e instanceof Import or
|
||||
e instanceof AwaitExpr or
|
||||
node instanceof DataFlow::PropRead or
|
||||
node instanceof DataFlow::InvokeNode
|
||||
then
|
||||
e instanceof SuperAccess and result = "super"
|
||||
or
|
||||
e instanceof ThisAccess and result = "this"
|
||||
or
|
||||
e instanceof VarAccess and result = e.(VarAccess).getName()
|
||||
or
|
||||
e instanceof Import and result = "import(" + getSimpleImportPath(e) + ")"
|
||||
or
|
||||
e instanceof AwaitExpr and
|
||||
result = "(await " + getSimpleAccessPath(e.(AwaitExpr).getOperand().flow()) + ")"
|
||||
or
|
||||
node instanceof DataFlow::PropRead and
|
||||
result =
|
||||
getSimpleAccessPath(node.(DataFlow::PropRead).getBase()) + "." +
|
||||
getPropertyNameOrUnknown(node)
|
||||
or
|
||||
(node instanceof DataFlow::InvokeNode and not e instanceof Import) and
|
||||
result = getSimpleAccessPath(node.(DataFlow::InvokeNode).getCalleeNode()) + "()"
|
||||
else result = getUnknownSymbol()
|
||||
)
|
||||
}
|
||||
|
||||
string getUnknownSymbol() { result = "?" }
|
||||
|
||||
/**
|
||||
* Gets the imported path.
|
||||
*
|
||||
* XXX To avoid teaching the ML model about npm packages, only relative paths are supported
|
||||
*
|
||||
* Unknown paths result in `?`.
|
||||
*/
|
||||
string getSimpleImportPath(Import i) {
|
||||
if exists(i.getImportedPath().getValue())
|
||||
then
|
||||
exists(string p | p = i.getImportedPath().getValue() |
|
||||
// Hide absolute imports from ML training data.
|
||||
// ============================================
|
||||
// There is the hypothesis that exposing absolute imports to the model
|
||||
// might lead to bad generalization. For example, the model might learn
|
||||
// to strongly associate a specific database client with sinks and no
|
||||
// longer be able to flag sinks when data flow is broken.
|
||||
// Placing this logic so deeply within the feature extraction code is
|
||||
// perhaps a bit of a hack and it is a use case to consider when refactoring
|
||||
// endpoint filters/data extraction.
|
||||
if p.matches(".%") then result = "\"p\"" else result = "!"
|
||||
)
|
||||
else result = getUnknownSymbol()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the property name of a property reference or `?` if it is unknown.
|
||||
*/
|
||||
string getPropertyNameOrUnknown(DataFlow::PropRef ref) {
|
||||
if exists(ref.getPropertyName())
|
||||
then result = ref.getPropertyName()
|
||||
else result = getUnknownSymbol()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the parameter name if it exists, or `?` if it is unknown.
|
||||
*/
|
||||
string getParameterNameOrUnknown(Parameter p) {
|
||||
if exists(p.getName()) then result = p.getName() else result = getUnknownSymbol()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The feature for the access path of the callee node of a call that has an argument that "contains" the endpoint.
|
||||
*
|
||||
* "Containment" is syntactic, and currently means that the endpoint is an argument to the call, or that the endpoint is a (nested) property value of an argument.
|
||||
*
|
||||
* Examples:
|
||||
* ```
|
||||
* foo(endpoint); // -> foo
|
||||
* foo.bar(endpoint); // -> foo.bar
|
||||
* foo.bar({ baz: endpoint }); // -> foo.bar
|
||||
* this.foo.bar(endpoint); // -> this.foo.bar
|
||||
* foo[complex()].bar(endpoint); // -> foo.?.bar
|
||||
* ```
|
||||
*/
|
||||
class CalleeFlexibleAccessPath extends EndpointFeature, TCalleeFlexibleAccessPath {
|
||||
override string getName() { result = "CalleeFlexibleAccessPath" }
|
||||
|
||||
override string getValue(DataFlow::Node endpoint) {
|
||||
exists(DataFlow::InvokeNode invk |
|
||||
result = SyntacticUtilities::getSimpleAccessPath(invk.getCalleeNode()) and
|
||||
// ignore the unknown path
|
||||
not result = SyntacticUtilities::getUnknownSymbol() and
|
||||
(
|
||||
invk.getAnArgument() = endpoint or
|
||||
SyntacticUtilities::getANestedInitializerValue(invk.getAnArgument()
|
||||
.asExpr()
|
||||
.getUnderlyingValue()).flow() = endpoint
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The feature for how a callee can refer to a the endpoint that is "contained" in some argument to a call
|
||||
*
|
||||
* "Containment" is syntactic, and currently means that the endpoint is an argument to the call, or that the endpoint is a (nested) property value of an argument.
|
||||
*
|
||||
* Examples:
|
||||
* ```
|
||||
* foo({ bar: endpoint }); // -> bar
|
||||
* foo(x, { bar: { baz: endpoint } }); // -> bar.baz
|
||||
* ```
|
||||
*/
|
||||
class InputAccessPathFromCallee extends EndpointFeature, TInputAccessPathFromCallee {
|
||||
override string getName() { result = "InputAccessPathFromCallee" }
|
||||
|
||||
override string getValue(DataFlow::Node endpoint) {
|
||||
exists(DataFlow::InvokeNode invk |
|
||||
result = SyntacticUtilities::getSimpleParameterAccessPath(endpoint) and
|
||||
SyntacticUtilities::getANestedInitializerValue(invk.getAnArgument()
|
||||
.asExpr()
|
||||
.getUnderlyingValue()).flow() = endpoint
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The feature for how the index of an argument that "contains" and endpoint.
|
||||
*
|
||||
* "Containment" is syntactic, and currently means that the endpoint is an argument to the call, or that the endpoint is a (nested) property value of an argument.
|
||||
*
|
||||
* Examples:
|
||||
* ```
|
||||
* foo(endpoint); // -> 0
|
||||
* foo({ bar: endpoint }); // -> 0
|
||||
* foo(x, { bar: { baz: endpoint } }); // -> 1
|
||||
* ```
|
||||
*/
|
||||
class InputArgumentIndex extends EndpointFeature, TInputArgumentIndex {
|
||||
override string getName() { result = "InputArgumentIndex" }
|
||||
|
||||
override string getValue(DataFlow::Node endpoint) {
|
||||
exists(DataFlow::InvokeNode invk, DataFlow::Node arg, int i | arg = invk.getArgument(i) |
|
||||
result = i + "" and
|
||||
(
|
||||
invk.getArgument(i) = endpoint
|
||||
or
|
||||
SyntacticUtilities::getANestedInitializerValue(arg.asExpr().getUnderlyingValue()).flow() =
|
||||
endpoint
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* Provides an implementation of scoring alerts for use in adaptive threat modeling (ATM).
|
||||
*/
|
||||
|
||||
private import javascript
|
||||
private import BaseScoring
|
||||
private import EndpointFeatures as EndpointFeatures
|
||||
private import FeaturizationConfig
|
||||
private import EndpointTypes
|
||||
|
||||
private string getACompatibleModelChecksum() {
|
||||
availableMlModels(result, "javascript", _, "atm-endpoint-scoring")
|
||||
}
|
||||
|
||||
module ModelScoring {
|
||||
/**
|
||||
* A featurization config that only featurizes new candidate endpoints that are part of a flow
|
||||
* path.
|
||||
*/
|
||||
class RelevantFeaturizationConfig extends FeaturizationConfig {
|
||||
RelevantFeaturizationConfig() { this = "RelevantFeaturization" }
|
||||
|
||||
override DataFlow::Node getAnEndpointToFeaturize() {
|
||||
getCfg().isEffectiveSource(result) and any(DataFlow::Configuration cfg).hasFlow(result, _)
|
||||
or
|
||||
getCfg().isEffectiveSink(result) and any(DataFlow::Configuration cfg).hasFlow(_, result)
|
||||
}
|
||||
}
|
||||
|
||||
DataFlow::Node getARequestedEndpoint() {
|
||||
result = any(FeaturizationConfig cfg).getAnEndpointToFeaturize()
|
||||
}
|
||||
|
||||
private int getARequestedEndpointType() { result = any(EndpointType type).getEncoding() }
|
||||
|
||||
predicate endpointScores(DataFlow::Node endpoint, int encodedEndpointType, float score) =
|
||||
scoreEndpoints(getARequestedEndpoint/0, EndpointFeatures::tokenFeatures/3,
|
||||
EndpointFeatures::getASupportedFeatureName/0, getARequestedEndpointType/0,
|
||||
getACompatibleModelChecksum/0)(endpoint, encodedEndpointType, score)
|
||||
}
|
||||
|
||||
/**
|
||||
* Return ATM's confidence that `source` is a source for the given security query. This will be a
|
||||
* number between 0.0 and 1.0.
|
||||
*/
|
||||
private float getScoreForSource(DataFlow::Node source) {
|
||||
if getCfg().isKnownSource(source)
|
||||
then result = 1.0
|
||||
else (
|
||||
// This restriction on `source` has no semantic effect but improves performance.
|
||||
getCfg().isEffectiveSource(source) and
|
||||
ModelScoring::endpointScores(source, getCfg().getASourceEndpointType().getEncoding(), result)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Return ATM's confidence that `sink` is a sink for the given security query. This will be a
|
||||
* number between 0.0 and 1.0.
|
||||
*/
|
||||
private float getScoreForSink(DataFlow::Node sink) {
|
||||
if getCfg().isKnownSink(sink)
|
||||
then result = 1.0
|
||||
else (
|
||||
// This restriction on `sink` has no semantic effect but improves performance.
|
||||
getCfg().isEffectiveSink(sink) and
|
||||
ModelScoring::endpointScores(sink, getCfg().getASinkEndpointType().getEncoding(), result)
|
||||
)
|
||||
}
|
||||
|
||||
class EndpointScoringResults extends ScoringResults {
|
||||
EndpointScoringResults() {
|
||||
this = "EndpointScoringResults" and exists(getACompatibleModelChecksum())
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ATM's confidence that a path between `source` and `sink` represents a security
|
||||
* vulnerability. This will be a number between 0.0 and 1.0.
|
||||
*/
|
||||
override float getScoreForFlow(DataFlow::Node source, DataFlow::Node sink) {
|
||||
result = getScoreForSource(source) * getScoreForSink(sink)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string representing why ATM included the given source in the dataflow analysis.
|
||||
*
|
||||
* In general, there may be multiple reasons why ATM included the given source, in which case
|
||||
* this predicate should have multiple results.
|
||||
*/
|
||||
pragma[inline]
|
||||
override string getASourceOrigin(DataFlow::Node source) {
|
||||
result = "known" and getCfg().isKnownSource(source)
|
||||
or
|
||||
result = "predicted" and getCfg().isEffectiveSource(source)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string representing why ATM included the given sink in the dataflow analysis.
|
||||
*
|
||||
* In general, there may be multiple reasons why ATM included the given sink, in which case
|
||||
* this predicate should have multiple results.
|
||||
*/
|
||||
pragma[inline]
|
||||
override string getASinkOrigin(DataFlow::Node sink) {
|
||||
result = "known" and getCfg().isKnownSink(sink)
|
||||
or
|
||||
not getCfg().isKnownSink(sink) and
|
||||
result =
|
||||
"predicted (scores: " +
|
||||
concat(EndpointType type, float score |
|
||||
ModelScoring::endpointScores(sink, type.getEncoding(), score)
|
||||
|
|
||||
type.getDescription() + "=" + score.toString(), ", " order by type.getEncoding()
|
||||
) + ")" and
|
||||
getCfg().isEffectiveSink(sink)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
override predicate shouldResultBeIncluded(DataFlow::Node source, DataFlow::Node sink) {
|
||||
exists(source) and
|
||||
if getCfg().isKnownSink(sink)
|
||||
then any()
|
||||
else (
|
||||
// This restriction on `sink` has no semantic effect but improves performance.
|
||||
getCfg().isEffectiveSink(sink) and
|
||||
exists(float sinkScore |
|
||||
ModelScoring::endpointScores(sink, getCfg().getASinkEndpointType().getEncoding(), sinkScore) and
|
||||
// Include the endpoint if (a) the query endpoint type scores higher than all other
|
||||
// endpoint types, or (b) the query endpoint type scores at least
|
||||
// 0.5 - (getCfg().getScoreCutoff() / 2).
|
||||
sinkScore >=
|
||||
[
|
||||
max(float s | ModelScoring::endpointScores(sink, _, s)),
|
||||
0.5 - getCfg().getScoreCutoff() / 2
|
||||
]
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module Debugging {
|
||||
query predicate hopInputEndpoints(DataFlow::Node endpoint) {
|
||||
endpoint = ModelScoring::getARequestedEndpoint()
|
||||
}
|
||||
|
||||
query predicate endpointScores = ModelScoring::endpointScores/3;
|
||||
|
||||
query predicate shouldResultBeIncluded(DataFlow::Node source, DataFlow::Node sink) {
|
||||
any(ScoringResults scoringResults).shouldResultBeIncluded(source, sink) and
|
||||
any(DataFlow::Configuration cfg).hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* Defines the set of classes that endpoint scoring models can predict. Endpoint scoring models must
|
||||
* only predict classes defined within this file. This file is the source of truth for the integer
|
||||
* representation of each of these classes.
|
||||
*/
|
||||
newtype TEndpointType =
|
||||
TNegativeType() or
|
||||
TXssSinkType() or
|
||||
TNosqlInjectionSinkType() or
|
||||
TSqlInjectionSinkType() or
|
||||
TTaintedPathSinkType() or
|
||||
TShellCommandInjectionFromEnvironmentSinkType()
|
||||
|
||||
/** A class that can be predicted by endpoint scoring models. */
|
||||
abstract class EndpointType extends TEndpointType {
|
||||
abstract string getDescription();
|
||||
|
||||
/**
|
||||
* Gets the integer representation of this endpoint type. This integer representation specifies the class number
|
||||
* used by the endpoint scoring model (the classifier) to represent this endpoint type. Class 0 is the negative
|
||||
* class (non-sink). Each positive int corresponds to a single sink type.
|
||||
*/
|
||||
abstract int getEncoding();
|
||||
|
||||
string toString() { result = this.getDescription() }
|
||||
}
|
||||
|
||||
/** The `Negative` class that can be predicted by endpoint scoring models. */
|
||||
class NegativeType extends EndpointType, TNegativeType {
|
||||
override string getDescription() { result = "Negative" }
|
||||
|
||||
override int getEncoding() { result = 0 }
|
||||
}
|
||||
|
||||
/** The `XssSink` class that can be predicted by endpoint scoring models. */
|
||||
class XssSinkType extends EndpointType, TXssSinkType {
|
||||
override string getDescription() { result = "XssSink" }
|
||||
|
||||
override int getEncoding() { result = 1 }
|
||||
}
|
||||
|
||||
/** The `NosqlInjectionSink` class that can be predicted by endpoint scoring models. */
|
||||
class NosqlInjectionSinkType extends EndpointType, TNosqlInjectionSinkType {
|
||||
override string getDescription() { result = "NosqlInjectionSink" }
|
||||
|
||||
override int getEncoding() { result = 2 }
|
||||
}
|
||||
|
||||
/** The `SqlInjectionSink` class that can be predicted by endpoint scoring models. */
|
||||
class SqlInjectionSinkType extends EndpointType, TSqlInjectionSinkType {
|
||||
override string getDescription() { result = "SqlInjectionSink" }
|
||||
|
||||
override int getEncoding() { result = 3 }
|
||||
}
|
||||
|
||||
/** The `TaintedPathSink` class that can be predicted by endpoint scoring models. */
|
||||
class TaintedPathSinkType extends EndpointType, TTaintedPathSinkType {
|
||||
override string getDescription() { result = "TaintedPathSink" }
|
||||
|
||||
override int getEncoding() { result = 4 }
|
||||
}
|
||||
|
||||
/** The `ShellCommandInjectionFromEnvironmentSink` class that can be predicted by endpoint scoring models. */
|
||||
class ShellCommandInjectionFromEnvironmentSinkType extends EndpointType,
|
||||
TShellCommandInjectionFromEnvironmentSinkType
|
||||
{
|
||||
override string getDescription() { result = "ShellCommandInjectionFromEnvironmentSink" }
|
||||
|
||||
override int getEncoding() { result = 5 }
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import javascript
|
||||
|
||||
/**
|
||||
* A configuration that defines which endpoints should be featurized.
|
||||
*
|
||||
* This is used as a performance optimization to ensure that we only featurize the endpoints we need
|
||||
* to featurize.
|
||||
*/
|
||||
abstract class FeaturizationConfig extends string {
|
||||
bindingset[this]
|
||||
FeaturizationConfig() { any() }
|
||||
|
||||
abstract DataFlow::Node getAnEndpointToFeaturize();
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
/**
|
||||
* FunctionBodyFeatures.qll
|
||||
*
|
||||
* Contains logic relating to the `enclosingFunctionBody` and `enclosingFunctionName` features.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
private import FeaturizationConfig
|
||||
|
||||
/**
|
||||
* Gets a tokenized representation of the AST node for use in the `enclosingFunctionBody` feature.
|
||||
*/
|
||||
string getTokenizedAstNode(AstNode node) {
|
||||
// e.g. `x` -> "x"
|
||||
result = node.(Identifier).getName()
|
||||
or
|
||||
// Computed property accesses for which we can predetermine the property being accessed.
|
||||
// e.g. we'll featurize the `["date"]` part of `response["date"]` as `date`
|
||||
result = node.(IndexExpr).getPropertyName()
|
||||
or
|
||||
// We use `getRawValue` to give us distinct representations for `0xa`, `0xA`, and `10`.
|
||||
// e.g. `0xa` -> "0xa", `0xA` -> "0xA", `10` -> "10"
|
||||
result = node.(NumberLiteral).getRawValue()
|
||||
or
|
||||
// We use `getValue` rather than `getRawValue` so we assign `"a"` and `'a'` the same
|
||||
// representation.
|
||||
// e.g. `"a"` -> "a", `'a'` -> "a", `true` -> "true"
|
||||
not node instanceof NumberLiteral and
|
||||
result = node.(Literal).getValue()
|
||||
or
|
||||
// e.g. we'll featurize the `Hello ` and `!` parts of ``Hello ${user.name}!`` to "Hello " and "!"
|
||||
// respectively
|
||||
result = node.(TemplateElement).getRawValue()
|
||||
}
|
||||
|
||||
/** Gets an AST node within the function `f` that we should featurize. */
|
||||
pragma[inline]
|
||||
AstNode getAnAstNodeToFeaturize(Function f) {
|
||||
result.getParent*() = f and
|
||||
// Don't featurize the function name as part of the function body tokens
|
||||
not result = f.getIdentifier()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a function that contains the endpoint.
|
||||
*
|
||||
* This can have multiple results, since functions can be nested in JavaScript. The predicate
|
||||
* `getRepresentativeFunctionForEndpoint` selects a single result from this predicate to use to
|
||||
* construct the `enclosingFunctionBody` feature for that endpoint. Generally you will want to use
|
||||
* `getRepresentativeFunctionForEndpoint` instead of this predicate.
|
||||
*/
|
||||
private Function getAFunctionForEndpoint(DataFlow::Node endpoint) {
|
||||
// Performance optimization: Restrict the set of endpoints to the endpoints to featurize.
|
||||
endpoint = any(FeaturizationConfig cfg).getAnEndpointToFeaturize() and
|
||||
result = endpoint.getContainer().getEnclosingContainer*()
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum number of AST nodes an function containing an endpoint should have before we should
|
||||
* choose a smaller function to represent the endpoint.
|
||||
*
|
||||
* This is intended to represent a balance in terms of the amount of context we provide to the
|
||||
* model: we don't want the function to be too small, because then it doesn't contain very much
|
||||
* context and miss useful information, but also we don't want it to be too large, because then
|
||||
* there's likely to be a lot of irrelevant or very loosely related context.
|
||||
*/
|
||||
private int getMaxNumAstNodes() { result = 1024 }
|
||||
|
||||
/**
|
||||
* Returns the number of AST nodes contained within the specified function.
|
||||
*/
|
||||
private int getNumAstNodesInFunction(Function function) {
|
||||
// Restrict the values `function` can take on
|
||||
function = getAFunctionForEndpoint(_) and
|
||||
result = count(getAnAstNodeToFeaturize(function))
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the enclosing function for an endpoint.
|
||||
*
|
||||
* This is used to compute the `enclosingFunctionBody` and `enclosingFunctionName` features.
|
||||
*
|
||||
* We try to use the largest function containing the endpoint that's below the AST node limit
|
||||
* defined in `getMaxNumAstNodes`. In the event of a tie, we use the function that appears first
|
||||
* within the source code.
|
||||
*
|
||||
* If no functions are smaller than the AST node limit, then we use the smallest function containing
|
||||
* the endpoint.
|
||||
*/
|
||||
Function getRepresentativeFunctionForEndpoint(DataFlow::Node endpoint) {
|
||||
// Check whether there's a function containing the endpoint that's smaller than the AST node
|
||||
// limit.
|
||||
if getNumAstNodesInFunction(getAFunctionForEndpoint(endpoint)) <= getMaxNumAstNodes()
|
||||
then
|
||||
// Use the largest function smaller than the AST node limit, resolving ties using the function
|
||||
// that appears first in the source code.
|
||||
result =
|
||||
min(Function function, int numAstNodes, Location l |
|
||||
function = getAFunctionForEndpoint(endpoint) and
|
||||
numAstNodes = getNumAstNodesInFunction(function) and
|
||||
numAstNodes <= getMaxNumAstNodes() and
|
||||
l = function.getLocation()
|
||||
|
|
||||
function
|
||||
order by
|
||||
numAstNodes desc, l.getStartLine(), l.getStartColumn(), l.getEndLine(), l.getEndColumn()
|
||||
)
|
||||
else
|
||||
// Use the smallest function, resolving ties using the function that appears first in the source
|
||||
// code.
|
||||
result =
|
||||
min(Function function, int numAstNodes, Location l |
|
||||
function = getAFunctionForEndpoint(endpoint) and
|
||||
numAstNodes = getNumAstNodesInFunction(function) and
|
||||
l = function.getLocation()
|
||||
|
|
||||
function
|
||||
order by
|
||||
numAstNodes, l.getStartLine(), l.getStartColumn(), l.getEndLine(), l.getEndColumn()
|
||||
)
|
||||
}
|
||||
|
||||
/** Returns an AST node within the function `f` that an associated token feature. */
|
||||
AstNode getAnAstNodeWithAFeature(Function f) {
|
||||
// Performance optimization: Restrict the set of functions to those containing an endpoint to featurize.
|
||||
f = getRepresentativeFunctionForEndpoint(any(FeaturizationConfig cfg).getAnEndpointToFeaturize()) and
|
||||
result = getAnAstNodeToFeaturize(f)
|
||||
}
|
||||
|
||||
/** Returns the number of source-code characters in a function. */
|
||||
int getNumCharsInFunction(Function f) {
|
||||
result =
|
||||
strictsum(AstNode node | node = getAnAstNodeWithAFeature(f) | getTokenizedAstNode(node).length())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum number of characters a feature can be.
|
||||
* The evaluator string limit is 5395415 characters. We choose a limit lower than this.
|
||||
*/
|
||||
private int getMaxChars() { result = 1000000 }
|
||||
|
||||
/**
|
||||
* Returns a featurized representation of the function that can be used to populate the
|
||||
* `enclosingFunctionBody` feature for an endpoint.
|
||||
*/
|
||||
string getBodyTokensFeature(Function function) {
|
||||
// Performance optimization: If a function has more than 256 body subtokens, then featurize it as
|
||||
// absent. This approximates the behavior of the classifier on non-generic body features where
|
||||
// large body features are replaced by the absent token.
|
||||
//
|
||||
// We count nodes instead of tokens because tokens are often not unique.
|
||||
strictcount(AstNode node |
|
||||
node = getAnAstNodeToFeaturize(function) and
|
||||
exists(getTokenizedAstNode(node))
|
||||
) <= 256 and
|
||||
// Performance optimization: If a function has more than getMaxChars() characters in its body subtokens,
|
||||
// then featurize it as absent.
|
||||
getNumCharsInFunction(function) <= getMaxChars() and
|
||||
result =
|
||||
strictconcat(Location l, string token |
|
||||
// The use of a nested exists here allows us to avoid duplicates due to two AST nodes in the
|
||||
// same location featurizing to the same token. By using a nested exists, we take only unique
|
||||
// (location, token) pairs.
|
||||
exists(AstNode node |
|
||||
node = getAnAstNodeToFeaturize(function) and
|
||||
token = getTokenizedAstNode(node) and
|
||||
l = node.getLocation()
|
||||
)
|
||||
|
|
||||
token, " "
|
||||
order by
|
||||
l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
|
||||
l.getEndColumn(), token
|
||||
)
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about NoSQL injection vulnerabilities.
|
||||
* Defines shared code used by the NoSQL injection boosted query.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
private import semmle.javascript.heuristics.SyntacticHeuristics
|
||||
private import semmle.javascript.security.dataflow.NosqlInjectionCustomizations
|
||||
import AdaptiveThreatModeling
|
||||
|
||||
class NosqlInjectionAtmConfig extends AtmConfig {
|
||||
NosqlInjectionAtmConfig() { this = "NosqlInjectionAtmConfig" }
|
||||
|
||||
override predicate isKnownSource(DataFlow::Node source) {
|
||||
source instanceof NosqlInjection::Source or TaintedObject::isSource(source, _)
|
||||
}
|
||||
|
||||
override EndpointType getASinkEndpointType() { result instanceof NosqlInjectionSinkType }
|
||||
|
||||
/*
|
||||
* This is largely a copy of the taint tracking configuration for the standard NoSQL injection
|
||||
* query, except additional ATM sinks have been added and the additional flow step has been
|
||||
* generalised to cover the sinks predicted by ATM.
|
||||
*/
|
||||
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
|
||||
TaintedObject::isSource(source, label)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) {
|
||||
sink.(NosqlInjection::Sink).getAFlowLabel() = label
|
||||
or
|
||||
// Allow effective sinks to have any taint label
|
||||
this.isEffectiveSink(sink)
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
super.isSanitizer(node) or
|
||||
node instanceof NosqlInjection::Sanitizer
|
||||
}
|
||||
|
||||
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
|
||||
guard instanceof TaintedObject::SanitizerGuard
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node src, DataFlow::Node trg, DataFlow::FlowLabel inlbl, DataFlow::FlowLabel outlbl
|
||||
) {
|
||||
// additional flow steps from the base (non-boosted) security query
|
||||
this.isBaseAdditionalFlowStep(src, trg, inlbl, outlbl)
|
||||
or
|
||||
// relaxed version of previous step to track taint through unmodeled NoSQL query objects
|
||||
this.isEffectiveSink(trg) and
|
||||
src = this.getASubexpressionWithinQuery(trg)
|
||||
}
|
||||
|
||||
/** Holds if src -> trg is an additional flow step in the non-boosted NoSql injection security query. */
|
||||
private predicate isBaseAdditionalFlowStep(
|
||||
DataFlow::Node src, DataFlow::Node trg, DataFlow::FlowLabel inlbl, DataFlow::FlowLabel outlbl
|
||||
) {
|
||||
TaintedObject::step(src, trg, inlbl, outlbl)
|
||||
or
|
||||
// additional flow step to track taint through NoSQL query objects
|
||||
inlbl = TaintedObject::label() and
|
||||
outlbl = TaintedObject::label() and
|
||||
exists(NoSql::Query query, DataFlow::SourceNode queryObj |
|
||||
queryObj.flowsTo(query) and
|
||||
queryObj.flowsTo(trg) and
|
||||
src = queryObj.getAPropertyWrite().getRhs()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value that is (transitively) written to `query`, where `query` is a NoSQL sink.
|
||||
*
|
||||
* This predicate allows us to propagate data flow through property writes and array constructors
|
||||
* within a query object, enabling the security query to pick up NoSQL injection vulnerabilities
|
||||
* involving more complex queries.
|
||||
*/
|
||||
private DataFlow::Node getASubexpressionWithinQuery(DataFlow::Node query) {
|
||||
this.isEffectiveSink(query) and
|
||||
exists(DataFlow::SourceNode receiver |
|
||||
receiver = [this.getASubexpressionWithinQuery(query), query].getALocalSource()
|
||||
|
|
||||
result =
|
||||
[
|
||||
receiver.getAPropertyWrite().getRhs(),
|
||||
receiver.(DataFlow::ArrayCreationNode).getAnElement()
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about command-injection
|
||||
* vulnerabilities.
|
||||
* Defines shared code used by the ShellCommandInjectionFromEnvironment boosted query.
|
||||
*/
|
||||
|
||||
private import semmle.javascript.heuristics.SyntacticHeuristics
|
||||
private import semmle.javascript.security.dataflow.ShellCommandInjectionFromEnvironmentCustomizations::ShellCommandInjectionFromEnvironment as ShellCommandInjectionFromEnvironment
|
||||
import AdaptiveThreatModeling
|
||||
|
||||
class ShellCommandInjectionFromEnvironmentAtmConfig extends AtmConfig {
|
||||
ShellCommandInjectionFromEnvironmentAtmConfig() {
|
||||
this = "ShellCommandInjectionFromEnvironmentAtmConfig"
|
||||
}
|
||||
|
||||
override predicate isKnownSource(DataFlow::Node source) {
|
||||
source instanceof ShellCommandInjectionFromEnvironment::Source
|
||||
}
|
||||
|
||||
override EndpointType getASinkEndpointType() {
|
||||
result instanceof ShellCommandInjectionFromEnvironmentSinkType
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
super.isSanitizer(node) or
|
||||
node instanceof ShellCommandInjectionFromEnvironment::Sanitizer
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about SQL injection vulnerabilities.
|
||||
* Defines shared code used by the SQL injection boosted query.
|
||||
*/
|
||||
|
||||
import semmle.javascript.heuristics.SyntacticHeuristics
|
||||
import semmle.javascript.security.dataflow.SqlInjectionCustomizations
|
||||
import AdaptiveThreatModeling
|
||||
|
||||
class SqlInjectionAtmConfig extends AtmConfig {
|
||||
SqlInjectionAtmConfig() { this = "SqlInjectionAtmConfig" }
|
||||
|
||||
override predicate isKnownSource(DataFlow::Node source) { source instanceof SqlInjection::Source }
|
||||
|
||||
override EndpointType getASinkEndpointType() { result instanceof SqlInjectionSinkType }
|
||||
|
||||
/*
|
||||
* This is largely a copy of the taint tracking configuration for the standard SQL injection
|
||||
* query, except additional sinks have been added using the sink endpoint filter.
|
||||
*/
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
super.isSanitizer(node) or
|
||||
node instanceof SqlInjection::Sanitizer
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about path injection vulnerabilities.
|
||||
* Defines shared code used by the path injection boosted query.
|
||||
*/
|
||||
|
||||
import semmle.javascript.heuristics.SyntacticHeuristics
|
||||
import semmle.javascript.security.dataflow.TaintedPathCustomizations
|
||||
import AdaptiveThreatModeling
|
||||
|
||||
class TaintedPathAtmConfig extends AtmConfig {
|
||||
TaintedPathAtmConfig() { this = "TaintedPathAtmConfig" }
|
||||
|
||||
override predicate isKnownSource(DataFlow::Node source) { source instanceof TaintedPath::Source }
|
||||
|
||||
override EndpointType getASinkEndpointType() { result instanceof TaintedPathSinkType }
|
||||
|
||||
/*
|
||||
* This is largely a copy of the taint tracking configuration for the standard path injection
|
||||
* query, except additional ATM sinks have been added to the `isSink` predicate.
|
||||
*/
|
||||
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) {
|
||||
label = sink.(TaintedPath::Sink).getAFlowLabel()
|
||||
or
|
||||
// Allow effective sinks to have any taint label
|
||||
this.isEffectiveSink(sink)
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof TaintedPath::Sanitizer }
|
||||
|
||||
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode node) {
|
||||
node instanceof BarrierGuardNodeAsSanitizerGuardNode
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node src, DataFlow::Node dst, DataFlow::FlowLabel srclabel,
|
||||
DataFlow::FlowLabel dstlabel
|
||||
) {
|
||||
TaintedPath::isAdditionalTaintedPathFlowStep(src, dst, srclabel, dstlabel)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class provides sanitizer guards for path injection.
|
||||
*
|
||||
* The standard library path injection query uses a data flow configuration, and therefore defines
|
||||
* barrier nodes. However we're using a taint tracking configuration for path injection to find new
|
||||
* kinds of less certain results. Since taint tracking configurations use sanitizer guards instead
|
||||
* of barrier guards, we port the barrier guards for the boosted query from the standard library to
|
||||
* sanitizer guards here.
|
||||
*/
|
||||
private class BarrierGuardNodeAsSanitizerGuardNode extends TaintTracking::LabeledSanitizerGuardNode instanceof TaintedPath::BarrierGuardNode
|
||||
{
|
||||
override predicate sanitizes(boolean outcome, Expr e) {
|
||||
this.blocks(outcome, e) or this.blocks(outcome, e, _)
|
||||
}
|
||||
|
||||
override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) {
|
||||
this.sanitizes(outcome, e) and exists(label)
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about XSS vulnerabilities.
|
||||
* Defines shared code used by the XSS boosted query.
|
||||
*/
|
||||
|
||||
private import semmle.javascript.heuristics.SyntacticHeuristics
|
||||
private import semmle.javascript.security.dataflow.DomBasedXssCustomizations
|
||||
import AdaptiveThreatModeling
|
||||
|
||||
class DomBasedXssAtmConfig extends AtmConfig {
|
||||
DomBasedXssAtmConfig() { this = "DomBasedXssAtmConfig" }
|
||||
|
||||
override predicate isKnownSource(DataFlow::Node source) { source instanceof DomBasedXss::Source }
|
||||
|
||||
override EndpointType getASinkEndpointType() { result instanceof XssSinkType }
|
||||
|
||||
/*
|
||||
* This is largely a copy of the taint tracking configuration for the standard XSSThroughDom query,
|
||||
* except additional ATM sinks have been added to the `isSink` predicate.
|
||||
*/
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
super.isSanitizer(node) or
|
||||
node instanceof DomBasedXss::Sanitizer or
|
||||
DomBasedXss::isOptionallySanitizedNode(node)
|
||||
}
|
||||
|
||||
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
|
||||
guard instanceof PrefixStringSanitizerActivated or
|
||||
guard instanceof QuoteGuard or
|
||||
guard instanceof ContainsHtmlGuard
|
||||
}
|
||||
}
|
||||
|
||||
private import semmle.javascript.security.dataflow.Xss::Shared as Shared
|
||||
|
||||
private class PrefixStringSanitizerActivated extends TaintTracking::SanitizerGuardNode,
|
||||
DomBasedXss::PrefixStringSanitizer
|
||||
{
|
||||
PrefixStringSanitizerActivated() { this = this }
|
||||
}
|
||||
|
||||
private class PrefixStringActivated extends DataFlow::FlowLabel, DomBasedXss::PrefixString {
|
||||
PrefixStringActivated() { this = this }
|
||||
}
|
||||
|
||||
private class QuoteGuard extends TaintTracking::SanitizerGuardNode, Shared::QuoteGuard {
|
||||
QuoteGuard() { this = this }
|
||||
}
|
||||
|
||||
private class ContainsHtmlGuard extends TaintTracking::SanitizerGuardNode, Shared::ContainsHtmlGuard
|
||||
{
|
||||
ContainsHtmlGuard() { this = this }
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about XSS through the DOM.
|
||||
* Defines shared code used by the XSS Through DOM boosted query.
|
||||
*/
|
||||
|
||||
private import semmle.javascript.heuristics.SyntacticHeuristics
|
||||
private import semmle.javascript.security.dataflow.DomBasedXssCustomizations
|
||||
private import semmle.javascript.dataflow.InferredTypes
|
||||
private import semmle.javascript.security.dataflow.XssThroughDomCustomizations::XssThroughDom as XssThroughDom
|
||||
private import semmle.javascript.security.dataflow.UnsafeJQueryPluginCustomizations::UnsafeJQueryPlugin as UnsafeJQuery
|
||||
import AdaptiveThreatModeling
|
||||
|
||||
class XssThroughDomAtmConfig extends AtmConfig {
|
||||
XssThroughDomAtmConfig() { this = "XssThroughDomAtmConfig" }
|
||||
|
||||
override predicate isKnownSource(DataFlow::Node source) {
|
||||
source instanceof XssThroughDom::Source
|
||||
}
|
||||
|
||||
override EndpointType getASinkEndpointType() { result instanceof XssSinkType }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
super.isSanitizer(node) or
|
||||
node instanceof DomBasedXss::Sanitizer or
|
||||
DomBasedXss::isOptionallySanitizedNode(node)
|
||||
}
|
||||
|
||||
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
|
||||
guard instanceof TypeTestGuard or
|
||||
guard instanceof UnsafeJQuery::PropertyPresenceSanitizer or
|
||||
guard instanceof UnsafeJQuery::NumberGuard or
|
||||
guard instanceof PrefixStringSanitizer or
|
||||
guard instanceof QuoteGuard or
|
||||
guard instanceof ContainsHtmlGuard
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A test of form `typeof x === "something"`, preventing `x` from being a string in some cases.
|
||||
*
|
||||
* This sanitizer helps prune infeasible paths in type-overloaded functions.
|
||||
*/
|
||||
class TypeTestGuard extends TaintTracking::SanitizerGuardNode, DataFlow::ValueNode {
|
||||
override EqualityTest astNode;
|
||||
Expr operand;
|
||||
boolean polarity;
|
||||
|
||||
TypeTestGuard() {
|
||||
exists(TypeofTag tag | TaintTracking::isTypeofGuard(astNode, operand, tag) |
|
||||
// typeof x === "string" sanitizes `x` when it evaluates to false
|
||||
tag = "string" and
|
||||
polarity = astNode.getPolarity().booleanNot()
|
||||
or
|
||||
// typeof x === "object" sanitizes `x` when it evaluates to true
|
||||
tag != "string" and
|
||||
polarity = astNode.getPolarity()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sanitizes(boolean outcome, Expr e) {
|
||||
polarity = outcome and
|
||||
e = operand
|
||||
}
|
||||
}
|
||||
|
||||
private import semmle.javascript.security.dataflow.Xss::Shared as Shared
|
||||
|
||||
private class PrefixStringSanitizer extends TaintTracking::SanitizerGuardNode,
|
||||
DomBasedXss::PrefixStringSanitizer
|
||||
{
|
||||
PrefixStringSanitizer() { this = this }
|
||||
}
|
||||
|
||||
private class PrefixString extends DataFlow::FlowLabel, DomBasedXss::PrefixString {
|
||||
PrefixString() { this = this }
|
||||
}
|
||||
|
||||
private class QuoteGuard extends TaintTracking::SanitizerGuardNode, Shared::QuoteGuard {
|
||||
QuoteGuard() { this = this }
|
||||
}
|
||||
|
||||
private class ContainsHtmlGuard extends TaintTracking::SanitizerGuardNode, Shared::ContainsHtmlGuard
|
||||
{
|
||||
ContainsHtmlGuard() { this = this }
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
name: codeql/javascript-experimental-atm-lib
|
||||
description: CodeQL libraries for the experimental ML-powered queries
|
||||
version: 0.4.10
|
||||
extractor: javascript
|
||||
library: true
|
||||
groups:
|
||||
- javascript
|
||||
- experimental
|
||||
dependencies:
|
||||
codeql/javascript-all: ${workspace}
|
||||
warnOnImplicitThis: true
|
||||
@@ -1,3 +0,0 @@
|
||||
# Avoid checking in ML models
|
||||
# This matches the mlModels property of qlpack.yml.
|
||||
resources/*.codeqlmodel
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
dependencies: {}
|
||||
compiled: false
|
||||
lockVersion: 1.0.0
|
||||
@@ -1,9 +0,0 @@
|
||||
name: codeql/javascript-experimental-atm-model
|
||||
description: Machine learning model supporting the experimental ML-powered queries
|
||||
version: 0.3.1
|
||||
groups:
|
||||
- javascript
|
||||
- experimental
|
||||
mlModels:
|
||||
- "resources/*.codeqlmodel"
|
||||
warnOnImplicitThis: true
|
||||
@@ -1,81 +0,0 @@
|
||||
/**
|
||||
* @name Debug result inclusion
|
||||
* @description Use this query to understand why some alerts are included or excluded from the
|
||||
* results of boosted queries. The results for this query are the union of the alerts
|
||||
* generated by each boosted query. Each alert includes an explanation why it was
|
||||
* included or excluded for each of the four security queries.
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @id adaptive-threat-modeling/js/debug-result-inclusion
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import experimental.adaptivethreatmodeling.ATMConfig
|
||||
import extraction.ExtractEndpointDataTraining
|
||||
private import experimental.adaptivethreatmodeling.NosqlInjectionATM as NosqlInjectionAtm
|
||||
private import experimental.adaptivethreatmodeling.SqlInjectionATM as SqlInjectionAtm
|
||||
private import experimental.adaptivethreatmodeling.TaintedPathATM as TaintedPathAtm
|
||||
private import experimental.adaptivethreatmodeling.XssATM as XssAtm
|
||||
private import experimental.adaptivethreatmodeling.XssThroughDomATM as XssThroughDomAtm
|
||||
private import experimental.adaptivethreatmodeling.ShellCommandInjectionFromEnvironmentATM as ShellCommandInjectionFromEnvironmentAtm
|
||||
|
||||
string getAReasonSinkExcluded(DataFlow::Node sinkCandidate, Query query) {
|
||||
query instanceof NosqlInjectionQuery and
|
||||
result = any(NosqlInjectionAtm::NosqlInjectionAtmConfig cfg).getAReasonSinkExcluded(sinkCandidate)
|
||||
or
|
||||
query instanceof SqlInjectionQuery and
|
||||
result = any(SqlInjectionAtm::SqlInjectionAtmConfig cfg).getAReasonSinkExcluded(sinkCandidate)
|
||||
or
|
||||
query instanceof TaintedPathQuery and
|
||||
result = any(TaintedPathAtm::TaintedPathAtmConfig cfg).getAReasonSinkExcluded(sinkCandidate)
|
||||
or
|
||||
query instanceof XssQuery and
|
||||
result = any(XssAtm::DomBasedXssAtmConfig cfg).getAReasonSinkExcluded(sinkCandidate)
|
||||
or
|
||||
query instanceof XssThroughDomQuery and
|
||||
result = any(XssThroughDomAtm::XssThroughDomAtmConfig cfg).getAReasonSinkExcluded(sinkCandidate)
|
||||
or
|
||||
query instanceof ShellCommandInjectionFromEnvironmentQuery and
|
||||
result =
|
||||
any(ShellCommandInjectionFromEnvironmentAtm::ShellCommandInjectionFromEnvironmentAtmConfig cfg)
|
||||
.getAReasonSinkExcluded(sinkCandidate)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
string getDescriptionForAlertCandidate(
|
||||
DataFlow::Node sourceCandidate, DataFlow::Node sinkCandidate, Query query
|
||||
) {
|
||||
result = "excluded[reason=" + getAReasonSinkExcluded(sinkCandidate, query) + "]"
|
||||
or
|
||||
getDataFlowCfg(query).(AtmConfig).isKnownSink(sinkCandidate) and
|
||||
result = "excluded[reason=known-sink]"
|
||||
or
|
||||
not exists(getAReasonSinkExcluded(sinkCandidate, query)) and
|
||||
not getDataFlowCfg(query).hasFlow(sourceCandidate, sinkCandidate) and
|
||||
(
|
||||
if
|
||||
getDataFlowCfg(query).isSource(sourceCandidate) or
|
||||
getDataFlowCfg(query).isSource(sourceCandidate, _)
|
||||
then result = "no flow"
|
||||
else result = "not a known source"
|
||||
)
|
||||
or
|
||||
getDataFlowCfg(query).hasFlow(sourceCandidate, sinkCandidate) and
|
||||
result = "included"
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
string getDescriptionForAlert(DataFlow::Node sourceCandidate, DataFlow::Node sinkCandidate) {
|
||||
result =
|
||||
concat(Query query |
|
||||
|
|
||||
query.getName() + ": " +
|
||||
getDescriptionForAlertCandidate(sourceCandidate, sinkCandidate, query), ", "
|
||||
)
|
||||
}
|
||||
|
||||
from DataFlow::Configuration cfg, DataFlow::Node source, DataFlow::Node sink
|
||||
where cfg.hasFlow(source, sink)
|
||||
select sink,
|
||||
"This is an ATM result that may depend on $@ [" + getDescriptionForAlert(source, sink) + "]",
|
||||
source, "a user-provided value"
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
lockVersion: 1.0.0
|
||||
dependencies:
|
||||
codeql/javascript-experimental-atm-model:
|
||||
version: 0.3.1-2023-03-01-12h42m43s.strong-turtle-1xp3dqvv.ecb17d40286d14132b481c065a43459a7f0ba9059015b7a49c909c9f9ce5fec5
|
||||
compiled: false
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
*
|
||||
* Count the number of sinks and alerts for a particular dataflow config.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import evaluation.EndToEndEvaluation
|
||||
|
||||
query predicate countAlertsAndSinks(int numAlerts, int numSinks) {
|
||||
numAlerts =
|
||||
count(DataFlow::Configuration cfg, DataFlow::Node source, DataFlow::Node sink |
|
||||
cfg.hasFlow(source, sink) and not isFlowExcluded(source, sink)
|
||||
) and
|
||||
numSinks =
|
||||
count(DataFlow::Node sink |
|
||||
exists(DataFlow::Configuration cfg | cfg.isSink(sink) or cfg.isSink(sink, _))
|
||||
)
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
*
|
||||
* Count the number of sinks and alerts for the `CodeInjection` security query.
|
||||
*/
|
||||
|
||||
import semmle.javascript.security.dataflow.CodeInjectionQuery
|
||||
import CountAlertsAndSinks
|
||||
@@ -1,9 +0,0 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
*
|
||||
* Count the number of sinks and alerts for the `NosqlInjection` security query.
|
||||
*/
|
||||
|
||||
import semmle.javascript.security.dataflow.NosqlInjectionQuery
|
||||
import CountAlertsAndSinks
|
||||
@@ -1,9 +0,0 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
*
|
||||
* Count the number of sinks and alerts for the `SqlInjection` security query.
|
||||
*/
|
||||
|
||||
import semmle.javascript.security.dataflow.SqlInjectionQuery
|
||||
import CountAlertsAndSinks
|
||||
@@ -1,9 +0,0 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
*
|
||||
* Count the number of sinks and alerts for the `TaintedPath` security query.
|
||||
*/
|
||||
|
||||
import semmle.javascript.security.dataflow.TaintedPathQuery
|
||||
import CountAlertsAndSinks
|
||||
@@ -1,9 +0,0 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
*
|
||||
* Count the number of sinks and alerts for the `DomBasedXss` security query.
|
||||
*/
|
||||
|
||||
import semmle.javascript.security.dataflow.DomBasedXssQuery
|
||||
import CountAlertsAndSinks
|
||||
@@ -1,9 +0,0 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
*
|
||||
* Count the number of sinks and alerts for the `XssThroughDom` security query.
|
||||
*/
|
||||
|
||||
import semmle.javascript.security.dataflow.XssThroughDomQuery
|
||||
import CountAlertsAndSinks
|
||||
@@ -1,11 +0,0 @@
|
||||
private import javascript
|
||||
private import extraction.Exclusions as Exclusions
|
||||
|
||||
/**
|
||||
* Holds if the flow from `source` to `sink` should be excluded from the results of an end-to-end
|
||||
* evaluation query.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate isFlowExcluded(DataFlow::Node source, DataFlow::Node sink) {
|
||||
Exclusions::isFileExcluded([source.getFile(), sink.getFile()])
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* EndpointScoresIntegrationTest.ql
|
||||
*
|
||||
* Extract scores for each test endpoint that is an argument to a function call in the database.
|
||||
* This is used by integration tests to verify that QL and the modeling codebase agree on the scores
|
||||
* of a set of test endpoints.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import experimental.adaptivethreatmodeling.ATMConfig
|
||||
import experimental.adaptivethreatmodeling.FeaturizationConfig
|
||||
import experimental.adaptivethreatmodeling.EndpointScoring::ModelScoring as ModelScoring
|
||||
|
||||
/**
|
||||
* A featurization config that featurizes endpoints that are arguments to function calls.
|
||||
*
|
||||
* This should only be used in extraction queries and tests.
|
||||
*/
|
||||
class FunctionArgumentFeaturizationConfig extends FeaturizationConfig {
|
||||
FunctionArgumentFeaturizationConfig() { this = "FunctionArgumentFeaturization" }
|
||||
|
||||
override DataFlow::Node getAnEndpointToFeaturize() {
|
||||
exists(DataFlow::CallNode call | result = call.getAnArgument())
|
||||
}
|
||||
}
|
||||
|
||||
query predicate endpointScores = ModelScoring::endpointScores/3;
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* ModelCheck.ql
|
||||
*
|
||||
* Returns checksums of ATM models.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The `availableMlModels` template predicate.
|
||||
*
|
||||
* This is populated by the evaluator with metadata for the available machine learning models.
|
||||
*/
|
||||
external predicate availableMlModels(
|
||||
string modelChecksum, string modelLanguage, string modelName, string modelType
|
||||
);
|
||||
|
||||
select any(string checksum | availableMlModels(checksum, "javascript", _, _))
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
* [DEPRECATED] Counts alerts and sinks for JavaScript security queries.
|
||||
*
|
||||
* This query is deprecated due to the performance implications of bringing in data flow
|
||||
* configurations from multiple queries. Instead use `CountSourcesAndSinks.ql` to count sinks for
|
||||
* JavaScript security queries, and count alerts by running the standard or evaluation queries for
|
||||
* each security vulnerability.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import semmle.javascript.security.dataflow.NosqlInjectionQuery as NosqlInjection
|
||||
import semmle.javascript.security.dataflow.SqlInjectionQuery as SqlInjection
|
||||
import semmle.javascript.security.dataflow.TaintedPathQuery as TaintedPath
|
||||
import semmle.javascript.security.dataflow.DomBasedXssQuery as DomBasedXss
|
||||
import semmle.javascript.security.dataflow.StoredXssQuery as StoredXss
|
||||
import semmle.javascript.security.dataflow.XssThroughDomQuery as XssThroughDom
|
||||
import evaluation.EndToEndEvaluation
|
||||
|
||||
int numAlerts(DataFlow::Configuration cfg) {
|
||||
result =
|
||||
count(DataFlow::Node source, DataFlow::Node sink |
|
||||
cfg.hasFlow(source, sink) and not isFlowExcluded(source, sink)
|
||||
)
|
||||
}
|
||||
|
||||
select numAlerts(any(NosqlInjection::Configuration cfg)) as numNosqlAlerts,
|
||||
numAlerts(any(SqlInjection::Configuration cfg)) as numSqlAlerts,
|
||||
numAlerts(any(TaintedPath::Configuration cfg)) as numTaintedPathAlerts,
|
||||
numAlerts(any(DomBasedXss::Configuration cfg)) as numXssAlerts,
|
||||
numAlerts(any(StoredXss::Configuration cfg)) as numStoredXssAlerts,
|
||||
numAlerts(any(XssThroughDom::Configuration cfg)) as numXssThroughDomAlerts,
|
||||
count(DataFlow::Node sink |
|
||||
exists(NosqlInjection::Configuration cfg | cfg.isSink(sink) or cfg.isSink(sink, _))
|
||||
) as numNosqlSinks,
|
||||
count(DataFlow::Node sink |
|
||||
exists(SqlInjection::Configuration cfg | cfg.isSink(sink) or cfg.isSink(sink, _))
|
||||
) as numSqlSinks,
|
||||
count(DataFlow::Node sink |
|
||||
exists(TaintedPath::Configuration cfg | cfg.isSink(sink) or cfg.isSink(sink, _))
|
||||
) as numTaintedPathSinks,
|
||||
count(DataFlow::Node sink |
|
||||
exists(DomBasedXss::Configuration cfg | cfg.isSink(sink) or cfg.isSink(sink, _))
|
||||
) as numXssSinks,
|
||||
count(DataFlow::Node sink |
|
||||
exists(StoredXss::Configuration cfg | cfg.isSink(sink) or cfg.isSink(sink, _))
|
||||
) as numStoredXssSinks,
|
||||
count(DataFlow::Node sink |
|
||||
exists(XssThroughDom::Configuration cfg | cfg.isSink(sink) or cfg.isSink(sink, _))
|
||||
) as numXssThroughDomSinks
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
* Counts sources and sinks for JavaScript security queries.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import semmle.javascript.dataflow.Configuration
|
||||
// javascript/ql/lib/semmle/javascript/security/dataflow$ ls *Query.qll | sed -e 's/\(.*\)Query.qll/import semmle.javascript.security.dataflow.\1Query as \1/'
|
||||
import semmle.javascript.security.dataflow.BrokenCryptoAlgorithmQuery as BrokenCryptoAlgorithm
|
||||
import semmle.javascript.security.dataflow.BuildArtifactLeakQuery as BuildArtifactLeak
|
||||
import semmle.javascript.security.dataflow.CleartextLoggingQuery as CleartextLogging
|
||||
import semmle.javascript.security.dataflow.CleartextStorageQuery as CleartextStorage
|
||||
import semmle.javascript.security.dataflow.ClientSideUrlRedirectQuery as ClientSideUrlRedirect
|
||||
import semmle.javascript.security.dataflow.CodeInjectionQuery as CodeInjection
|
||||
import semmle.javascript.security.dataflow.CommandInjectionQuery as CommandInjection
|
||||
import semmle.javascript.security.dataflow.ConditionalBypassQuery as ConditionalBypass
|
||||
import semmle.javascript.security.dataflow.CorsMisconfigurationForCredentialsQuery as CorsMisconfigurationForCredentials
|
||||
import semmle.javascript.security.dataflow.DeepObjectResourceExhaustionQuery as DeepObjectResourceExhaustion
|
||||
import semmle.javascript.security.dataflow.DifferentKindsComparisonBypassQuery as DifferentKindsComparisonBypass
|
||||
import semmle.javascript.security.dataflow.DomBasedXssQuery as DomBasedXss
|
||||
import semmle.javascript.security.dataflow.ExceptionXssQuery as ExceptionXss
|
||||
import semmle.javascript.security.dataflow.ExternalAPIUsedWithUntrustedDataQuery as ExternalApiUsedWithUntrustedData
|
||||
import semmle.javascript.security.dataflow.FileAccessToHttpQuery as FileAccessToHttp
|
||||
import semmle.javascript.security.dataflow.HardcodedCredentialsQuery as HardcodedCredentials
|
||||
import semmle.javascript.security.dataflow.HardcodedDataInterpretedAsCodeQuery as HardcodedDataInterpretedAsCode
|
||||
import semmle.javascript.security.dataflow.HostHeaderPoisoningInEmailGenerationQuery as HostHeaderPoisoningInEmailGeneration
|
||||
import semmle.javascript.security.dataflow.HttpToFileAccessQuery as HttpToFileAccess
|
||||
import semmle.javascript.security.dataflow.ImproperCodeSanitizationQuery as ImproperCodeSanitization
|
||||
import semmle.javascript.security.dataflow.IncompleteHtmlAttributeSanitizationQuery as IncompleteHtmlAttributeSanitization
|
||||
import semmle.javascript.security.dataflow.IndirectCommandInjectionQuery as IndirectCommandInjection
|
||||
import semmle.javascript.security.dataflow.InsecureDownloadQuery as InsecureDownload
|
||||
import semmle.javascript.security.dataflow.InsecureRandomnessQuery as InsecureRandomness
|
||||
import semmle.javascript.security.dataflow.InsufficientPasswordHashQuery as InsufficientPasswordHash
|
||||
import semmle.javascript.security.dataflow.LogInjectionQuery as LogInjection
|
||||
import semmle.javascript.security.dataflow.LoopBoundInjectionQuery as LoopBoundInjection
|
||||
import semmle.javascript.security.dataflow.NosqlInjectionQuery as NosqlInjection
|
||||
import semmle.javascript.security.dataflow.PostMessageStarQuery as PostMessageStar
|
||||
import semmle.javascript.security.dataflow.PrototypePollutingAssignmentQuery as PrototypePollutingAssignment
|
||||
import semmle.javascript.security.dataflow.PrototypePollutionQuery as PrototypePollution
|
||||
import semmle.javascript.security.dataflow.ReflectedXssQuery as ReflectedXss
|
||||
import semmle.javascript.security.dataflow.RegExpInjectionQuery as RegExpInjection
|
||||
import semmle.javascript.security.dataflow.RemotePropertyInjectionQuery as RemotePropertyInjection
|
||||
import semmle.javascript.security.dataflow.RequestForgeryQuery as RequestForgery
|
||||
import semmle.javascript.security.dataflow.ServerSideUrlRedirectQuery as ServerSideUrlRedirect
|
||||
import semmle.javascript.security.dataflow.ShellCommandInjectionFromEnvironmentQuery as ShellCommandInjectionFromEnvironment
|
||||
import semmle.javascript.security.dataflow.SqlInjectionQuery as SqlInjection
|
||||
import semmle.javascript.security.dataflow.StackTraceExposureQuery as StackTraceExposure
|
||||
import semmle.javascript.security.dataflow.StoredXssQuery as StoredXss
|
||||
import semmle.javascript.security.dataflow.TaintedFormatStringQuery as TaintedFormatString
|
||||
import semmle.javascript.security.dataflow.TaintedPathQuery as TaintedPath
|
||||
import semmle.javascript.security.dataflow.TemplateObjectInjectionQuery as TemplateObjectInjection
|
||||
import semmle.javascript.security.dataflow.TypeConfusionThroughParameterTamperingQuery as TypeConfusionThroughParameterTampering
|
||||
import semmle.javascript.security.dataflow.UnsafeDeserializationQuery as UnsafeDeserialization
|
||||
import semmle.javascript.security.dataflow.UnsafeDynamicMethodAccessQuery as UnsafeDynamicMethodAccess
|
||||
import semmle.javascript.security.dataflow.UnsafeHtmlConstructionQuery as UnsafeHtmlConstruction
|
||||
import semmle.javascript.security.dataflow.UnsafeJQueryPluginQuery as UnsafeJQueryPlugin
|
||||
import semmle.javascript.security.dataflow.UnsafeShellCommandConstructionQuery as UnsafeShellCommandConstruction
|
||||
import semmle.javascript.security.dataflow.UnvalidatedDynamicMethodCallQuery as UnvalidatedDynamicMethodCall
|
||||
import semmle.javascript.security.dataflow.XmlBombQuery as XmlBomb
|
||||
import semmle.javascript.security.dataflow.XpathInjectionQuery as XpathInjection
|
||||
import semmle.javascript.security.dataflow.XssThroughDomQuery as XssThroughDom
|
||||
import semmle.javascript.security.dataflow.XxeQuery as Xxe
|
||||
import semmle.javascript.security.dataflow.ZipSlipQuery as ZipSlip
|
||||
|
||||
DataFlow::Node getASink(Configuration cfg) { cfg.isSink(result) or cfg.isSink(result, _) }
|
||||
|
||||
DataFlow::Node getASource(Configuration cfg) { cfg.isSource(result) or cfg.isSource(result, _) }
|
||||
|
||||
from Configuration cfg, int sources, int sinks
|
||||
where count(getASource(cfg)) = sources and count(getASink(cfg)) = sinks
|
||||
select cfg, sources, sinks
|
||||
@@ -1,49 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* Defines files that should be excluded from the evaluation of ML models.
|
||||
*/
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.filters.ClassifyFiles as ClassifyFiles
|
||||
|
||||
/** Holds if the file should be excluded from end-to-end evaluation. */
|
||||
predicate isFileExcluded(File file) {
|
||||
// Ignore files that are outside the root folder of the analyzed source location.
|
||||
//
|
||||
// If the file doesn't have a relative path, then the source file is located outside the root
|
||||
// folder of the analyzed source location, meaning that the files are additional files added to
|
||||
// the database like standard library files that we would like to ignore.
|
||||
not exists(file.getRelativePath())
|
||||
or
|
||||
// Ignore files based on their path.
|
||||
exists(string ignorePattern, string separator |
|
||||
ignorePattern =
|
||||
// Exclude test files
|
||||
"(tests?|test[_-]?case|" +
|
||||
// Exclude library files
|
||||
//
|
||||
// - The Bower and npm package managers store packages in bower_components and node_modules
|
||||
// folders respectively.
|
||||
// - Specific exclusion for end-to-end: `applications/examples/static/epydoc` contains
|
||||
// library code from Epydoc.
|
||||
"3rd[_-]?party|bower_components|extern(s|al)?|node_modules|resources|third[_-]?party|_?vendor|"
|
||||
+ "applications" + separator + "examples" + separator + "static" + separator + "epydoc|" +
|
||||
// Exclude generated code
|
||||
"gen|\\.?generated|" +
|
||||
// Exclude benchmarks
|
||||
"benchmarks?|" +
|
||||
// Exclude documentation
|
||||
"docs?|documentation)" and
|
||||
separator = "(\\/|\\.)" and
|
||||
exists(
|
||||
file.getRelativePath()
|
||||
.toLowerCase()
|
||||
.regexpFind(separator + ignorePattern + separator + "|" + "^" + ignorePattern + separator +
|
||||
"|" + separator + ignorePattern + "$", _, _)
|
||||
)
|
||||
)
|
||||
or
|
||||
// Ignore externs, generated, library, and test files.
|
||||
ClassifyFiles::classify(file, ["externs", "generated", "library", "test"])
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
* Extracts training data we can use to train ML models for ML-powered queries.
|
||||
*/
|
||||
|
||||
private import ExtractEndpointDataTraining as ExtractEndpointDataTraining
|
||||
|
||||
query predicate endpoints = ExtractEndpointDataTraining::reformattedTrainingEndpoints/5;
|
||||
|
||||
query predicate tokenFeatures = ExtractEndpointDataTraining::tokenFeatures/3;
|
||||
@@ -1,255 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* Extracts training data we can use to train ML models for ML-powered queries.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import experimental.adaptivethreatmodeling.EndpointCharacteristics
|
||||
import experimental.adaptivethreatmodeling.EndpointFeatures as EndpointFeatures
|
||||
import NoFeaturizationRestrictionsConfig
|
||||
private import Exclusions as Exclusions
|
||||
import Queries
|
||||
private import experimental.adaptivethreatmodeling.NosqlInjectionATM as NosqlInjectionAtm
|
||||
private import experimental.adaptivethreatmodeling.SqlInjectionATM as SqlInjectionAtm
|
||||
private import experimental.adaptivethreatmodeling.TaintedPathATM as TaintedPathAtm
|
||||
private import experimental.adaptivethreatmodeling.XssATM as XssAtm
|
||||
private import experimental.adaptivethreatmodeling.XssThroughDomATM as XssThroughDomAtm
|
||||
private import experimental.adaptivethreatmodeling.ShellCommandInjectionFromEnvironmentATM as ShellCommandInjectionFromEnvironmentAtm
|
||||
|
||||
/**
|
||||
* Gets the set of featureName-featureValue pairs for each endpoint in the training set.
|
||||
*
|
||||
* `EndpointFeatures::tokenFeatures` has no results when `featureName` is absent for the endpoint
|
||||
* `endpoint`. To preserve compatibility with the data pipeline, this relation will instead set
|
||||
* `featureValue` to the empty string in this case.
|
||||
*/
|
||||
predicate tokenFeatures(DataFlow::Node endpoint, string featureName, string featureValue) {
|
||||
trainingEndpoints(endpoint, _, _) and
|
||||
(
|
||||
EndpointFeatures::tokenFeatures(endpoint, featureName, featureValue)
|
||||
or
|
||||
// Performance note: this creates a Cartesian product between `endpoint` and `featureName`.
|
||||
featureName = EndpointFeatures::getASupportedFeatureName() and
|
||||
not EndpointFeatures::tokenFeatures(endpoint, featureName, _) and
|
||||
featureValue = ""
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given endpoint should be included in the training set as a sample belonging to endpointClass, and has
|
||||
* the given characteristic. This query uses the endpoint characteristics to select and label endpoints for the training
|
||||
* set, and provides a list of characteristics for each endpoint in the training set, which is used in the modeling
|
||||
* code.
|
||||
*
|
||||
* Params:
|
||||
* endpoint: The endpoint to include / exclude.
|
||||
* endpointClass: The sink type. See the documentation of EndpointType.getEncoding for details about the relationship
|
||||
* between an EndpointType and a class in the classifier.
|
||||
* characteristic: Provides the list of characteristics that apply to the endpoint, which the modeling code currently
|
||||
* uses for type balancing.
|
||||
*
|
||||
* Note: This predicate will produce multiple tuples for endpoints that have multiple characteristics, which we must
|
||||
* then group together into a list of characteristics.
|
||||
*/
|
||||
query predicate trainingEndpoints(
|
||||
DataFlow::Node endpoint, EndpointType endpointClass, EndpointCharacteristic characteristic
|
||||
) {
|
||||
characteristic.appliesToEndpoint(endpoint) and
|
||||
// Only consider the source code for the project being analyzed.
|
||||
exists(endpoint.getFile().getRelativePath()) and
|
||||
// Only select endpoints that can be part of a tainted flow: Constant expressions always evaluate to a constant
|
||||
// primitive value. Therefore they can't ever appear in an alert, making them less interesting training examples.
|
||||
// TODO: Experiment with removing this requirement.
|
||||
not endpoint.asExpr() instanceof ConstantExpr and
|
||||
// Do not select endpoints filtered out by end-to-end evaluation.
|
||||
// TODO: Experiment with removing this requirement.
|
||||
not Exclusions::isFileExcluded(endpoint.getFile()) and
|
||||
// Filter out negative examples that also have a LikelyNotASinkReason, because this is currently done here
|
||||
// https://github.com/github/codeql/blob/387e57546bf7352f7c1cfe781daa1a3799b7063e/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/extraction/ExtractEndpointData.qll#L77
|
||||
// TODO: Experiment with removing this requirement.
|
||||
not (
|
||||
endpointClass instanceof NegativeType and
|
||||
exists(EndpointCharacteristic c |
|
||||
c.appliesToEndpoint(endpoint) and
|
||||
c instanceof LikelyNotASinkCharacteristic
|
||||
)
|
||||
) and
|
||||
// Don't surface endpoint filters as characteristics, because they were previously not surfaced.
|
||||
// TODO: Experiment with surfacing these to the modeling code by removing the following line (and then make
|
||||
// EndpointFilterCharacteristic private).
|
||||
not characteristic instanceof EndpointFilterCharacteristic and
|
||||
(
|
||||
// If the list of characteristics includes positive indicators with high confidence for this class, select this as a
|
||||
// training sample belonging to the class.
|
||||
exists(EndpointCharacteristic characteristic2, float confidence |
|
||||
characteristic2.appliesToEndpoint(endpoint) and
|
||||
characteristic2.hasImplications(endpointClass, true, confidence) and
|
||||
confidence >= characteristic2.getHighConfidenceThreshold()
|
||||
) and
|
||||
(
|
||||
// Temporarily limit this only to positive classes. For negative classes, additionally select only endpoints that
|
||||
// have no high confidence indicators that they are sinks, because this is what was previously done.
|
||||
// TODO: Experiment with removing this requirement, and instead ensuring that an endpoint never has both a high
|
||||
// confidence indicator that it _is_ a sink and a high confidence indicator that it is _not_ a sink.
|
||||
not endpointClass instanceof NegativeType
|
||||
or
|
||||
not exists(EndpointCharacteristic characteristic3, float confidence3, EndpointType posClass |
|
||||
characteristic3.appliesToEndpoint(endpoint) and
|
||||
characteristic3.hasImplications(posClass, true, confidence3) and
|
||||
confidence3 >= characteristic3.getHighConfidenceThreshold() and
|
||||
not posClass instanceof NegativeType
|
||||
)
|
||||
)
|
||||
or
|
||||
// If the list of characteristics includes negative indicators with high confidence for all classes other than 0,
|
||||
// select this as a training sample of class 0 (this means we had query-specific characteristics to decide this
|
||||
// endpoint isn't a sink for each of our sink types).
|
||||
endpointClass instanceof NegativeType and
|
||||
forall(EndpointType otherClass | not otherClass instanceof NegativeType |
|
||||
exists(EndpointCharacteristic characteristic2, float confidence |
|
||||
characteristic2.appliesToEndpoint(endpoint) and
|
||||
characteristic2.hasImplications(otherClass, false, confidence) and
|
||||
confidence >= characteristic2.getHighConfidenceThreshold()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporary:
|
||||
* Reformat the training data that was extracted with the new logic to match the format produced by the old predicate.
|
||||
* This is the format expected by the endpoint pipeline.
|
||||
*/
|
||||
query predicate reformattedTrainingEndpoints(
|
||||
DataFlow::Node endpoint, string queryName, string key, string value, string valueType
|
||||
) {
|
||||
trainingEndpoints(endpoint, _, _) and
|
||||
exists(Query query |
|
||||
queryName = query.getName() and
|
||||
// For sinks, only list that sink type, but for non-sinks, list all sink types.
|
||||
(
|
||||
exists(EndpointType endpointClass |
|
||||
endpointClass.getDescription().matches(queryName + "%") and
|
||||
not endpointClass instanceof NegativeType and
|
||||
trainingEndpoints(endpoint, endpointClass, _)
|
||||
)
|
||||
or
|
||||
exists(EndpointType endpointClass |
|
||||
endpointClass instanceof NegativeType and
|
||||
trainingEndpoints(endpoint, endpointClass, _)
|
||||
)
|
||||
) and
|
||||
(
|
||||
// NOTE: We don't use hasFlowFromSource in training, so we could just hardcode it to be false.
|
||||
key = "hasFlowFromSource" and
|
||||
(
|
||||
if FlowFromSource::hasFlowFromSource(endpoint, query)
|
||||
then value = "true"
|
||||
else value = "false"
|
||||
) and
|
||||
valueType = "boolean"
|
||||
or
|
||||
// Constant expressions always evaluate to a constant primitive value. Therefore they can't ever
|
||||
// appear in an alert, making them less interesting training examples.
|
||||
key = "isConstantExpression" and
|
||||
(if endpoint.asExpr() instanceof ConstantExpr then value = "true" else value = "false") and
|
||||
valueType = "boolean"
|
||||
or
|
||||
// Holds if alerts involving the endpoint are excluded from the end-to-end evaluation.
|
||||
key = "isExcludedFromEndToEndEvaluation" and
|
||||
(if Exclusions::isFileExcluded(endpoint.getFile()) then value = "true" else value = "false") and
|
||||
valueType = "boolean"
|
||||
or
|
||||
// The label for this query, considering the endpoint as a sink.
|
||||
key = "sinkLabel" and
|
||||
valueType = "string" and
|
||||
value = "Sink" and
|
||||
exists(EndpointType endpointClass |
|
||||
endpointClass.getDescription().matches(queryName + "%") and
|
||||
not endpointClass instanceof NegativeType and
|
||||
trainingEndpoints(endpoint, endpointClass, _)
|
||||
)
|
||||
or
|
||||
key = "sinkLabel" and
|
||||
valueType = "string" and
|
||||
value = "NotASink" and
|
||||
exists(EndpointType endpointClass |
|
||||
endpointClass instanceof NegativeType and
|
||||
trainingEndpoints(endpoint, endpointClass, _)
|
||||
)
|
||||
or
|
||||
// The reason, or reasons, why the endpoint was labeled NotASink for this query, only for negative examples.
|
||||
key = "notASinkReason" and
|
||||
exists(EndpointCharacteristic characteristic, EndpointType endpointClass |
|
||||
characteristic.appliesToEndpoint(endpoint) and
|
||||
characteristic.hasImplications(endpointClass, true, _) and
|
||||
endpointClass instanceof NegativeType and
|
||||
value = characteristic
|
||||
) and
|
||||
// Don't include a notASinkReason for endpoints that are also known sinks.
|
||||
not exists(EndpointCharacteristic characteristic3, float confidence3, EndpointType posClass |
|
||||
characteristic3.appliesToEndpoint(endpoint) and
|
||||
characteristic3.hasImplications(posClass, true, confidence3) and
|
||||
confidence3 >= characteristic3.getHighConfidenceThreshold() and
|
||||
not posClass instanceof NegativeType
|
||||
) and
|
||||
// Don't surface endpoint filters as notASinkReasons, because they were previously not surfaced.
|
||||
// TODO: Experiment with surfacing these to the modeling code by removing the following line (and then make
|
||||
// EndpointFilterCharacteristic private).
|
||||
not value instanceof EndpointFilterCharacteristic and
|
||||
valueType = "string"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ATM data flow configuration for the specified query.
|
||||
* TODO: Delete this once we are no longer surfacing `hasFlowFromSource`.
|
||||
*/
|
||||
DataFlow::Configuration getDataFlowCfg(Query query) {
|
||||
query instanceof NosqlInjectionQuery and
|
||||
result instanceof NosqlInjectionAtm::NosqlInjectionAtmConfig
|
||||
or
|
||||
query instanceof SqlInjectionQuery and result instanceof SqlInjectionAtm::SqlInjectionAtmConfig
|
||||
or
|
||||
query instanceof TaintedPathQuery and result instanceof TaintedPathAtm::TaintedPathAtmConfig
|
||||
or
|
||||
query instanceof XssQuery and result instanceof XssAtm::DomBasedXssAtmConfig
|
||||
or
|
||||
query instanceof XssThroughDomQuery and result instanceof XssThroughDomAtm::XssThroughDomAtmConfig
|
||||
or
|
||||
query instanceof ShellCommandInjectionFromEnvironmentQuery and
|
||||
result instanceof
|
||||
ShellCommandInjectionFromEnvironmentAtm::ShellCommandInjectionFromEnvironmentAtmConfig
|
||||
}
|
||||
|
||||
// TODO: Delete this once we are no longer surfacing `hasFlowFromSource`.
|
||||
private module FlowFromSource {
|
||||
predicate hasFlowFromSource(DataFlow::Node endpoint, Query q) {
|
||||
exists(Configuration cfg | cfg.getQuery() = q | cfg.hasFlow(_, endpoint))
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow configuration that replicates the data flow configuration for a specific query, but
|
||||
* replaces the set of sinks with the set of endpoints we're extracting.
|
||||
*
|
||||
* We use this to find out when there is flow to a particular endpoint from a known source.
|
||||
*
|
||||
* This configuration behaves in a very similar way to the `ForwardExploringConfiguration` class
|
||||
* from the CodeQL standard libraries for JavaScript.
|
||||
*/
|
||||
private class Configuration extends DataFlow::Configuration {
|
||||
Query q;
|
||||
|
||||
Configuration() { this = getDataFlowCfg(q) }
|
||||
|
||||
Query getQuery() { result = q }
|
||||
|
||||
/** Holds if `sink` is an endpoint we're extracting. */
|
||||
override predicate isSink(DataFlow::Node sink) { any() }
|
||||
|
||||
/** Holds if `sink` is an endpoint we're extracting. */
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel lbl) { exists(lbl) }
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* @name Endpoint types
|
||||
* @description Maps endpoint type encodings to human-readable descriptions.
|
||||
* @kind table
|
||||
* @id js/ml-powered/model-building/endpoint-type-encodings
|
||||
*/
|
||||
|
||||
import experimental.adaptivethreatmodeling.EndpointTypes
|
||||
|
||||
from EndpointType type
|
||||
select type.getEncoding() as label, type.getDescription() as labelName order by label
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
* Maps ML-powered queries to their `EndpointType` for clearer labelling while evaluating ML model during training.
|
||||
*/
|
||||
|
||||
import experimental.adaptivethreatmodeling.SqlInjectionATM as SqlInjectionAtm
|
||||
import experimental.adaptivethreatmodeling.NosqlInjectionATM as NosqlInjectionAtm
|
||||
import experimental.adaptivethreatmodeling.TaintedPathATM as TaintedPathAtm
|
||||
import experimental.adaptivethreatmodeling.XssATM as XssAtm
|
||||
import experimental.adaptivethreatmodeling.XssThroughDomATM as XssThroughDomAtm
|
||||
import experimental.adaptivethreatmodeling.ShellCommandInjectionFromEnvironmentATM as ShellCommandInjectionFromEnvironmentAtm
|
||||
import experimental.adaptivethreatmodeling.AdaptiveThreatModeling
|
||||
|
||||
from string queryName, AtmConfig c, EndpointType e
|
||||
where
|
||||
(
|
||||
queryName = "SqlInjection" and
|
||||
c instanceof SqlInjectionAtm::SqlInjectionAtmConfig
|
||||
or
|
||||
queryName = "NosqlInjection" and
|
||||
c instanceof NosqlInjectionAtm::NosqlInjectionAtmConfig
|
||||
or
|
||||
queryName = "TaintedPath" and
|
||||
c instanceof TaintedPathAtm::TaintedPathAtmConfig
|
||||
or
|
||||
queryName = "Xss" and c instanceof XssAtm::DomBasedXssAtmConfig
|
||||
or
|
||||
queryName = "XssThroughDom" and c instanceof XssThroughDomAtm::XssThroughDomAtmConfig
|
||||
or
|
||||
queryName = "ShellCommandInjectionFromEnvironment" and
|
||||
c instanceof
|
||||
ShellCommandInjectionFromEnvironmentAtm::ShellCommandInjectionFromEnvironmentAtmConfig
|
||||
) and
|
||||
e = c.getASinkEndpointType()
|
||||
select queryName, e.getEncoding() as label
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
* Query for finding misclassified endpoints which we can use to debug ML-powered queries.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import experimental.adaptivethreatmodeling.AdaptiveThreatModeling
|
||||
import experimental.adaptivethreatmodeling.BaseScoring
|
||||
import experimental.adaptivethreatmodeling.EndpointFeatures as EndpointFeatures
|
||||
import semmle.javascript.security.dataflow.NosqlInjectionCustomizations
|
||||
|
||||
/** Gets the positive endpoint type for which you wish to find misclassified examples. */
|
||||
EndpointType getEndpointType() { result instanceof NosqlInjectionSinkType }
|
||||
|
||||
/** Get a positive endpoint. This will be run through the classifier to determine whether it is misclassified. */
|
||||
DataFlow::Node getAPositiveEndpoint() { result instanceof NosqlInjection::Sink }
|
||||
|
||||
/** An ATM configuration to find misclassified endpoints of type `getEndpointType()`. */
|
||||
class ExtractMisclassifiedEndpointsAtmConfig extends AtmConfig {
|
||||
ExtractMisclassifiedEndpointsAtmConfig() { this = "ExtractMisclassifiedEndpointsATMConfig" }
|
||||
|
||||
override predicate isEffectiveSink(DataFlow::Node sinkCandidate) {
|
||||
sinkCandidate = getAPositiveEndpoint()
|
||||
}
|
||||
|
||||
override EndpointType getASinkEndpointType() { result = getEndpointType() }
|
||||
}
|
||||
|
||||
/** Get an endpoint from `getAPositiveEndpoint()` that is incorrectly excluded from the results. */
|
||||
DataFlow::Node getAMisclassifedEndpoint() {
|
||||
any(ExtractMisclassifiedEndpointsAtmConfig config).isEffectiveSink(result) and
|
||||
not any(ScoringResults results).shouldResultBeIncluded(_, result)
|
||||
}
|
||||
|
||||
/** The token features for each misclassified endpoint. */
|
||||
query predicate tokenFeaturesForMisclassifiedEndpoints(
|
||||
DataFlow::Node endpoint, string featureName, string featureValue
|
||||
) {
|
||||
endpoint = getAMisclassifedEndpoint() and
|
||||
EndpointFeatures::tokenFeatures(endpoint, featureName, featureValue)
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
* Labels used in training and evaluation data to indicate knowledge about whether an endpoint is a
|
||||
* sink for a particular security query.
|
||||
*/
|
||||
|
||||
newtype TEndpointLabel =
|
||||
TSinkLabel() or
|
||||
TNotASinkLabel() or
|
||||
TUnknownLabel()
|
||||
|
||||
abstract class EndpointLabel extends TEndpointLabel {
|
||||
abstract string getEncoding();
|
||||
|
||||
string toString() { result = this.getEncoding() }
|
||||
}
|
||||
|
||||
class SinkLabel extends EndpointLabel, TSinkLabel {
|
||||
override string getEncoding() { result = "Sink" }
|
||||
}
|
||||
|
||||
class NotASinkLabel extends EndpointLabel, TNotASinkLabel {
|
||||
override string getEncoding() { result = "NotASink" }
|
||||
}
|
||||
|
||||
class UnknownLabel extends EndpointLabel, TUnknownLabel {
|
||||
override string getEncoding() { result = "Unknown" }
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*/
|
||||
|
||||
private import experimental.adaptivethreatmodeling.FeaturizationConfig
|
||||
|
||||
/**
|
||||
* A featurization config that featurizes all endpoints.
|
||||
*
|
||||
* This should only be used in extraction queries and tests.
|
||||
*/
|
||||
class NoRestrictionsFeaturizationConfig extends FeaturizationConfig {
|
||||
NoRestrictionsFeaturizationConfig() { this = "NoRestrictionsFeaturization" }
|
||||
|
||||
override DataFlow::Node getAnEndpointToFeaturize() { any() }
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
* Represents the security queries for which we currently have ML-powered versions.
|
||||
*/
|
||||
|
||||
newtype TQuery =
|
||||
TNosqlInjectionQuery() or
|
||||
TSqlInjectionQuery() or
|
||||
TTaintedPathQuery() or
|
||||
TXssQuery() or
|
||||
TXssThroughDomQuery() or
|
||||
TShellCommandInjectionFromEnvironmentQuery()
|
||||
|
||||
abstract class Query extends TQuery {
|
||||
abstract string getName();
|
||||
|
||||
string toString() { result = this.getName() }
|
||||
}
|
||||
|
||||
class NosqlInjectionQuery extends Query, TNosqlInjectionQuery {
|
||||
override string getName() { result = "NosqlInjection" }
|
||||
}
|
||||
|
||||
class SqlInjectionQuery extends Query, TSqlInjectionQuery {
|
||||
override string getName() { result = "SqlInjection" }
|
||||
}
|
||||
|
||||
class TaintedPathQuery extends Query, TTaintedPathQuery {
|
||||
override string getName() { result = "TaintedPath" }
|
||||
}
|
||||
|
||||
class XssQuery extends Query, TXssQuery {
|
||||
override string getName() { result = "Xss" }
|
||||
}
|
||||
|
||||
class XssThroughDomQuery extends Query, TXssThroughDomQuery {
|
||||
override string getName() { result = "XssThroughDom" }
|
||||
}
|
||||
|
||||
class ShellCommandInjectionFromEnvironmentQuery extends Query,
|
||||
TShellCommandInjectionFromEnvironmentQuery
|
||||
{
|
||||
override string getName() { result = "ShellCommandInjectionFromEnvironment" }
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
name: codeql/javascript-experimental-atm-model-building
|
||||
description: CodeQL libraries for building machine learning models for the experimental ML-powered queries
|
||||
extractor: javascript
|
||||
library: false
|
||||
groups:
|
||||
- javascript
|
||||
- experimental
|
||||
dependencies:
|
||||
codeql/javascript-experimental-atm-lib: ${workspace}
|
||||
codeql/javascript-experimental-atm-model: "0.3.1-2023-03-01-12h42m43s.strong-turtle-1xp3dqvv.ecb17d40286d14132b481c065a43459a7f0ba9059015b7a49c909c9f9ce5fec5"
|
||||
warnOnImplicitThis: true
|
||||
@@ -1,62 +0,0 @@
|
||||
# NoSQL database query built from user-controlled sources (experimental)
|
||||
If a database query is built from user-provided data without sufficient sanitization, a user may be able to run malicious database queries.
|
||||
|
||||
Note: This CodeQL query is an experimental query. Experimental queries generate alerts using machine learning. They might include more false positives but they will improve over time.
|
||||
|
||||
|
||||
## Recommendation
|
||||
Ensure that untrusted data is interpreted as a literal value and not as a query object, eg., by using an operator like MongoDB's `$eq`.
|
||||
|
||||
## Example
|
||||
In the following example, an `express.js` application is defining two endpoints that permit a user to query a MongoDB database.
|
||||
|
||||
In each case, the handler constructs two copies of the same query involving user input taken from the request object. In both handlers, the input is parsed using the `body-parser` library, which will transform the request data that arrives as a string to JSON objects.
|
||||
|
||||
In the first case, `/search1`, the input is used as a query object. This means that a malicious user is able to inject queries that select more data than the developer intended.
|
||||
|
||||
In the second case, `/search2`, parts of the input are converted to a string representation and then used with the `$eq` operator to construct a query object.
|
||||
|
||||
|
||||
```javascript
|
||||
const app = require("express")(),
|
||||
mongodb = require("mongodb"),
|
||||
bodyParser = require('body-parser');
|
||||
|
||||
const client = new MongoClient('mongodb://localhost:27017/test');
|
||||
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
|
||||
app.get("/search1", async function handler(req, res) {
|
||||
await client.connect();
|
||||
const db = client.db('test');
|
||||
const doc = db.collection('doc');
|
||||
|
||||
const result = doc.find({
|
||||
// BAD:
|
||||
// This is vulnerable.
|
||||
// Eg., req.body.title might be the object { $ne: "foobarbaz" }, and the
|
||||
// endpoint would return all data.
|
||||
title: req.body.title
|
||||
});
|
||||
|
||||
res.send(await result);
|
||||
});
|
||||
|
||||
app.get("/search2", async function handler(req, res) {
|
||||
await client.connect();
|
||||
const db = client.db('test');
|
||||
const doc = db.collection('doc');
|
||||
|
||||
// GOOD:
|
||||
// The input is converted to a string, and matched using the $eq operator.
|
||||
// At most one datum is returned.
|
||||
const result = await doc.find({ title: { $eq: `${req.body.title}` } });
|
||||
|
||||
res.send(await result);
|
||||
});
|
||||
```
|
||||
|
||||
## References
|
||||
* Acunetix Blog: [NoSQL Injections and How to Avoid Them](https://www.acunetix.com/blog/web-security-zone/nosql-injections/).
|
||||
* MongoDB: [$eq operator](https://docs.mongodb.com/manual/reference/operator/query/eq).
|
||||
* MongoDB: [$ne operator](https://docs.mongodb.com/manual/reference/operator/query/ne).
|
||||
@@ -1,24 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* @name NoSQL database query built from user-controlled sources (experimental)
|
||||
* @description Building a database query from user-controlled sources is vulnerable to insertion of
|
||||
* malicious code by the user.
|
||||
* @kind path-problem
|
||||
* @scored
|
||||
* @problem.severity error
|
||||
* @security-severity 8.8
|
||||
* @id js/ml-powered/nosql-injection
|
||||
* @tags experimental security
|
||||
* external/cwe/cwe-943
|
||||
*/
|
||||
|
||||
import ATM::ResultsInfo
|
||||
import DataFlow::PathGraph
|
||||
import experimental.adaptivethreatmodeling.NosqlInjectionATM
|
||||
|
||||
from AtmConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink, float score
|
||||
where cfg.hasBoostedFlowPath(source, sink, score)
|
||||
select sink.getNode(), source, sink,
|
||||
"(Experimental) This may be a database query that depends on $@. Identified using machine learning.",
|
||||
source.getNode(), "a user-provided value", score
|
||||
@@ -1,75 +0,0 @@
|
||||
|
||||
# Shell command built from environment values (experimental)
|
||||
|
||||
Dynamically constructing a shell command with values from the
|
||||
local environment, such as file paths, may inadvertently
|
||||
change the meaning of the shell command.
|
||||
|
||||
Such changes can occur when an environment value contains
|
||||
characters that the shell interprets in a special way, for instance
|
||||
quotes and spaces.
|
||||
|
||||
This can result in the shell command misbehaving, or even
|
||||
allowing a malicious user to execute arbitrary commands on the system.
|
||||
|
||||
Note: This CodeQL query is an experimental query. Experimental queries generate alerts using machine learning. They might include more false positives but they will improve over time.
|
||||
|
||||
## Recommendation
|
||||
|
||||
If possible, use hard-coded string literals to specify the
|
||||
shell command to run, and provide the dynamic arguments to the shell
|
||||
command separately to avoid interpretation by the shell.
|
||||
|
||||
Alternatively, if the shell command must be constructed
|
||||
dynamically, then add code to ensure that special characters in
|
||||
environment values do not alter the shell command unexpectedly.
|
||||
|
||||
## Example
|
||||
|
||||
The following example shows a dynamically constructed shell
|
||||
command that recursively removes a temporary directory that is located
|
||||
next to the currently executing JavaScript file. Such utilities are
|
||||
often found in custom build scripts.
|
||||
|
||||
```javascript
|
||||
var cp = require("child_process"),
|
||||
path = require("path");
|
||||
function cleanupTemp() {
|
||||
let cmd = "rm -rf " + path.join(__dirname, "temp");
|
||||
cp.execSync(cmd); // BAD
|
||||
}
|
||||
```
|
||||
|
||||
The shell command will, however, fail to work as intended if the
|
||||
absolute path of the script's directory contains spaces. In that
|
||||
case, the shell command will interpret the absolute path as multiple
|
||||
paths, instead of a single path.
|
||||
|
||||
For instance, if the absolute path of
|
||||
the temporary directory is "`/home/username/important project/temp`", then the shell command will recursively delete
|
||||
`"/home/username/important"` and `"project/temp"`,
|
||||
where the latter path gets resolved relative to the working directory
|
||||
of the JavaScript process.
|
||||
|
||||
Even worse, although less likely, a malicious user could
|
||||
provide the path `"/home/username/; cat /etc/passwd #/important
|
||||
project/temp"` in order to execute the command `"cat
|
||||
/etc/passwd"`.
|
||||
|
||||
To avoid such potentially catastrophic behaviors, provide the
|
||||
directory as an argument that does not get interpreted by a
|
||||
shell:
|
||||
|
||||
```javascript
|
||||
var cp = require("child_process"),
|
||||
path = require("path");
|
||||
function cleanupTemp() {
|
||||
let cmd = "rm",
|
||||
args = ["-rf", path.join(__dirname, "temp")];
|
||||
cp.execFileSync(cmd, args); // GOOD
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## References
|
||||
* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection)
|
||||
@@ -1,29 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* @name Shell command built from environment values
|
||||
* @description Building a shell command string with values from the enclosing
|
||||
* environment may cause subtle bugs or vulnerabilities.
|
||||
* @kind path-problem
|
||||
* @scored
|
||||
* @problem.severity warning
|
||||
* @security-severity 6.3
|
||||
* @precision high
|
||||
* @id js/ml-powered/shell-command-injection-from-environment
|
||||
* @tags experimental security
|
||||
* correctness
|
||||
* security
|
||||
* external/cwe/cwe-078
|
||||
* external/cwe/cwe-088
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import experimental.adaptivethreatmodeling.ShellCommandInjectionFromEnvironmentATM
|
||||
import ATM::ResultsInfo
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from AtmConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink, float score
|
||||
where cfg.hasBoostedFlowPath(source, sink, score)
|
||||
select sink.getNode(), source, sink,
|
||||
"(Experimental) This shell command depends on $@. Identified using machine learning.",
|
||||
source.getNode(), "an uncontrolled value", score
|
||||
@@ -1,46 +0,0 @@
|
||||
# SQL database query built from user-controlled sources (experimental)
|
||||
If a SQL query is built from user-provided data without sufficient sanitization, a malicious user may be able to run malicious database queries.
|
||||
|
||||
Note: This CodeQL query is an experimental query. Experimental queries generate alerts using machine learning. They might include more false positives but they will improve over time.
|
||||
|
||||
|
||||
## Recommendation
|
||||
Most database connector libraries offer a way of safely embedding untrusted data into a query by means of query parameters or prepared statements.
|
||||
|
||||
## Example
|
||||
In the following example, an `express.js` application is defining two endpoints that permit a user to query a postgres database.
|
||||
|
||||
The handler constructs two copies of the same SQL query involving user input taken from the request object, once unsafely using string concatenation, and once safely using query parameters.
|
||||
|
||||
In the first case, the query string `query1` is built by directly concatenating a user-supplied request parameter with some string literals. The parameter may include quote characters, so this code is vulnerable to a SQL injection attack.
|
||||
|
||||
In the second case, the parameter is embedded into the query string `query2` using query parameters. In this example, we use the API offered by the `pg` Postgres database connector library, but other libraries offer similar features. This version is immune to injection attacks.
|
||||
|
||||
|
||||
```javascript
|
||||
const app = require("express")(),
|
||||
pg = require("pg"),
|
||||
pool = new pg.Pool(config);
|
||||
|
||||
app.get("search", function handler(req, res) {
|
||||
// BAD: the category might have SQL special characters in it
|
||||
var query1 =
|
||||
"SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" +
|
||||
req.params.category +
|
||||
"' ORDER BY PRICE";
|
||||
pool.query(query1, [], function(err, results) {
|
||||
// process results
|
||||
});
|
||||
|
||||
// GOOD: use parameters
|
||||
var query2 =
|
||||
"SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=$1" + " ORDER BY PRICE";
|
||||
pool.query(query2, [req.params.category], function(err, results) {
|
||||
// process results
|
||||
});
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
## References
|
||||
* Wikipedia: [SQL injection](https://en.wikipedia.org/wiki/SQL_injection).
|
||||
@@ -1,24 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* @name SQL database query built from user-controlled sources (experimental)
|
||||
* @description Building a database query from user-controlled sources is vulnerable to insertion of
|
||||
* malicious code by the user.
|
||||
* @kind path-problem
|
||||
* @scored
|
||||
* @problem.severity error
|
||||
* @security-severity 8.8
|
||||
* @id js/ml-powered/sql-injection
|
||||
* @tags experimental security
|
||||
* external/cwe/cwe-089
|
||||
*/
|
||||
|
||||
import experimental.adaptivethreatmodeling.SqlInjectionATM
|
||||
import ATM::ResultsInfo
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from AtmConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink, float score
|
||||
where cfg.hasBoostedFlowPath(source, sink, score)
|
||||
select sink.getNode(), source, sink,
|
||||
"(Experimental) This may be a database query that depends on $@. Identified using machine learning.",
|
||||
source.getNode(), "a user-provided value", score
|
||||
@@ -1,42 +0,0 @@
|
||||
# Uncontrolled data used in path expression (experimental)
|
||||
Accessing files using paths constructed from user-controlled data can allow an attacker to access unexpected resources. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files.
|
||||
|
||||
Note: This CodeQL query is an experimental query. Experimental queries generate alerts using machine learning. They might include more false positives but they will improve over time.
|
||||
|
||||
|
||||
## Recommendation
|
||||
Validate user input before using it to construct a file path, either using an off-the-shelf library like the `sanitize-filename` npm package, or by performing custom validation.
|
||||
|
||||
Ideally, follow these rules:
|
||||
|
||||
* Do not allow more than a single "." character.
|
||||
* Do not allow directory separators such as "/" or "\\" (depending on the file system).
|
||||
* Do not rely on simply replacing problematic sequences such as "../". For example, after applying this filter to ".../...//", the resulting string would still be "../".
|
||||
* Use a whitelist of known good patterns.
|
||||
|
||||
## Example
|
||||
In the first example, a file name is read from an HTTP request and then used to access a file. However, a malicious user could enter a file name which is an absolute path, such as `"/etc/passwd"`.
|
||||
|
||||
In the second example, it appears that the user is restricted to opening a file within the `"user"` home directory. However, a malicious user could enter a file name containing special characters. For example, the string `"../../etc/passwd"` will result in the code reading the file located at `"/home/user/../../etc/passwd"`, which is the system's password file. This file would then be sent back to the user, giving them access to all the system's passwords.
|
||||
|
||||
|
||||
```javascript
|
||||
var fs = require('fs'),
|
||||
http = require('http'),
|
||||
url = require('url');
|
||||
|
||||
var server = http.createServer(function(req, res) {
|
||||
let path = url.parse(req.url, true).query.path;
|
||||
|
||||
// BAD: This could read any file on the file system
|
||||
res.write(fs.readFileSync(path));
|
||||
|
||||
// BAD: This could still read any file on the file system
|
||||
res.write(fs.readFileSync("/home/user/" + path));
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
## References
|
||||
* OWASP: [Path Traversal](https://owasp.org/www-community/attacks/Path_Traversal).
|
||||
* npm: [sanitize-filename](https://www.npmjs.com/package/sanitize-filename) package.
|
||||
@@ -1,28 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* @name Uncontrolled data used in path expression (experimental)
|
||||
* @description Accessing paths influenced by users can allow an attacker to access
|
||||
* unexpected resources.
|
||||
* @kind path-problem
|
||||
* @scored
|
||||
* @problem.severity error
|
||||
* @security-severity 7.5
|
||||
* @id js/ml-powered/path-injection
|
||||
* @tags experimental security
|
||||
* external/cwe/cwe-022
|
||||
* external/cwe/cwe-023
|
||||
* external/cwe/cwe-036
|
||||
* external/cwe/cwe-073
|
||||
* external/cwe/cwe-099
|
||||
*/
|
||||
|
||||
import ATM::ResultsInfo
|
||||
import DataFlow::PathGraph
|
||||
import experimental.adaptivethreatmodeling.TaintedPathATM
|
||||
|
||||
from AtmConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink, float score
|
||||
where cfg.hasBoostedFlowPath(source, sink, score)
|
||||
select sink.getNode(), source, sink,
|
||||
"(Experimental) This may be a path that depends on $@. Identified using machine learning.",
|
||||
source.getNode(), "a user-provided value", score
|
||||
@@ -1,32 +0,0 @@
|
||||
# Client-side cross-site scripting (experimental)
|
||||
Directly writing user input (for example, a URL query parameter) to a webpage without properly sanitizing the input first, allows for a cross-site scripting vulnerability.
|
||||
|
||||
This kind of vulnerability is also called *DOM-based* cross-site scripting, to distinguish it from other types of cross-site scripting.
|
||||
|
||||
Note: This CodeQL query is an experimental query. Experimental queries generate alerts using machine learning. They might include more false positives but they will improve over time.
|
||||
|
||||
|
||||
## Recommendation
|
||||
To guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references.
|
||||
|
||||
|
||||
## Example
|
||||
The following example shows part of the page URL being written directly to the document, leaving the website vulnerable to cross-site scripting.
|
||||
|
||||
|
||||
```javascript
|
||||
function setLanguageOptions() {
|
||||
var href = document.location.href,
|
||||
deflt = href.substring(href.indexOf("default=")+8);
|
||||
document.write("<OPTION value=1>"+deflt+"</OPTION>");
|
||||
document.write("<OPTION value=2>English</OPTION>");
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## References
|
||||
* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html).
|
||||
* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).
|
||||
* OWASP [DOM Based XSS](https://www.owasp.org/index.php/DOM_Based_XSS).
|
||||
* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting).
|
||||
* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* @name Client-side cross-site scripting (experimental)
|
||||
* @description Writing user input directly to the DOM allows for
|
||||
* a cross-site scripting vulnerability.
|
||||
* @kind path-problem
|
||||
* @scored
|
||||
* @problem.severity error
|
||||
* @security-severity 6.1
|
||||
* @id js/ml-powered/xss
|
||||
* @tags experimental security
|
||||
* external/cwe/cwe-079
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import ATM::ResultsInfo
|
||||
import DataFlow::PathGraph
|
||||
import experimental.adaptivethreatmodeling.XssATM
|
||||
|
||||
from AtmConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink, float score
|
||||
where cfg.hasBoostedFlowPath(source, sink, score)
|
||||
select sink.getNode(), source, sink,
|
||||
"(Experimental) This may be a cross-site scripting vulnerability due to $@. Identified using machine learning.",
|
||||
source.getNode(), "a user-provided value", score
|
||||
@@ -1,48 +0,0 @@
|
||||
# DOM text reinterpreted as HTML (experimental)
|
||||
|
||||
Extracting text from a DOM node and interpreting it as HTML can lead to a cross-site scripting vulnerability.
|
||||
|
||||
A webpage with this vulnerability reads text from the DOM, and afterwards adds the text as HTML to the DOM. Using text from the DOM as HTML effectively unescapes the text, and thereby invalidates any escaping done on the text. If an attacker is able to control the safe sanitized text, then this vulnerability can be exploited to perform a cross-site scripting attack.
|
||||
|
||||
Note: This CodeQL query is an experimental query. Experimental queries generate alerts using machine learning. They might include more false positives but they will improve over time.
|
||||
|
||||
## Recommendation
|
||||
|
||||
To guard against cross-site scripting, consider using contextual output encoding/escaping before writing text to the page, or one of the other solutions that are mentioned in the References section below.
|
||||
|
||||
## Example
|
||||
|
||||
The following example shows a webpage using a `data-target` attribute
|
||||
to select and manipulate a DOM element using the JQuery library. In the example, the
|
||||
`data-target` attribute is read into the `target` variable, and the
|
||||
`$` function is then supposed to use the `target` variable as a CSS
|
||||
selector to determine which element should be manipulated.
|
||||
|
||||
```javascript
|
||||
$("button").click(function () {
|
||||
var target = $(this).attr("data-target");
|
||||
$(target).hide();
|
||||
});
|
||||
```
|
||||
|
||||
However, if an attacker can control the `data-target` attribute,
|
||||
then the value of `target` can be used to cause the `$` function
|
||||
to execute arbitrary JavaScript.
|
||||
|
||||
The above vulnerability can be fixed by using `$.find` instead of `$`.
|
||||
The `$.find` function will only interpret `target` as a CSS selector
|
||||
and never as HTML, thereby preventing an XSS attack.
|
||||
|
||||
```javascript
|
||||
$("button").click(function () {
|
||||
var target = $(this).attr("data-target");
|
||||
$.find(target).hide();
|
||||
});
|
||||
```
|
||||
|
||||
## References
|
||||
* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html)
|
||||
* OWASP: [(Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html)
|
||||
* OWASP [DOM Based XSS](https://owasp.org/www-community/attacks/DOM_Based_XSS)
|
||||
* OWASP [Types of Cross-Site Scripting](https://owasp.org/www-community/Types_of_Cross-Site_Scripting)
|
||||
* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting)
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* @name DOM text reinterpreted as HTML (experimental)
|
||||
* @description Reinterpreting text from the DOM as HTML can lead
|
||||
* to a cross-site scripting vulnerability.
|
||||
* @kind path-problem
|
||||
* @scored
|
||||
* @problem.severity error
|
||||
* @security-severity 6.1
|
||||
* @id js/ml-powered/xss-through-dom
|
||||
* @tags experimental security
|
||||
* external/cwe/cwe-079 external/cwe/cwe-116
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import ATM::ResultsInfo
|
||||
import DataFlow::PathGraph
|
||||
import experimental.adaptivethreatmodeling.XssThroughDomATM
|
||||
|
||||
from AtmConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink, float score
|
||||
where cfg.hasBoostedFlowPath(source, sink, score)
|
||||
select sink.getNode(), source, sink,
|
||||
"(Experimental) $@ may be reinterpreted as HTML without escaping meta-characters. Identified using machine learning.",
|
||||
source.getNode(), "DOM text", score
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
lockVersion: 1.0.0
|
||||
dependencies:
|
||||
codeql/javascript-experimental-atm-model:
|
||||
version: 0.3.1-2023-03-01-12h42m43s.strong-turtle-1xp3dqvv.ecb17d40286d14132b481c065a43459a7f0ba9059015b7a49c909c9f9ce5fec5
|
||||
compiled: false
|
||||
@@ -1,2 +0,0 @@
|
||||
- description: ATM boosted Code Scanning queries for JavaScript
|
||||
- queries: .
|
||||
@@ -1,13 +0,0 @@
|
||||
name: codeql/javascript-experimental-atm-queries
|
||||
description: Experimental ML-powered queries for JavaScript
|
||||
language: javascript
|
||||
version: 0.4.10
|
||||
suites: codeql-suites
|
||||
defaultSuiteFile: codeql-suites/javascript-atm-code-scanning.qls
|
||||
groups:
|
||||
- javascript
|
||||
- experimental
|
||||
dependencies:
|
||||
codeql/javascript-experimental-atm-lib: ${workspace}
|
||||
codeql/javascript-experimental-atm-model: "0.3.1-2023-03-01-12h42m43s.strong-turtle-1xp3dqvv.ecb17d40286d14132b481c065a43459a7f0ba9059015b7a49c909c9f9ce5fec5"
|
||||
warnOnImplicitThis: true
|
||||
@@ -1,2 +0,0 @@
|
||||
**/*.testproj
|
||||
**/*.actual
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
lockVersion: 1.0.0
|
||||
dependencies:
|
||||
codeql/javascript-experimental-atm-model:
|
||||
version: 0.3.1-2023-03-01-12h42m43s.strong-turtle-1xp3dqvv.ecb17d40286d14132b481c065a43459a7f0ba9059015b7a49c909c9f9ce5fec5
|
||||
compiled: false
|
||||
@@ -1,2 +0,0 @@
|
||||
erroneousEndpoints
|
||||
erroneousConfidences
|
||||
@@ -1,90 +0,0 @@
|
||||
/**
|
||||
* ContradictoryEndpointCharacteristics.ql
|
||||
*
|
||||
* This tests surfaces endpoints that have a set of characteristics are logically incompatible with one another (e.g one
|
||||
* high-confidence characteristic that implies a non-sink and another that implies a sink). If the test surfaces any
|
||||
* such endpoints, this is a hint that some of our endpoint characteristics may be need to be adjusted.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
private import experimental.adaptivethreatmodeling.EndpointCharacteristics as EndpointCharacteristics
|
||||
private import experimental.adaptivethreatmodeling.EndpointTypes as EndpointTypes
|
||||
|
||||
/**
|
||||
* Holds if `characteristic1` and `characteristic2` are among the several pairs of currently known high-confidence
|
||||
* negative characteristics that apply to some known sinks.
|
||||
*
|
||||
* TODO: Experiment with lowering the confidence of `"FileSystemAccess"`, `"DOM"`, `"DatabaseAccess"`, and
|
||||
* `"JQueryArgument"`.
|
||||
*/
|
||||
private predicate knownContradictoryCharacteristics(
|
||||
EndpointCharacteristics::EndpointCharacteristic characteristic1,
|
||||
EndpointCharacteristics::EndpointCharacteristic characteristic2
|
||||
) {
|
||||
characteristic1 != characteristic2 and
|
||||
(
|
||||
characteristic1 = ["TaintedPathSink", "FileSystemAccess"] and
|
||||
characteristic2 = ["TaintedPathSink", "FileSystemAccess"]
|
||||
or
|
||||
characteristic1 = ["DomBasedXssSink", "DOM"] and
|
||||
characteristic2 = ["DomBasedXssSink", "DOM"]
|
||||
or
|
||||
characteristic1 = ["DomBasedXssSink", "JQueryArgument"] and
|
||||
characteristic2 = ["DomBasedXssSink", "JQueryArgument"]
|
||||
or
|
||||
characteristic1 = ["NosqlInjectionSink", "DatabaseAccess"] and
|
||||
characteristic2 = ["NosqlInjectionSink", "DatabaseAccess"]
|
||||
or
|
||||
characteristic1 = ["SqlInjectionSink", "DatabaseAccess"] and
|
||||
characteristic2 = ["SqlInjectionSink", "DatabaseAccess"]
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given endpoint has a self-contradictory combination of characteristics. Detects errors in our endpoint
|
||||
* characteristics. Lists the problematic characterisitics and their implications for all such endpoints, together with
|
||||
* an error message indicating why this combination is problematic.
|
||||
*/
|
||||
query predicate erroneousEndpoints(
|
||||
DataFlow::Node endpoint, EndpointCharacteristics::EndpointCharacteristic characteristic,
|
||||
EndpointTypes::EndpointType endpointClass, float confidence, string errorMessage
|
||||
) {
|
||||
// An endpoint's characteristics should not include positive indicators with medium/high confidence for more than one
|
||||
// class.
|
||||
exists(
|
||||
EndpointCharacteristics::EndpointCharacteristic characteristic2,
|
||||
EndpointTypes::EndpointType endpointClass2, float confidence2
|
||||
|
|
||||
endpointClass.getEncoding() != endpointClass2.getEncoding() and
|
||||
characteristic.appliesToEndpoint(endpoint) and
|
||||
characteristic2.appliesToEndpoint(endpoint) and
|
||||
characteristic.hasImplications(endpointClass, true, confidence) and
|
||||
characteristic2.hasImplications(endpointClass2, true, confidence2) and
|
||||
confidence > characteristic.mediumConfidence() and
|
||||
confidence2 > characteristic2.mediumConfidence() and
|
||||
// We currently know of several high-confidence negative characteristics that apply to some known sinks.
|
||||
not knownContradictoryCharacteristics(characteristic, characteristic2)
|
||||
) and
|
||||
errorMessage = "Endpoint has high-confidence positive indicators for multiple classes"
|
||||
or
|
||||
// An enpoint's characteristics should not include positive indicators with medium/high confidence for some class and
|
||||
// also include negative indicators with medium/high confidence for this same class.
|
||||
exists(EndpointCharacteristics::EndpointCharacteristic characteristic2, float confidence2 |
|
||||
characteristic.appliesToEndpoint(endpoint) and
|
||||
characteristic2.appliesToEndpoint(endpoint) and
|
||||
characteristic.hasImplications(endpointClass, true, confidence) and
|
||||
characteristic2.hasImplications(endpointClass, false, confidence2) and
|
||||
confidence > characteristic.mediumConfidence() and
|
||||
confidence2 > characteristic2.mediumConfidence()
|
||||
) and
|
||||
errorMessage = "Endpoint has high-confidence positive and negative indicators for the same class"
|
||||
}
|
||||
|
||||
query predicate erroneousConfidences(
|
||||
EndpointCharacteristics::EndpointCharacteristic characteristic, float confidence,
|
||||
string errorMessage
|
||||
) {
|
||||
characteristic.hasImplications(_, _, confidence) and
|
||||
(confidence < 0 or confidence > 1) and
|
||||
errorMessage = "Characteristic has an indicator with confidence outside of [0, 1]"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,42 +0,0 @@
|
||||
/**
|
||||
* EndpointFeatures.ql
|
||||
*
|
||||
* This tests generic token-based featurization of all endpoint candidates for all of the security
|
||||
* queries we support. This is in comparison to the `ExtractEndpointData.qlref` test, which tests
|
||||
* just the endpoints we extract in the training data.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import experimental.adaptivethreatmodeling.NosqlInjectionATM as NosqlInjectionAtm
|
||||
import experimental.adaptivethreatmodeling.SqlInjectionATM as SqlInjectionAtm
|
||||
import experimental.adaptivethreatmodeling.TaintedPathATM as TaintedPathAtm
|
||||
import experimental.adaptivethreatmodeling.XssATM as XssAtm
|
||||
import experimental.adaptivethreatmodeling.XssThroughDomATM as XssThroughDomAtm
|
||||
import experimental.adaptivethreatmodeling.ShellCommandInjectionFromEnvironmentATM as ShellCommandInjectionFromEnvironmentAtm
|
||||
import experimental.adaptivethreatmodeling.EndpointFeatures as EndpointFeatures
|
||||
import extraction.NoFeaturizationRestrictionsConfig
|
||||
private import experimental.adaptivethreatmodeling.EndpointCharacteristics as EndpointCharacteristics
|
||||
|
||||
query predicate tokenFeatures(DataFlow::Node endpoint, string featureName, string featureValue) {
|
||||
(
|
||||
not exists(any(NosqlInjectionAtm::NosqlInjectionAtmConfig cfg).getAReasonSinkExcluded(endpoint)) or
|
||||
not exists(any(SqlInjectionAtm::SqlInjectionAtmConfig cfg).getAReasonSinkExcluded(endpoint)) or
|
||||
not exists(any(TaintedPathAtm::TaintedPathAtmConfig cfg).getAReasonSinkExcluded(endpoint)) or
|
||||
not exists(any(XssAtm::DomBasedXssAtmConfig cfg).getAReasonSinkExcluded(endpoint)) or
|
||||
not exists(any(XssThroughDomAtm::XssThroughDomAtmConfig cfg).getAReasonSinkExcluded(endpoint)) or
|
||||
not exists(
|
||||
any(ShellCommandInjectionFromEnvironmentAtm::ShellCommandInjectionFromEnvironmentAtmConfig cfg)
|
||||
.getAReasonSinkExcluded(endpoint)
|
||||
) or
|
||||
any(EndpointCharacteristics::IsArgumentToModeledFunctionCharacteristic characteristic)
|
||||
.appliesToEndpoint(endpoint)
|
||||
) and
|
||||
EndpointFeatures::tokenFeatures(endpoint, featureName, featureValue)
|
||||
}
|
||||
|
||||
query predicate invalidTokenFeatures(
|
||||
DataFlow::Node endpoint, string featureName, string featureValue
|
||||
) {
|
||||
strictcount(string value | EndpointFeatures::tokenFeatures(endpoint, featureName, value)) > 1 and
|
||||
EndpointFeatures::tokenFeatures(endpoint, featureName, featureValue)
|
||||
}
|
||||
@@ -1,518 +0,0 @@
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/typed/typedClient.ts:14:30:14:30 | v |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/typed/typedClient.ts:22:33:22:33 | v |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/typed/typedClient.ts:23:33:23:33 | v |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/graphql.js:82:11:91:6 | JSON.st ... \\n }) |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/graphql.js:99:11:111:6 | JSON.st ... \\n }) |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/graphql.js:109:13:109:14 | id |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/json-schema-validator.js:26:25:26:29 | query |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/ldap.js:32:15:32:59 | `(\|(nam ... ame}))` |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/ldap.js:40:15:42:11 | `(\|(nam ... )}))` |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/ldap.js:64:5:64:49 | `(\|(nam ... ame}))` |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongodb.js:77:22:77:24 | tag |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongodb.js:85:20:85:22 | tag |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongoose.js:130:23:130:24 | id |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongoose.js:131:30:131:31 | id |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongooseModelClient.js:11:22:11:22 | v |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongooseModelClient.js:12:22:12:32 | req.body.id |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongooseModelClient.js:13:22:13:37 | `${req.body.id}` |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mysql.js:10:21:10:26 | [temp] |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mysql.js:10:22:10:25 | temp |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/pg-promise.js:26:13:26:25 | req.params.id |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/pg-promise.js:41:7:41:20 | req.params.foo |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/pg-promise.js:48:13:48:27 | req.params.name |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/pg-promise.js:55:13:55:27 | req.params.name |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/redis.js:52:28:52:30 | key |
|
||||
| DomBasedXssAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/tst3.js:16:23:16:41 | req.params.category |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:28:28:28:30 | cmd |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:29:33:29:35 | cmd |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:30:26:30:28 | cmd |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:31:26:31:28 | cmd |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:32:26:32:28 | cmd |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:39:26:39:28 | cmd |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:56:54:56:56 | cmd |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:85:37:85:54 | req.query.fileName |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/exec-sh2.js:10:40:10:46 | command |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/exec-sh.js:15:44:15:50 | command |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/other.js:33:12:33:69 | "http:/ ... ry.user |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/other.js:34:44:34:46 | cmd |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:7:33:7:38 | remote |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:9:29:9:34 | remote |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:20:35:20:40 | remote |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:26:35:26:40 | remote |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:31:27:31:40 | req.query.args |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:40:28:40:43 | req.query.remote |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:42:31:42:46 | req.query.remote |
|
||||
| DomBasedXssAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:46:34:46:49 | req.query.remote |
|
||||
| DomBasedXssAtmConfig | autogenerated/TaintedPath/handlebars.js:29:46:29:60 | req.params.path |
|
||||
| DomBasedXssAtmConfig | autogenerated/TaintedPath/handlebars.js:33:42:33:56 | req.params.name |
|
||||
| DomBasedXssAtmConfig | autogenerated/TaintedPath/handlebars.js:37:43:37:57 | req.params.name |
|
||||
| DomBasedXssAtmConfig | autogenerated/TaintedPath/handlebars.js:43:15:43:29 | req.params.path |
|
||||
| DomBasedXssAtmConfig | autogenerated/TaintedPath/handlebars.js:49:17:49:33 | req.params.prefix |
|
||||
| DomBasedXssAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:312:19:312:22 | path |
|
||||
| DomBasedXssAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:321:19:321:32 | normalizedPath |
|
||||
| DomBasedXssAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:328:19:328:32 | normalizedPath |
|
||||
| DomBasedXssAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:381:25:381:28 | path |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/classnames.js:7:47:7:69 | classNa ... w.name) |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/classnames.js:8:47:8:70 | classNa ... w.name) |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/classnames.js:9:47:9:70 | classNa ... w.name) |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/classnames.js:10:45:10:55 | window.name |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/classnames.js:11:47:11:64 | unsafeStyle('foo') |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/classnames.js:13:47:13:68 | safeSty ... w.name) |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/classnames.js:15:47:15:63 | clsx(window.name) |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/classnames.js:17:5:17:79 | documen ... <span>` |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/classnames.js:17:48:17:64 | clsx(window.name) |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/clipboard.ts:8:18:8:51 | clipboa ... /html') |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/clipboard.ts:43:22:43:55 | clipboa ... /html') |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/clipboard.ts:98:22:98:54 | dataTra ... /html') |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/dates.js:15:65:15:69 | taint |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/dates.js:17:49:17:53 | taint |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/dragAndDrop.ts:8:18:8:50 | dataTra ... /html') |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/dragAndDrop.ts:43:22:43:54 | dataTra ... /html') |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/event-handler-receiver.js:2:49:2:61 | location.href |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/jquery.js:7:20:7:26 | tainted |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/jquery.js:10:13:10:31 | location.toString() |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/jquery.js:34:13:34:16 | hash |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/nodemailer.js:10:30:10:47 | req.query.receiver |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/nodemailer.js:12:11:12:69 | `Hi, yo ... sage}.` |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/sanitiser.js:23:29:23:35 | tainted |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/sanitiser.js:30:29:30:35 | tainted |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/sanitiser.js:33:29:33:35 | tainted |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/sanitiser.js:38:29:38:35 | tainted |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/sanitiser.js:45:29:45:35 | tainted |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/stored-xss.js:12:35:12:38 | href |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/tst3.js:6:27:6:32 | data.w |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/tst3.js:11:36:11:41 | data.w |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/tst3.js:15:23:15:29 | data[p] |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:8:37:8:114 | documen ... t=")+8) |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:12:28:12:33 | target |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:15:37:15:42 | target |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:43:20:43:20 | s |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:83:29:83:52 | documen ... .search |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:86:31:86:54 | documen ... .search |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:87:28:87:51 | documen ... .search |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:357:20:357:25 | target |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:361:14:361:19 | target |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/various-concat-obfuscations.js:4:14:4:20 | tainted |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/various-concat-obfuscations.js:5:12:5:18 | tainted |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/various-concat-obfuscations.js:7:14:7:20 | tainted |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/various-concat-obfuscations.js:9:19:9:25 | tainted |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/various-concat-obfuscations.js:10:16:10:22 | tainted |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/various-concat-obfuscations.js:12:19:12:25 | tainted |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/DomBasedXss/various-concat-obfuscations.js:15:27:15:55 | (attrs. ... 'left') |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:5:11:5:11 | x |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:9:11:9:13 | foo |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:21:11:21:21 | foo + "bar" |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:27:19:27:21 | foo |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:33:11:33:22 | ["bar", foo] |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:33:19:33:21 | foo |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:68:19:68:21 | foo |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:89:11:89:26 | foo.match(/foo/) |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:95:11:95:22 | [foo, "bar"] |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:95:12:95:14 | foo |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:102:12:102:14 | foo |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:117:11:117:23 | req.params.id |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:128:11:128:52 | session ... ssion') |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:136:10:136:22 | req.params.id |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:148:33:148:35 | foo |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:171:11:171:17 | tainted |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:180:10:180:22 | req.params.id |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXss.js:32:5:32:22 | ['body', req.body] |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXss.js:32:14:32:21 | req.body |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXss.js:70:47:70:54 | req.body |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXss.js:99:31:99:38 | req.body |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXss.js:102:68:102:75 | req.body |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXssGood.js:19:45:19:57 | req.params.id |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ReflectedXss/live-server.js:6:28:6:34 | tainted |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ReflectedXss/live-server.js:12:28:12:34 | tainted |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ReflectedXss/partial.js:13:42:13:48 | req.url |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ReflectedXss/partial.js:40:42:40:50 | [req.url] |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ReflectedXss/partial.js:40:43:40:49 | req.url |
|
||||
| DomBasedXssAtmConfig | autogenerated/Xss/ReflectedXss/partial.js:49:38:49:44 | req.url |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/typed/typedClient.ts:14:24:14:32 | { id: v } |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/typed/typedClient.ts:22:27:22:35 | { id: v } |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/typed/typedClient.ts:23:27:23:35 | { id: v } |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/json-schema-validator.js:25:23:25:48 | JSON.pa ... y.data) |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/json-schema-validator.js:26:25:26:29 | query |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/json-schema-validator.js:50:23:50:48 | JSON.pa ... y.data) |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/ldap.js:64:5:64:49 | `(\|(nam ... ame}))` |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/marsdb-flow-to.js:10:17:10:18 | {} |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/marsdb.js:12:17:12:18 | {} |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/minimongo.js:14:17:14:18 | {} |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongodb.js:12:19:12:20 | {} |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongodb.js:48:19:48:20 | {} |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongodb.js:59:16:59:17 | {} |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongodb.js:106:17:106:18 | {} |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongodb_bodySafe.js:12:19:12:20 | {} |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongodb_bodySafe.js:23:19:23:20 | {} |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongoose.js:20:19:20:20 | {} |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongoose.js:76:12:76:16 | query |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongoose.js:81:37:81:41 | query |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongoose.js:86:46:86:50 | query |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongoose.js:88:51:88:55 | query |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongoose.js:90:49:90:53 | query |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongoose.js:93:43:93:47 | query |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongoose.js:95:48:95:52 | query |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongoose.js:97:46:97:50 | query |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongoose.js:99:44:99:48 | query |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongooseJsonParse.js:19:19:19:20 | {} |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/pg-promise.js:6:15:7:55 | "SELECT ... PRICE" |
|
||||
| NosqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/redis.js:52:28:52:30 | key |
|
||||
| NosqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:85:37:85:54 | req.query.fileName |
|
||||
| NosqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/other.js:33:12:33:69 | "http:/ ... ry.user |
|
||||
| NosqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/other.js:34:33:34:48 | { command: cmd } |
|
||||
| NosqlInjectionAtmConfig | autogenerated/TaintedPath/handlebars.js:29:38:29:62 | { path: ... .path } |
|
||||
| NosqlInjectionAtmConfig | autogenerated/TaintedPath/handlebars.js:33:34:33:58 | { name: ... .name } |
|
||||
| NosqlInjectionAtmConfig | autogenerated/TaintedPath/handlebars.js:37:35:37:59 | { name: ... .name } |
|
||||
| NosqlInjectionAtmConfig | autogenerated/TaintedPath/handlebars.js:41:33:44:5 | {\\n ... )\\n } |
|
||||
| NosqlInjectionAtmConfig | autogenerated/TaintedPath/handlebars.js:48:33:51:5 | {\\n ... "\\n } |
|
||||
| NosqlInjectionAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:312:19:312:22 | path |
|
||||
| NosqlInjectionAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:321:19:321:32 | normalizedPath |
|
||||
| NosqlInjectionAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:328:19:328:32 | normalizedPath |
|
||||
| NosqlInjectionAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:381:25:381:28 | path |
|
||||
| NosqlInjectionAtmConfig | autogenerated/TaintedPath/other-fs-libraries.js:62:37:62:47 | {cwd: path} |
|
||||
| NosqlInjectionAtmConfig | autogenerated/TaintedPath/other-fs-libraries.js:63:45:63:55 | {cwd: path} |
|
||||
| NosqlInjectionAtmConfig | autogenerated/TaintedPath/pupeteer.js:9:20:9:50 | { path: ... 'a4' } |
|
||||
| NosqlInjectionAtmConfig | autogenerated/TaintedPath/pupeteer.js:13:29:13:45 | { path: tainted } |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/clipboard.ts:19:26:19:28 | div |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/clipboard.ts:54:30:54:32 | div |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/dates.js:15:65:15:69 | taint |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/dates.js:17:49:17:53 | taint |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/dragAndDrop.ts:19:26:19:28 | div |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/dragAndDrop.ts:54:30:54:32 | div |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/nodemailer.js:8:22:14:3 | {\\n f ... OK\\n } |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/nodemailer.js:10:30:10:47 | req.query.receiver |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/tst3.js:6:27:6:32 | data.w |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/tst3.js:11:36:11:41 | data.w |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/tst3.js:15:23:15:29 | data[p] |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:15:37:15:42 | target |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:83:29:83:52 | documen ... .search |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:86:31:86:54 | documen ... .search |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:87:28:87:51 | documen ... .search |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:199:32:199:75 | {danger ... inted}} |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:200:32:200:75 | {danger ... inted}} |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:361:14:361:19 | target |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:442:25:442:40 | {"html": source} |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:444:35:444:50 | {"html": source} |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:5:11:5:11 | x |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:9:11:9:13 | foo |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:21:11:21:21 | foo + "bar" |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:27:11:27:23 | { prop: foo } |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:33:11:33:22 | ["bar", foo] |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:68:19:68:21 | foo |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:89:11:89:26 | foo.match(/foo/) |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:95:11:95:22 | [foo, "bar"] |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:102:12:102:14 | foo |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:117:11:117:23 | req.params.id |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:128:11:128:52 | session ... ssion') |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:136:10:136:22 | req.params.id |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:148:33:148:35 | foo |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:171:11:171:17 | tainted |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:180:10:180:22 | req.params.id |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXss.js:70:47:70:54 | req.body |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXss.js:99:31:99:38 | req.body |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXss.js:102:68:102:75 | req.body |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ReflectedXss/partial.js:13:42:13:48 | req.url |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ReflectedXss/partial.js:40:42:40:50 | [req.url] |
|
||||
| NosqlInjectionAtmConfig | autogenerated/Xss/ReflectedXss/partial.js:49:38:49:44 | req.url |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/ShellCommandInjectionFromEnvironment/tst_shell-command-injection-from-environment.js:5:33:5:60 | path.jo ... "temp") |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/ShellCommandInjectionFromEnvironment/tst_shell-command-injection-from-environment.js:6:26:6:53 | path.jo ... "temp") |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/ShellCommandInjectionFromEnvironment/tst_shell-command-injection-from-environment.js:8:26:8:53 | path.jo ... "temp") |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/ShellCommandInjectionFromEnvironment/tst_shell-command-injection-from-environment.js:9:30:9:57 | path.jo ... "temp") |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/TaintedPath.js:104:32:104:39 | realpath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/TaintedPath.js:104:32:104:39 | realpath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:117:7:117:44 | path |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:117:14:117:44 | fs.real ... y.path) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:122:7:122:10 | path |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:122:7:122:21 | path.startsWith |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:236:7:236:47 | path |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:236:14:236:47 | pathMod ... y.path) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:242:7:242:10 | path |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:242:7:242:20 | path.substring |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:242:7:242:40 | path.su ... length) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:247:7:247:10 | path |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:247:7:247:16 | path.slice |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:247:7:247:36 | path.sl ... length) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:254:7:254:47 | path |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:254:14:254:47 | pathMod ... y.path) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:260:7:260:56 | relative |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:260:18:260:56 | pathMod ... , path) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:261:6:261:13 | relative |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:261:6:261:24 | relative.startsWith |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:261:52:261:59 | relative |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:267:7:267:42 | newpath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:267:17:267:42 | pathMod ... e(path) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:268:7:268:85 | relativePath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:268:22:268:85 | pathMod ... ewpath) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:269:7:269:18 | relativePath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:275:7:275:42 | newpath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:275:17:275:42 | pathMod ... e(path) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:276:7:276:85 | relativePath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:276:22:276:85 | pathMod ... ewpath) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:277:7:277:18 | relativePath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:283:7:283:42 | newpath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:283:17:283:42 | pathMod ... e(path) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:284:7:284:85 | relativePath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:284:22:284:85 | pathMod ... ewpath) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:285:7:285:40 | pathMod ... vePath) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:291:7:291:42 | newpath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:291:17:291:42 | pathMod ... e(path) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:292:7:292:85 | relativePath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:292:22:292:85 | pathMod ... ewpath) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:293:7:293:40 | pathMod ... vePath) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:339:6:339:46 | path |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:339:13:339:46 | pathMod ... y.path) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:343:6:343:35 | abs |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:343:12:343:35 | pathMod ... e(path) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:345:6:345:8 | abs |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:352:5:352:12 | rootPath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:352:5:352:28 | rootPath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:352:16:352:28 | process.cwd() |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:353:33:353:32 | rootPath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:358:7:358:51 | requestPath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:358:21:358:51 | pathMod ... , path) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:362:5:362:25 | targetP ... ootPath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:362:5:362:25 | targetPath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:362:18:362:25 | rootPath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:368:3:368:3 | targetPath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:370:22:370:32 | requestPath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:370:22:370:32 | requestPath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:370:35:370:42 | rootPath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:370:35:370:42 | rootPath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:371:12:371:22 | requestPath |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/tainted-require.js:14:43:14:51 | __dirname |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/tainted-sendFile.js:20:7:20:33 | homeDir |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/tainted-sendFile.js:20:17:20:33 | path.resolve('.') |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/tainted-sendFile.js:21:16:21:22 | homeDir |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/tainted-sendFile.js:21:16:21:33 | homeDir + '/data/' |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/TaintedPath/tainted-sendFile.js:27:16:27:22 | homeDir |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:7:43:7:48 | files1 |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:7:43:7:48 | files1 |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:17:5:23:5 | return of function format |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:17:21:17:26 | files2 |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:17:21:17:26 | files2 |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:18:13:18:18 | files3 |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:18:13:18:23 | files3 |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:18:22:18:23 | [] |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:19:9:19:14 | files2 |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:19:9:19:19 | files2.sort |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:19:9:19:25 | files2.sort(sort) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:19:9:19:33 | files2. ... forEach |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:19:35:19:34 | files3 |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:19:45:19:48 | file |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:19:45:19:48 | file |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:20:13:20:18 | files3 |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:20:13:20:23 | files3.push |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:20:25:20:37 | '<li>' + file |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:20:34:20:37 | file |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:22:16:22:21 | files3 |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:22:16:22:26 | files3.join |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:22:16:22:30 | files3.join('') |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:25:43:25:48 | files1 |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:25:43:25:48 | files1 |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:29:13:29:18 | files2 |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:29:13:29:23 | files2 |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:29:22:29:23 | [] |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:30:9:30:14 | files1 |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:30:9:30:22 | files1.forEach |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:30:24:30:23 | files2 |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:30:34:30:37 | file |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:30:34:30:37 | file |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:31:13:31:18 | files2 |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:31:13:31:23 | files2.push |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:35:13:35:35 | files3 |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:35:22:35:35 | format(files2) |
|
||||
| ShellCommandInjectionFromEnvironmentAtmConfig | autogenerated/Xss/StoredXss/xss-through-filenames.js:35:29:35:34 | files2 |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/typed/typedClient.ts:14:30:14:30 | v |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/typed/typedClient.ts:22:33:22:33 | v |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/typed/typedClient.ts:23:33:23:33 | v |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/graphql.js:82:11:91:6 | JSON.st ... \\n }) |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/graphql.js:99:11:111:6 | JSON.st ... \\n }) |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/graphql.js:109:13:109:14 | id |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/json-schema-validator.js:25:23:25:48 | JSON.pa ... y.data) |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/json-schema-validator.js:26:25:26:29 | query |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/json-schema-validator.js:50:23:50:48 | JSON.pa ... y.data) |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/ldap.js:32:15:32:59 | `(\|(nam ... ame}))` |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/ldap.js:64:5:64:49 | `(\|(nam ... ame}))` |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongodb.js:77:22:77:24 | tag |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongodb.js:85:20:85:22 | tag |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongoose.js:130:23:130:24 | id |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongoose.js:131:30:131:31 | id |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongooseModelClient.js:11:22:11:22 | v |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongooseModelClient.js:12:22:12:32 | req.body.id |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongooseModelClient.js:13:22:13:37 | `${req.body.id}` |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mysql.js:10:21:10:26 | [temp] |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mysql.js:10:22:10:25 | temp |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/pg-promise.js:6:15:7:34 | "SELECT ... ategory |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/pg-promise.js:6:15:7:55 | "SELECT ... PRICE" |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/pg-promise.js:26:13:26:25 | req.params.id |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/pg-promise.js:41:7:41:20 | req.params.foo |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/pg-promise.js:48:13:48:27 | req.params.name |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/pg-promise.js:55:13:55:27 | req.params.name |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/redis.js:52:28:52:30 | key |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/tst3.js:7:16:8:34 | "SELECT ... ategory |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/tst3.js:7:16:8:55 | "SELECT ... PRICE" |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/tst3.js:16:23:16:41 | req.params.category |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/tst4.js:8:10:8:60 | 'SELECT ... rams.id |
|
||||
| SqlInjectionAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/tst.js:10:10:10:58 | 'SELECT ... rams.id |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:28:28:28:30 | cmd |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:29:33:29:35 | cmd |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:30:26:30:28 | cmd |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:31:26:31:28 | cmd |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:32:26:32:28 | cmd |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:39:26:39:28 | cmd |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:56:54:56:56 | cmd |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:85:37:85:54 | req.query.fileName |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/exec-sh2.js:10:40:10:46 | command |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/exec-sh.js:15:44:15:50 | command |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/other.js:33:12:33:69 | "http:/ ... ry.user |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/other.js:34:44:34:46 | cmd |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:7:33:7:38 | remote |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:9:29:9:34 | remote |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:18:35:18:40 | remote |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:20:35:20:40 | remote |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:24:35:24:40 | remote |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:26:35:26:40 | remote |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:31:27:31:40 | req.query.args |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:40:28:40:43 | req.query.remote |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:42:31:42:46 | req.query.remote |
|
||||
| SqlInjectionAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:46:34:46:49 | req.query.remote |
|
||||
| SqlInjectionAtmConfig | autogenerated/TaintedPath/handlebars.js:29:46:29:60 | req.params.path |
|
||||
| SqlInjectionAtmConfig | autogenerated/TaintedPath/handlebars.js:33:42:33:56 | req.params.name |
|
||||
| SqlInjectionAtmConfig | autogenerated/TaintedPath/handlebars.js:37:43:37:57 | req.params.name |
|
||||
| SqlInjectionAtmConfig | autogenerated/TaintedPath/handlebars.js:43:15:43:29 | req.params.path |
|
||||
| SqlInjectionAtmConfig | autogenerated/TaintedPath/handlebars.js:49:17:49:33 | req.params.prefix |
|
||||
| SqlInjectionAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:312:19:312:22 | path |
|
||||
| SqlInjectionAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:321:19:321:32 | normalizedPath |
|
||||
| SqlInjectionAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:328:19:328:32 | normalizedPath |
|
||||
| SqlInjectionAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:381:25:381:28 | path |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/classnames.js:10:45:10:55 | window.name |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/dates.js:15:65:15:69 | taint |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/dates.js:17:49:17:53 | taint |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/nodemailer.js:10:30:10:47 | req.query.receiver |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/nodemailer.js:12:11:12:69 | `Hi, yo ... sage}.` |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/tst3.js:6:27:6:32 | data.w |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/tst3.js:11:36:11:41 | data.w |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/tst3.js:15:23:15:29 | data[p] |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:15:37:15:42 | target |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:83:29:83:52 | documen ... .search |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/DomBasedXss/tst.js:86:31:86:54 | documen ... .search |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:5:11:5:11 | x |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:9:11:9:13 | foo |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:21:11:21:21 | foo + "bar" |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:27:19:27:21 | foo |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:33:19:33:21 | foo |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:68:19:68:21 | foo |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:89:11:89:26 | foo.match(/foo/) |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:95:12:95:14 | foo |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:102:12:102:14 | foo |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:117:11:117:23 | req.params.id |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:128:11:128:52 | session ... ssion') |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:136:10:136:22 | req.params.id |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:148:33:148:35 | foo |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:171:11:171:17 | tainted |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:180:10:180:22 | req.params.id |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXss.js:32:5:32:22 | ['body', req.body] |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXss.js:32:14:32:21 | req.body |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXss.js:70:47:70:54 | req.body |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXssGood.js:19:45:19:57 | req.params.id |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXssGood.js:49:34:49:43 | msg.length |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ReflectedXss/partial.js:13:42:13:48 | req.url |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ReflectedXss/partial.js:40:43:40:49 | req.url |
|
||||
| SqlInjectionAtmConfig | autogenerated/Xss/ReflectedXss/partial.js:49:38:49:44 | req.url |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/typed/typedClient.ts:14:30:14:30 | v |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/typed/typedClient.ts:22:33:22:33 | v |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/typed/typedClient.ts:23:33:23:33 | v |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/graphql.js:82:11:91:6 | JSON.st ... \\n }) |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/graphql.js:99:11:111:6 | JSON.st ... \\n }) |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/graphql.js:109:13:109:14 | id |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/json-schema-validator.js:26:25:26:29 | query |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/ldap.js:32:15:32:59 | `(\|(nam ... ame}))` |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/ldap.js:40:15:42:11 | `(\|(nam ... )}))` |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/ldap.js:64:5:64:49 | `(\|(nam ... ame}))` |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongodb.js:21:25:21:45 | '' + qu ... y.title |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongodb.js:24:25:24:50 | query.b ... bstr(1) |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongodb.js:77:22:77:24 | tag |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongodb.js:85:20:85:22 | tag |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongoose.js:130:23:130:24 | id |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongoose.js:131:30:131:31 | id |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongooseModelClient.js:11:22:11:22 | v |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongooseModelClient.js:12:22:12:32 | req.body.id |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mongooseModelClient.js:13:22:13:37 | `${req.body.id}` |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mysql.js:10:21:10:26 | [temp] |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/mysql.js:10:22:10:25 | temp |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/pg-promise.js:26:13:26:25 | req.params.id |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/pg-promise.js:41:7:41:20 | req.params.foo |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/pg-promise.js:48:13:48:27 | req.params.name |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/pg-promise.js:55:13:55:27 | req.params.name |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/redis.js:52:28:52:30 | key |
|
||||
| TaintedPathAtmConfig | autogenerated/NosqlAndSqlInjection/untyped/tst3.js:16:23:16:41 | req.params.category |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:28:28:28:30 | cmd |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:29:33:29:35 | cmd |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:30:26:30:28 | cmd |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:31:26:31:28 | cmd |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:32:26:32:28 | cmd |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:39:26:39:28 | cmd |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:56:54:56:56 | cmd |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/child_process-test.js:85:37:85:54 | req.query.fileName |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/exec-sh2.js:10:40:10:46 | command |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/exec-sh.js:15:44:15:50 | command |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/other.js:33:12:33:69 | "http:/ ... ry.user |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/CommandInjection/other.js:34:44:34:46 | cmd |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:7:33:7:38 | remote |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:9:29:9:34 | remote |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:20:35:20:40 | remote |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:26:35:26:40 | remote |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:31:27:31:40 | req.query.args |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:40:28:40:43 | req.query.remote |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:42:31:42:46 | req.query.remote |
|
||||
| TaintedPathAtmConfig | autogenerated/ShellCommandInjectionFromEnvironment/SecondOrderCommandInjection/second-order.js:46:34:46:49 | req.query.remote |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/TaintedPath.js:115:12:115:51 | path.re ... /g, '') |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/TaintedPath.js:116:12:116:36 | path.re ... /g, '') |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/TaintedPath.js:128:11:128:50 | path.re ... /g, '') |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/TaintedPath.js:129:12:129:36 | path.re ... /g, '') |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/handlebars.js:29:46:29:60 | req.params.path |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/handlebars.js:33:42:33:56 | req.params.name |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/handlebars.js:37:43:37:57 | req.params.name |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/handlebars.js:43:15:43:29 | req.params.path |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/handlebars.js:49:17:49:33 | req.params.prefix |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:21:14:21:49 | pathMod ... y.path) |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:31:14:31:49 | pathMod ... y.path) |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:54:14:54:49 | pathMod ... y.path) |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:73:14:73:56 | pathMod ... y.path) |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:94:14:94:49 | pathMod ... y.path) |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:106:14:106:49 | pathMod ... y.path) |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:117:14:117:44 | fs.real ... y.path) |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:130:14:130:49 | pathMod ... y.path) |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:139:14:139:62 | pathMod ... y.path) |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:148:14:148:58 | 'foo/' ... y.path) |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:160:14:160:49 | pathMod ... y.path) |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:214:14:214:49 | pathMod ... y.path) |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:219:10:219:33 | decodeU ... t(path) |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:226:14:226:70 | pathMod ... g, ' ') |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:230:12:230:36 | path.re ... /g, '') |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:236:14:236:47 | pathMod ... y.path) |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:254:14:254:47 | pathMod ... y.path) |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:312:19:312:22 | path |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:321:19:321:32 | normalizedPath |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:328:19:328:32 | normalizedPath |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:339:13:339:46 | pathMod ... y.path) |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:381:25:381:28 | path |
|
||||
| TaintedPathAtmConfig | autogenerated/TaintedPath/normalizedPaths.js:385:14:385:46 | pathMod ... uery.x) |
|
||||
| TaintedPathAtmConfig | autogenerated/Xss/DomBasedXss/nodemailer.js:10:30:10:47 | req.query.receiver |
|
||||
| TaintedPathAtmConfig | autogenerated/Xss/DomBasedXss/nodemailer.js:12:11:12:69 | `Hi, yo ... sage}.` |
|
||||
| TaintedPathAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:117:11:117:23 | req.params.id |
|
||||
| TaintedPathAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:136:10:136:22 | req.params.id |
|
||||
| TaintedPathAtmConfig | autogenerated/Xss/ExceptionXss/exception-xss.js:180:10:180:22 | req.params.id |
|
||||
| TaintedPathAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXss.js:32:5:32:22 | ['body', req.body] |
|
||||
| TaintedPathAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXss.js:32:14:32:21 | req.body |
|
||||
| TaintedPathAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXss.js:70:47:70:54 | req.body |
|
||||
| TaintedPathAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXss.js:99:31:99:38 | req.body |
|
||||
| TaintedPathAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXss.js:102:68:102:75 | req.body |
|
||||
| TaintedPathAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXssGood.js:19:45:19:57 | req.params.id |
|
||||
| TaintedPathAtmConfig | autogenerated/Xss/ReflectedXss/ReflectedXssGood.js:49:34:49:43 | msg.length |
|
||||
| TaintedPathAtmConfig | autogenerated/Xss/ReflectedXss/partial.js:13:42:13:48 | req.url |
|
||||
| TaintedPathAtmConfig | autogenerated/Xss/ReflectedXss/partial.js:40:42:40:50 | [req.url] |
|
||||
| TaintedPathAtmConfig | autogenerated/Xss/ReflectedXss/partial.js:40:43:40:49 | req.url |
|
||||
| TaintedPathAtmConfig | autogenerated/Xss/ReflectedXss/partial.js:49:38:49:44 | req.url |
|
||||
| XssThroughDomAtmConfig | autogenerated/Xss/XssThroughDom/xss-through-dom.js:109:45:109:55 | this.el.src |
|
||||
| XssThroughDomAtmConfig | autogenerated/Xss/XssThroughDom/xss-through-dom.js:122:53:122:70 | ev.target.files[0] |
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* ExtractEndpointDataInference.ql
|
||||
*
|
||||
* This test surfaces the endpoints that pass the endpoint filters and have flow from a source for each query config,
|
||||
* and are therefore used as candidates for scoring at inference time.
|
||||
*
|
||||
* This is equivalent to ExtractEndpointDataTraining.qlref, but testing the inference endpoints rather than the training
|
||||
* endpoints. It detects CodeQL changes that impact the endpoints that get scored at inference time.
|
||||
*
|
||||
* This test does not actually score the endpoints and test for changes in the model predictions: that gets done in the
|
||||
* integration tests.
|
||||
*/
|
||||
|
||||
private import javascript as JS
|
||||
import extraction.NoFeaturizationRestrictionsConfig
|
||||
private import experimental.adaptivethreatmodeling.ATMConfig as AtmConfig
|
||||
private import experimental.adaptivethreatmodeling.NosqlInjectionATM as NosqlInjectionAtm
|
||||
private import experimental.adaptivethreatmodeling.SqlInjectionATM as SqlInjectionAtm
|
||||
private import experimental.adaptivethreatmodeling.TaintedPathATM as TaintedPathAtm
|
||||
private import experimental.adaptivethreatmodeling.XssATM as XssAtm
|
||||
private import experimental.adaptivethreatmodeling.XssThroughDomATM as XssThroughDomAtm
|
||||
private import experimental.adaptivethreatmodeling.ShellCommandInjectionFromEnvironmentATM as ShellCommandInjectionFromEnvironmentAtm
|
||||
|
||||
query predicate isSinkCandidateForQuery(
|
||||
AtmConfig::AtmConfig queryConfig, JS::DataFlow::PathNode sink
|
||||
) {
|
||||
queryConfig.isSinkCandidateWithFlow(sink)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
extraction/ExtractEndpointDataTraining.ql
|
||||
@@ -1,33 +0,0 @@
|
||||
nosqlFilteredTruePositives
|
||||
| autogenerated/NosqlAndSqlInjection/untyped/mongoose.js:111:14:111:18 | query | not a direct argument to a likely external library call or a heuristic sink (nosql) |
|
||||
sqlFilteredTruePositives
|
||||
| autogenerated/NosqlAndSqlInjection/untyped/tst2.js:7:13:7:45 | select ... e id = | not an argument to a likely external library call or a heuristic sink |
|
||||
| autogenerated/NosqlAndSqlInjection/untyped/tst2.js:7:48:7:60 | req.params.id | not an argument to a likely external library call or a heuristic sink |
|
||||
taintedPathFilteredTruePositives
|
||||
| autogenerated/TaintedPath/TaintedPath.js:66:26:66:31 | "SAFE" | not a direct argument to a likely external library call or a heuristic sink (tainted path) |
|
||||
| autogenerated/TaintedPath/TaintedPath.js:71:26:71:45 | Cookie.get("unsafe") | not a direct argument to a likely external library call or a heuristic sink (tainted path) |
|
||||
xssFilteredTruePositives
|
||||
| autogenerated/Xss/DomBasedXss/classnames.js:17:32:17:79 | `<span ... <span>` | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/d3.js:12:20:12:29 | getTaint() | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/d3.js:14:20:14:29 | getTaint() | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/express.js:7:15:7:33 | req.param("wobble") | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/jwt-server.js:11:19:11:29 | decoded.foo | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/trusted-types.js:2:71:2:71 | x | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/trusted-types.js:5:71:5:76 | 'safe' | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/trusted-types.js:8:71:8:71 | x | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/tst.js:316:35:316:42 | location | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/typeahead.js:10:16:10:18 | loc | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/typeahead.js:25:18:25:20 | val | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
xssThroughDomFilteredTruePositives
|
||||
| autogenerated/Xss/DomBasedXss/classnames.js:17:32:17:79 | `<span ... <span>` | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/d3.js:12:20:12:29 | getTaint() | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/d3.js:14:20:14:29 | getTaint() | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/express.js:7:15:7:33 | req.param("wobble") | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/jwt-server.js:11:19:11:29 | decoded.foo | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/trusted-types.js:2:71:2:71 | x | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/trusted-types.js:5:71:5:76 | 'safe' | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/trusted-types.js:8:71:8:71 | x | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/tst.js:316:35:316:42 | location | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/typeahead.js:10:16:10:18 | loc | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
| autogenerated/Xss/DomBasedXss/typeahead.js:25:18:25:20 | val | not a direct argument to a likely external library call or a heuristic sink (xss) |
|
||||
shellCommandInjectionFromEnvironmentAtmFilteredTruePositives
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* FilteredTruePositives.ql
|
||||
*
|
||||
* This test checks several components of the endpoint filters for each query to see whether they
|
||||
* filter out any known sinks. It explicitly does not check the endpoint filtering step that's based
|
||||
* on whether the endpoint is an argument to a modeled function, since this necessarily filters out
|
||||
* all known sinks. However, we can test all the other filtering steps against the set of known
|
||||
* sinks.
|
||||
*
|
||||
* Ideally, the sink endpoint filters would have perfect recall and therefore each of the predicates
|
||||
* in this test would have zero results. However, in some cases we have chosen to sacrifice recall
|
||||
* when we perceive the improved precision of the results to be worth the drop in recall.
|
||||
*/
|
||||
|
||||
import semmle.javascript.security.dataflow.NosqlInjectionCustomizations
|
||||
import semmle.javascript.security.dataflow.SqlInjectionCustomizations
|
||||
import semmle.javascript.security.dataflow.DomBasedXssCustomizations
|
||||
import semmle.javascript.security.dataflow.ShellCommandInjectionFromEnvironmentCustomizations
|
||||
import experimental.adaptivethreatmodeling.NosqlInjectionATM as NosqlInjectionAtm
|
||||
import experimental.adaptivethreatmodeling.SqlInjectionATM as SqlInjectionAtm
|
||||
import experimental.adaptivethreatmodeling.TaintedPathATM as TaintedPathAtm
|
||||
import experimental.adaptivethreatmodeling.XssATM as XssAtm
|
||||
import experimental.adaptivethreatmodeling.XssThroughDomATM as XssThroughDomAtm
|
||||
import experimental.adaptivethreatmodeling.ShellCommandInjectionFromEnvironmentATM as ShellCommandInjectionFromEnvironmentAtm
|
||||
|
||||
query predicate nosqlFilteredTruePositives(DataFlow::Node endpoint, string reason) {
|
||||
endpoint instanceof NosqlInjection::Sink and
|
||||
reason = any(NosqlInjectionAtm::NosqlInjectionAtmConfig cfg).getAReasonSinkExcluded(endpoint) and
|
||||
not reason = ["argument to modeled function", "modeled sink", "modeled database access"]
|
||||
}
|
||||
|
||||
query predicate sqlFilteredTruePositives(DataFlow::Node endpoint, string reason) {
|
||||
endpoint instanceof SqlInjection::Sink and
|
||||
reason = any(SqlInjectionAtm::SqlInjectionAtmConfig cfg).getAReasonSinkExcluded(endpoint) and
|
||||
reason != "argument to modeled function"
|
||||
}
|
||||
|
||||
query predicate taintedPathFilteredTruePositives(DataFlow::Node endpoint, string reason) {
|
||||
endpoint instanceof TaintedPath::Sink and
|
||||
reason = any(TaintedPathAtm::TaintedPathAtmConfig cfg).getAReasonSinkExcluded(endpoint) and
|
||||
reason != "argument to modeled function"
|
||||
}
|
||||
|
||||
query predicate xssFilteredTruePositives(DataFlow::Node endpoint, string reason) {
|
||||
endpoint instanceof DomBasedXss::Sink and
|
||||
reason = any(XssAtm::DomBasedXssAtmConfig cfg).getAReasonSinkExcluded(endpoint) and
|
||||
reason != "argument to modeled function"
|
||||
}
|
||||
|
||||
query predicate xssThroughDomFilteredTruePositives(DataFlow::Node endpoint, string reason) {
|
||||
endpoint instanceof DomBasedXss::Sink and
|
||||
reason = any(XssThroughDomAtm::XssThroughDomAtmConfig cfg).getAReasonSinkExcluded(endpoint) and
|
||||
reason != "argument to modeled function"
|
||||
}
|
||||
|
||||
query predicate shellCommandInjectionFromEnvironmentAtmFilteredTruePositives(
|
||||
DataFlow::Node endpoint, string reason
|
||||
) {
|
||||
endpoint instanceof ShellCommandInjectionFromEnvironment::Sink and
|
||||
reason =
|
||||
any(ShellCommandInjectionFromEnvironmentAtm::ShellCommandInjectionFromEnvironmentAtmConfig cfg)
|
||||
.getAReasonSinkExcluded(endpoint) and
|
||||
reason != "argument to modeled function"
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
# autogenerated folder
|
||||
|
||||
This folder contains test data for the ATM endpoint CodeQL tests that has been autogenerated from the standard JS CodeQL libraries.
|
||||
|
||||
It is helpful, but not required, to periodically update this test data to incorporate new test data introduced in the standard JS CodeQL libraries.
|
||||
|
||||
To update this test data, run `python /path/to/codeql-lib/ql/javascript/test/update_endpoint_test_files.py`.
|
||||
|
||||
For more information view the source code of [`update_endpoint_test_files.py`](../../update_endpoint_test_files.py).
|
||||
@@ -1,13 +0,0 @@
|
||||
declare module "mongodb" {
|
||||
interface Collection {
|
||||
find(query: any): any;
|
||||
}
|
||||
}
|
||||
declare module "mongoose" {
|
||||
interface Model {
|
||||
find(query: any): any;
|
||||
}
|
||||
interface Query {
|
||||
find(query: any): any;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import * as mongodb from "mongodb";
|
||||
|
||||
const express = require("express") as any;
|
||||
const bodyParser = require("body-parser") as any;
|
||||
|
||||
declare function getCollection(): mongodb.Collection;
|
||||
|
||||
let app = express();
|
||||
|
||||
app.use(bodyParser.json());
|
||||
|
||||
app.post("/find", (req, res) => {
|
||||
let v = JSON.parse(req.body.x);
|
||||
getCollection().find({ id: v }); // NOT OK
|
||||
});
|
||||
|
||||
import * as mongoose from "mongoose";
|
||||
declare function getMongooseModel(): mongoose.Model;
|
||||
declare function getMongooseQuery(): mongoose.Query;
|
||||
app.post("/find", (req, res) => {
|
||||
let v = JSON.parse(req.body.x);
|
||||
getMongooseModel().find({ id: v }); // NOT OK
|
||||
getMongooseQuery().find({ id: v }); // NOT OK
|
||||
});
|
||||
@@ -1,13 +0,0 @@
|
||||
let dbClient = require("mongodb").MongoClient,
|
||||
db = null;
|
||||
module.exports = {
|
||||
db: () => {
|
||||
return db;
|
||||
},
|
||||
connect: fn => {
|
||||
dbClient.connect(process.env.DB_URL, {}, (err, client) => {
|
||||
db = client.db(process.env.DB_NAME);
|
||||
return fn(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,121 +0,0 @@
|
||||
var express = require('express');
|
||||
var app = express();
|
||||
|
||||
import { Octokit } from "@octokit/core";
|
||||
const kit = new Octokit();
|
||||
|
||||
app.get('/post/:id', function(req, res) {
|
||||
const id = req.params.id;
|
||||
// NOT OK
|
||||
const response = kit.graphql(`
|
||||
query {
|
||||
repository(owner: "github", name: "${id}") {
|
||||
object(expression: "master:foo") {
|
||||
... on Blob {
|
||||
text
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
import { graphql, withCustomRequest } from "@octokit/graphql";
|
||||
|
||||
app.get('/user/:id/', function(req, res) {
|
||||
const id = req.params.id;
|
||||
const response = graphql(`foo ${id}`); // NOT OK
|
||||
|
||||
const myGraphql = withCustomRequest(request);
|
||||
const response = myGraphql(`foo ${id}`); // NOT OK
|
||||
|
||||
const withDefaults = graphql.defaults({});
|
||||
withDefaults(`foo ${id}`); // NOT OK
|
||||
});
|
||||
|
||||
const { request } = require("@octokit/request");
|
||||
|
||||
app.get('/article/:id/', async function(req, res) {
|
||||
const id = req.params.id;
|
||||
const result = await request("POST /graphql", {
|
||||
headers: {
|
||||
authorization: "token 0000000000000000000000000000000000000001",
|
||||
},
|
||||
query: `foo ${id}`, // NOT OK
|
||||
});
|
||||
|
||||
const withDefaults = request.defaults({});
|
||||
withDefaults("POST /graphql", { query: `foo ${id}` }); // NOT OK
|
||||
});
|
||||
|
||||
import { Octokit as Core } from "@octokit/rest";
|
||||
const kit2 = new Core();
|
||||
|
||||
app.get('/event/:id/', async function(req, res) {
|
||||
const id = req.params.id;
|
||||
const result = await kit2.graphql(`foo ${id}`); // NOT OK
|
||||
|
||||
const result2 = await kit2.request("POST /graphql", { query: `foo ${id}` }); // NOT OK
|
||||
});
|
||||
|
||||
import { graphql as nativeGraphql, buildSchema } from 'graphql';
|
||||
var schema = buildSchema(`
|
||||
type Query {
|
||||
hello: String
|
||||
}
|
||||
`);
|
||||
var root = {
|
||||
hello: () => {
|
||||
return 'Hello world!';
|
||||
},
|
||||
};
|
||||
|
||||
app.get('/thing/:id', async function(req, res) {
|
||||
const id = req.query.id;
|
||||
const result = await nativeGraphql(schema, "{ foo" + id + " }", root); // NOT OK
|
||||
|
||||
fetch("https://my-grpahql-server.com/graphql", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
// NOT OK
|
||||
query: `{
|
||||
thing {
|
||||
name
|
||||
url
|
||||
${id}
|
||||
}
|
||||
}`
|
||||
})
|
||||
})
|
||||
|
||||
fetch("https://my-grpahql-server.com/graphql", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
// OK
|
||||
query: `{
|
||||
thing {
|
||||
name
|
||||
url
|
||||
$id
|
||||
}
|
||||
}`,
|
||||
variables: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
const github = require('@actions/github');
|
||||
app.get('/event/:id/', async function(req, res) {
|
||||
const kit = github.getOctokit("foo")
|
||||
|
||||
const id = req.params.id;
|
||||
const result = await kit.graphql(`foo ${id}`); // NOT OK
|
||||
});
|
||||
@@ -1,64 +0,0 @@
|
||||
import Ajv from 'ajv';
|
||||
import express from 'express';
|
||||
import { MongoClient } from 'mongodb';
|
||||
|
||||
const app = express();
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
date: { type: 'string' },
|
||||
title: { type: 'string' },
|
||||
},
|
||||
};
|
||||
const ajv = new Ajv();
|
||||
const checkSchema = ajv.compile(schema);
|
||||
|
||||
function validate(x) {
|
||||
return x != null;
|
||||
}
|
||||
|
||||
app.post('/documents/find', (req, res) => {
|
||||
MongoClient.connect('mongodb://localhost:27017/test', (err, db) => {
|
||||
let doc = db.collection('doc');
|
||||
|
||||
const query = JSON.parse(req.query.data);
|
||||
if (checkSchema(query)) {
|
||||
doc.find(query); // OK
|
||||
}
|
||||
if (ajv.validate(schema, query)) {
|
||||
doc.find(query); // OK
|
||||
}
|
||||
if (validate(query)) {
|
||||
doc.find(query); // NOT OK - validate() doesn't sanitize
|
||||
}
|
||||
doc.find(query); // NOT OK
|
||||
});
|
||||
});
|
||||
|
||||
import Joi from 'joi';
|
||||
|
||||
const joiSchema = Joi.object({
|
||||
date: Joi.string().required(),
|
||||
title: Joi.string().required()
|
||||
}).with('date', 'title');
|
||||
|
||||
app.post('/documents/insert', (req, res) => {
|
||||
MongoClient.connect('mongodb://localhost:27017/test', async (err, db) => {
|
||||
let doc = db.collection('doc');
|
||||
|
||||
const query = JSON.parse(req.query.data);
|
||||
const validate = joiSchema.validate(query);
|
||||
if (!validate.error) {
|
||||
doc.find(query); // OK
|
||||
} else {
|
||||
doc.find(query); // NOT OK
|
||||
}
|
||||
try {
|
||||
await joiSchema.validateAsync(query);
|
||||
doc.find(query); // OK - but still flagged [INCONSISTENCY]
|
||||
} catch (e) {
|
||||
doc.find(query); // NOT OK
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,71 +0,0 @@
|
||||
const http = require("http");
|
||||
const url = require("url");
|
||||
const ldap = require("ldapjs");
|
||||
const client = ldap.createClient({
|
||||
url: "ldap://127.0.0.1:1389",
|
||||
});
|
||||
|
||||
// https://github.com/vesse/node-ldapauth-fork/commit/3feea43e243698bcaeffa904a7324f4d96df60e4
|
||||
const sanitizeInput = function (input) {
|
||||
return input
|
||||
.replace(/\*/g, "\\2a")
|
||||
.replace(/\(/g, "\\28")
|
||||
.replace(/\)/g, "\\29")
|
||||
.replace(/\\/g, "\\5c")
|
||||
.replace(/\0/g, "\\00")
|
||||
.replace(/\//g, "\\2f");
|
||||
};
|
||||
|
||||
const server = http.createServer((req, res) => {
|
||||
let q = url.parse(req.url, true);
|
||||
|
||||
let username = q.query.username;
|
||||
|
||||
var opts1 = {
|
||||
filter: `(|(name=${username})(username=${username}))`,
|
||||
};
|
||||
|
||||
client.search("o=example", opts1, function (err, res) {}); // NOT OK
|
||||
|
||||
client.search(
|
||||
"o=example",
|
||||
{ filter: `(|(name=${username})(username=${username}))` }, // NOT OK
|
||||
function (err, res) {}
|
||||
);
|
||||
|
||||
// GOOD
|
||||
client.search(
|
||||
"o=example",
|
||||
{ // OK
|
||||
filter: `(|(name=${sanitizeInput(username)})(username=${sanitizeInput(
|
||||
username
|
||||
)}))`,
|
||||
},
|
||||
function (err, res) {}
|
||||
);
|
||||
|
||||
// GOOD (https://github.com/ldapjs/node-ldapjs/issues/181)
|
||||
let f = new OrFilter({
|
||||
filters: [
|
||||
new EqualityFilter({
|
||||
attribute: "name",
|
||||
value: username,
|
||||
}),
|
||||
new EqualityFilter({
|
||||
attribute: "username",
|
||||
value: username,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
client.search("o=example", { filter: f }, function (err, res) {});
|
||||
|
||||
const parsedFilter = ldap.parseFilter(
|
||||
`(|(name=${username})(username=${username}))`
|
||||
);
|
||||
client.search("o=example", { filter: parsedFilter }, function (err, res) {}); // NOT OK
|
||||
|
||||
const dn = ldap.parseDN(`cn=${username}`, function (err, dn) {}); // NOT OK
|
||||
});
|
||||
|
||||
server.listen(389, () => {});
|
||||
@@ -1,9 +0,0 @@
|
||||
const MarsDB = require("marsdb");
|
||||
|
||||
const myDoc = new MarsDB.Collection("myDoc");
|
||||
|
||||
const db = {
|
||||
myDoc
|
||||
};
|
||||
|
||||
module.exports = db;
|
||||
@@ -1,15 +0,0 @@
|
||||
const express = require("express"),
|
||||
bodyParser = require("body-parser"),
|
||||
db = require('./marsdb-flow-from');
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
|
||||
app.post("/documents/find", (req, res) => {
|
||||
const query = {};
|
||||
query.title = req.body.title;
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
db.myDoc.find(query, (err, data) => {});
|
||||
});
|
||||
@@ -1,17 +0,0 @@
|
||||
const express = require("express"),
|
||||
MarsDB = require("marsdb"),
|
||||
bodyParser = require("body-parser");
|
||||
|
||||
let doc = new MarsDB.Collection("myDoc");
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
|
||||
app.post("/documents/find", (req, res) => {
|
||||
const query = {};
|
||||
query.title = req.body.title;
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
doc.find(query, (err, data) => {});
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
const express = require("express"),
|
||||
minimongo = require("minimongo"),
|
||||
bodyParser = require("body-parser");
|
||||
|
||||
var LocalDb = minimongo.MemoryDb,
|
||||
db = new LocalDb(),
|
||||
doc = db.myDocs;
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
|
||||
app.post("/documents/find", (req, res) => {
|
||||
const query = {};
|
||||
query.title = req.body.title;
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
doc.find(query);
|
||||
});
|
||||
@@ -1,114 +0,0 @@
|
||||
const express = require('express'),
|
||||
mongodb = require('mongodb'),
|
||||
bodyParser = require('body-parser');
|
||||
|
||||
const MongoClient = mongodb.MongoClient;
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
|
||||
app.post('/documents/find', (req, res) => {
|
||||
const query = {};
|
||||
query.title = req.body.title;
|
||||
MongoClient.connect('mongodb://localhost:27017/test', (err, db) => {
|
||||
let doc = db.collection('doc');
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
doc.find(query);
|
||||
|
||||
// OK: user-data is coerced to a string
|
||||
doc.find({ title: '' + query.body.title });
|
||||
|
||||
// OK: throws unless user-data is a string
|
||||
doc.find({ title: query.body.title.substr(1) });
|
||||
|
||||
let title = req.body.title;
|
||||
if (typeof title === "string") {
|
||||
// OK: input checked to be a string
|
||||
doc.find({ title: title });
|
||||
|
||||
// NOT OK: input is parsed as JSON after string check
|
||||
doc.find({ title: JSON.parse(title) });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/:id', (req, res) => {
|
||||
let query = { id: req.param.id };
|
||||
MongoClient.connect('mongodb://localhost:27017/test', (err, db) => {
|
||||
let doc = db.collection('doc');
|
||||
|
||||
// OK: query is tainted, but only by string value
|
||||
doc.find(query);
|
||||
});
|
||||
});
|
||||
|
||||
app.post('/documents/find', (req, res) => {
|
||||
const query = {};
|
||||
query.title = req.query.title;
|
||||
MongoClient.connect('mongodb://localhost:27017/test', (err, db) => {
|
||||
let doc = db.collection('doc');
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
doc.find(query);
|
||||
});
|
||||
});
|
||||
|
||||
app.post('/documents/find', (req, res) => {
|
||||
const query = {};
|
||||
query.title = req.query.title;
|
||||
MongoClient.connect('mongodb://localhost:27017/test', (err, client) => {
|
||||
let doc = client.db("MASTER").collection('doc');
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
doc.find(query);
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/logs/count-by-tag", (req, res) => {
|
||||
let tag = req.query.tag;
|
||||
|
||||
MongoClient.connect(process.env.DB_URL, {}, (err, client) => {
|
||||
client
|
||||
.db(process.env.DB_NAME)
|
||||
.collection("logs")
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
.count({ tags: tag });
|
||||
});
|
||||
|
||||
let importedDbo = require("./dbo.js");
|
||||
importedDbo
|
||||
.db()
|
||||
.collection("logs")
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
.count({ tags: tag });
|
||||
});
|
||||
|
||||
|
||||
app.get('/:id', (req, res) => {
|
||||
useParams(req.param);
|
||||
});
|
||||
function useParams(params) {
|
||||
let query = { id: params.id };
|
||||
MongoClient.connect('mongodb://localhost:27017/test', (err, db) => {
|
||||
let doc = db.collection('doc');
|
||||
|
||||
// OK: query is tainted, but only by string value
|
||||
doc.find(query);
|
||||
});
|
||||
}
|
||||
|
||||
app.post('/documents/find', (req, res) => {
|
||||
useQuery(req.query);
|
||||
});
|
||||
function useQuery(queries) {
|
||||
const query = {};
|
||||
query.title = queries.title;
|
||||
MongoClient.connect('mongodb://localhost:27017/test', (err, db) => {
|
||||
let doc = db.collection('doc');
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
doc.find(query);
|
||||
});
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
const express = require('express'),
|
||||
mongodb = require('mongodb'),
|
||||
bodyParser = require('body-parser');
|
||||
|
||||
const MongoClient = mongodb.MongoClient;
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(bodyParser.urlencoded({ extended: false }));
|
||||
|
||||
app.post('/documents/find', (req, res) => {
|
||||
const query = {};
|
||||
query.title = req.body.title;
|
||||
MongoClient.connect('mongodb://localhost:27017/test', (err, db) => {
|
||||
let doc = db.collection('doc');
|
||||
|
||||
// OK: req.body is safe
|
||||
doc.find(query);
|
||||
});
|
||||
});
|
||||
|
||||
app.post('/documents/find', (req, res) => {
|
||||
const query = {};
|
||||
query.title = req.query.title;
|
||||
MongoClient.connect('mongodb://localhost:27017/test', (err, db) => {
|
||||
let doc = db.collection('doc');
|
||||
|
||||
// NOT OK: regardless of body parser, query value is still tainted
|
||||
doc.find(query);
|
||||
});
|
||||
});
|
||||
@@ -1,132 +0,0 @@
|
||||
'use strict';
|
||||
const Express = require('express');
|
||||
const BodyParser = require('body-parser');
|
||||
const Mongoose = require('mongoose');
|
||||
Mongoose.Promise = global.Promise;
|
||||
Mongoose.connect('mongodb://localhost/injectable1');
|
||||
|
||||
const app = Express();
|
||||
app.use(BodyParser.json());
|
||||
|
||||
const Document = Mongoose.model('Document', {
|
||||
title: {
|
||||
type: String,
|
||||
unique: true
|
||||
},
|
||||
type: String
|
||||
});
|
||||
|
||||
app.post('/documents/find', (req, res) => {
|
||||
const query = {};
|
||||
query.title = req.body.title;
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
Document.aggregate([query]);
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
Document.count(query);
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
Document.deleteMany(query);
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
Document.deleteOne(query);
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
Document.distinct('type', query);
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
Document.find(query);
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
Document.findOne(query);
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
Document.findOneAndDelete(query);
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
Document.findOneAndRemove(query);
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
Document.findOneAndUpdate(query);
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
Document.replaceOne(query);
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
Document.update(query);
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
Document.updateMany(query);
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
Document.updateOne(query).then(X);
|
||||
|
||||
Document.findByIdAndUpdate(X, query, function(){}); // NOT OK
|
||||
|
||||
new Mongoose.Query(X, Y, query) // NOT OK
|
||||
.and(query, function(){}) // NOT OK
|
||||
;
|
||||
|
||||
Document.where(query) // NOT OK - `.where()` on a Model.
|
||||
.where(query) // NOT OK - `.where()` on a Query.
|
||||
.and(query) // NOT OK
|
||||
.or(query) // NOT OK
|
||||
.distinct(X, query) // NOT OK
|
||||
.comment(query) // OK
|
||||
.count(query) // NOT OK
|
||||
.exec()
|
||||
;
|
||||
|
||||
Mongoose.createConnection(X).count(query); // OK (invalid program)
|
||||
Mongoose.createConnection(X).model(Y).count(query); // NOT OK
|
||||
Mongoose.createConnection(X).models[Y].count(query); // NOT OK
|
||||
|
||||
Document.findOne(X, (err, res) => res.count(query)); // NOT OK
|
||||
Document.findOne(X, (err, res) => err.count(query)); // OK
|
||||
Document.findOne(X).exec((err, res) => res.count(query)); // NOT OK
|
||||
Document.findOne(X).exec((err, res) => err.count(query)); // OK
|
||||
Document.findOne(X).then((res) => res.count(query)); // NOT OK
|
||||
Document.findOne(X).then(Y, (err) => err.count(query)); // OK
|
||||
|
||||
Document.find(X, (err, res) => res[i].count(query)); // NOT OK
|
||||
Document.find(X, (err, res) => err.count(query)); // OK
|
||||
Document.find(X).exec((err, res) => res[i].count(query)); // NOT OK
|
||||
Document.find(X).exec((err, res) => err.count(query)); // OK
|
||||
Document.find(X).then((res) => res[i].count(query)); // NOT OK
|
||||
Document.find(X).then(Y, (err) => err.count(query)); // OK
|
||||
|
||||
Document.count(X, (err, res) => res.count(query)); // OK (res is a number)
|
||||
|
||||
function innocent(X, Y, query) { // To detect if API-graphs were used incorrectly.
|
||||
return new Mongoose.Query("constant", "constant", "constant");
|
||||
}
|
||||
new innocent(X, Y, query);
|
||||
|
||||
function getQueryConstructor() {
|
||||
return Mongoose.Query;
|
||||
}
|
||||
|
||||
var C = getQueryConstructor();
|
||||
new C(X, Y, query); // NOT OK
|
||||
|
||||
Document.findOneAndUpdate(X, query, function () { }); // NOT OK
|
||||
|
||||
let id = req.query.id, cond = req.query.cond;
|
||||
Document.deleteMany(cond); // NOT OK
|
||||
Document.deleteOne(cond); // NOT OK
|
||||
Document.geoSearch(cond); // NOT OK
|
||||
Document.remove(cond); // NOT OK
|
||||
Document.replaceOne(cond, Y); // NOT OK
|
||||
Document.find(cond); // NOT OK
|
||||
Document.findOne(cond); // NOT OK
|
||||
Document.findById(id); // NOT OK
|
||||
Document.findOneAndDelete(cond); // NOT OK
|
||||
Document.findOneAndRemove(cond); // NOT OK
|
||||
Document.findOneAndUpdate(cond, Y); // NOT OK
|
||||
Document.update(cond, Y); // NOT OK
|
||||
Document.updateMany(cond, Y); // NOT OK
|
||||
Document.updateOne(cond, Y); // NOT OK
|
||||
Document.find({ _id: id }); // NOT OK
|
||||
Document.find({ _id: { $eq: id } }); // OK
|
||||
});
|
||||
@@ -1,25 +0,0 @@
|
||||
'use strict';
|
||||
const Express = require('express');
|
||||
const BodyParser = require('body-parser');
|
||||
const Mongoose = require('mongoose');
|
||||
Mongoose.Promise = global.Promise;
|
||||
Mongoose.connect('mongodb://localhost/injectable1');
|
||||
|
||||
const app = Express();
|
||||
|
||||
const Document = Mongoose.model('Document', {
|
||||
title: {
|
||||
type: String,
|
||||
unique: true
|
||||
},
|
||||
type: String
|
||||
});
|
||||
|
||||
app.get('/documents/find', (req, res) => {
|
||||
const query = {};
|
||||
query.title = JSON.parse(req.query.data).title;
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
Document.find(query);
|
||||
});
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
import mongoose from 'mongoose';
|
||||
|
||||
export const MyModel = mongoose.model('MyModel', getSchema());
|
||||
@@ -1,14 +0,0 @@
|
||||
import { MyModel } from './mongooseModel';
|
||||
import express from 'express';
|
||||
import bodyParser from 'body-parser';
|
||||
|
||||
let app = express();
|
||||
|
||||
app.use(bodyParser.json());
|
||||
|
||||
app.post('/find', (req, res) => {
|
||||
let v = JSON.parse(req.body.x);
|
||||
MyModel.find({ id: v }); // NOT OK
|
||||
MyModel.find({ id: req.body.id }); // NOT OK
|
||||
MyModel.find({ id: `${req.body.id}` }); // OK
|
||||
});
|
||||
@@ -1,22 +0,0 @@
|
||||
const app = require("express")();
|
||||
const mysql = require('mysql');
|
||||
const pool = mysql.createPool(getConfig());
|
||||
|
||||
app.get("search", function handler(req, res) {
|
||||
let temp = req.params.value;
|
||||
pool.getConnection(function(err, connection) {
|
||||
connection.query({
|
||||
sql: 'SELECT * FROM `books` WHERE `author` = ?', // OK
|
||||
values: [temp]
|
||||
}, function(error, results, fields) {});
|
||||
});
|
||||
pool.getConnection(function(err, connection) {
|
||||
connection.query({
|
||||
sql: 'SELECT * FROM `books` WHERE `author` = ' + temp, // NOT OK
|
||||
}, function(error, results, fields) {});
|
||||
});
|
||||
pool.getConnection(function(err, connection) {
|
||||
connection.query('SELECT * FROM `books` WHERE `author` = ' + temp, // NOT OK
|
||||
function(error, results, fields) {});
|
||||
});
|
||||
});
|
||||
@@ -1,13 +0,0 @@
|
||||
import { IDatabase } from "pg-promise";
|
||||
|
||||
export class Foo {
|
||||
db: IDatabase;
|
||||
|
||||
onRequest(req, res) {
|
||||
let taint = req.params.x;
|
||||
this.db.one(taint); // NOT OK
|
||||
res.end();
|
||||
}
|
||||
}
|
||||
|
||||
require('express')().get('/foo', (req, res) => new Foo().onRequest(req, res));
|
||||
@@ -1,66 +0,0 @@
|
||||
const pgp = require('pg-promise')();
|
||||
|
||||
require('express')().get('/foo', (req, res) => {
|
||||
const db = pgp(process.env['DB_CONNECTION_STRING']);
|
||||
|
||||
var query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
||||
+ req.params.category + "' ORDER BY PRICE";
|
||||
|
||||
db.any(query); // NOT OK
|
||||
db.many(query); // NOT OK
|
||||
db.manyOrNone(query); // NOT OK
|
||||
db.map(query); // NOT OK
|
||||
db.multi(query); // NOT OK
|
||||
db.multiResult(query); // NOT OK
|
||||
db.none(query); // NOT OK
|
||||
db.one(query); // NOT OK
|
||||
db.oneOrNone(query); // NOT OK
|
||||
db.query(query); // NOT OK
|
||||
db.result(query); // NOT OK
|
||||
|
||||
db.one({
|
||||
text: query // NOT OK
|
||||
});
|
||||
db.one({
|
||||
text: 'SELECT * FROM news where id = $1', // OK
|
||||
values: req.params.id, // OK
|
||||
});
|
||||
db.one({
|
||||
text: 'SELECT * FROM news where id = $1:raw',
|
||||
values: req.params.id, // NOT OK - interpreted as raw parameter
|
||||
});
|
||||
db.one({
|
||||
text: 'SELECT * FROM news where id = $1^',
|
||||
values: req.params.id, // NOT OK
|
||||
});
|
||||
db.one({
|
||||
text: 'SELECT * FROM news where id = $1:raw AND name = $2:raw AND foo = $3',
|
||||
values: [
|
||||
req.params.id, // NOT OK
|
||||
req.params.name, // NOT OK
|
||||
req.params.foo, // OK - not using raw interpolation
|
||||
]
|
||||
});
|
||||
db.one({
|
||||
text: 'SELECT * FROM news where id = ${id}:raw AND name = ${name}',
|
||||
values: {
|
||||
id: req.params.id, // NOT OK
|
||||
name: req.params.name, // OK - not using raw interpolation
|
||||
}
|
||||
});
|
||||
db.one({
|
||||
text: "SELECT * FROM news where id = ${id}:value AND name LIKE '%${name}:value%' AND title LIKE \"%${title}:value%\"",
|
||||
values: {
|
||||
id: req.params.id, // NOT OK
|
||||
name: req.params.name, // OK - :value cannot break out of single quotes
|
||||
title: req.params.title, // NOT OK - enclosed by wrong type of quote
|
||||
}
|
||||
});
|
||||
db.task(t => {
|
||||
return t.one(query); // NOT OK
|
||||
});
|
||||
db.taskIf(
|
||||
{ cnd: t => t.one(query) }, // NOT OK
|
||||
t => t.one(query) // NOT OK
|
||||
);
|
||||
});
|
||||
@@ -1,53 +0,0 @@
|
||||
|
||||
const redis = require("redis");
|
||||
const client = redis.createClient();
|
||||
|
||||
const Express = require('express');
|
||||
const app = Express();
|
||||
app.use(require('body-parser').json());
|
||||
|
||||
app.post('/documents/find', (req, res) => {
|
||||
client.set(req.body.key, "value"); // NOT OK
|
||||
|
||||
var key = req.body.key;
|
||||
if (typeof key === "string") {
|
||||
client.set(key, "value"); // OK
|
||||
client.set(["key", "value"]);
|
||||
}
|
||||
|
||||
client.set(key, "value"); // NOT OK
|
||||
client.hmset("key", "field", "value", key, "value2"); // NOT OK
|
||||
|
||||
// chain commands
|
||||
client
|
||||
.multi()
|
||||
.set("constant", "value")
|
||||
.set(key, "value") // NOT OK
|
||||
.get(key) // OK
|
||||
.exec(function (err, replies) { });
|
||||
|
||||
client.duplicate((err, newClient) => {
|
||||
newClient.set(key, "value"); // NOT OK
|
||||
});
|
||||
client.duplicate().set(key, "value"); // NOT OK
|
||||
});
|
||||
|
||||
|
||||
import { promisify } from 'util';
|
||||
app.post('/documents/find', (req, res) => {
|
||||
const key = req.body.key;
|
||||
client.set(key, "value"); // NOT OK
|
||||
|
||||
const setAsync = promisify(client.set).bind(client);
|
||||
|
||||
const foo1 = setAsync(key, "value"); // NOT OK
|
||||
|
||||
client.setAsync = promisify(client.set);
|
||||
const foo2 = client.setAsync(key, "value"); // NOT OK
|
||||
|
||||
client.unrelated = promisify(() => {});
|
||||
const foo3 = client.unrelated(key, "value"); // OK
|
||||
|
||||
const unrelated = promisify(client.foobar).bind(client);
|
||||
const foo4 = unrelated(key, "value"); // OK
|
||||
});
|
||||
@@ -1,13 +0,0 @@
|
||||
// Adapted from https://github.com/mapbox/node-sqlite3/wiki/API, which is
|
||||
// part of the node-sqlite3 project, which is licensed under the BSD 3-Clause
|
||||
// License; see file node-sqlite3-LICENSE.
|
||||
var express = require('express');
|
||||
var sqlite3 = require('sqlite3').verbose();
|
||||
var db = new sqlite3.Database(':memory:');
|
||||
|
||||
var io = require('socket.io')();
|
||||
io.on('connection', (socket) => {
|
||||
socket.on('newuser', (handle) => {
|
||||
db.run(`INSERT INTO users(name) VALUES ${handle}`);
|
||||
});
|
||||
});
|
||||
@@ -1,11 +0,0 @@
|
||||
// Adapted from https://github.com/mapbox/node-sqlite3/wiki/API, which is
|
||||
// part of the node-sqlite3 project, which is licensed under the BSD 3-Clause
|
||||
// License; see file node-sqlite3-LICENSE.
|
||||
var express = require('express');
|
||||
var sqlite3 = require('sqlite3').verbose();
|
||||
var db = new sqlite3.Database(':memory:');
|
||||
|
||||
var app = express();
|
||||
app.get('/post/:id', function(req, res) {
|
||||
db.get('SELECT * FROM Post WHERE id = "' + req.params.id + '"');
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
var express = require('express');
|
||||
const sql = require('mssql');
|
||||
|
||||
var app = express();
|
||||
app.get('/post/:id', async function(req, res) {
|
||||
// OK
|
||||
sql.query`select * from mytable where id = ${req.params.id}`;
|
||||
// NOT OK
|
||||
new sql.Request().query("select * from mytable where id = '" + req.params.id + "'");
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user