Merge branch 'main' into threat-models

This commit is contained in:
Rasmus Wriedt Larsen
2024-09-26 11:44:24 +02:00
305 changed files with 11499 additions and 5937 deletions

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The common sanitizer guard `StringConstCompareBarrier` has been renamed to `ConstCompareBarrier` and expanded to cover comparisons with other constant values such as `None`. This may result in fewer false positive results for several queries.

View File

@@ -1467,6 +1467,59 @@ module Http {
override DataFlow::Node getValueArg() { none() }
}
/**
* A data-flow node that enables or disables CORS
* in a global manner.
*
* Extend this class to refine existing API models. If you want to model new APIs,
* extend `CorsMiddleware::Range` instead.
*/
class CorsMiddleware extends DataFlow::Node instanceof CorsMiddleware::Range {
/**
* Gets the string corresponding to the middleware
*/
string getMiddlewareName() { result = super.getMiddlewareName() }
/**
* Gets the dataflow node corresponding to the allowed CORS origins
*/
DataFlow::Node getOrigins() { result = super.getOrigins() }
/**
* Gets the boolean value corresponding to if CORS credentials is enabled
* (`true`) or disabled (`false`) by this node.
*/
DataFlow::Node getCredentialsAllowed() { result = super.getCredentialsAllowed() }
}
/** Provides a class for modeling new CORS middleware APIs. */
module CorsMiddleware {
/**
* A data-flow node that enables or disables Cross-site request forgery protection
* in a global manner.
*
* Extend this class to model new APIs. If you want to refine existing API models,
* extend `CorsMiddleware` instead.
*/
abstract class Range extends DataFlow::Node {
/**
* Gets the name corresponding to the middleware
*/
abstract string getMiddlewareName();
/**
* Gets the strings corresponding to the origins allowed by the cors policy
*/
abstract DataFlow::Node getOrigins();
/**
* Gets the boolean value corresponding to if CORS credentials is enabled
* (`true`) or disabled (`false`) by this node.
*/
abstract DataFlow::Node getCredentialsAllowed();
}
}
/**
* A data-flow node that enables or disables Cross-site request forgery protection
* in a global manner.

View File

@@ -3,34 +3,45 @@
private import python
private import semmle.python.dataflow.new.DataFlow
private predicate stringConstCompare(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) {
private predicate constCompare(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) {
exists(CompareNode cn | cn = g |
exists(StringLiteral str_const, Cmpop op |
exists(ImmutableLiteral const, Cmpop op |
op = any(Eq eq) and branch = true
or
op = any(NotEq ne) and branch = false
|
cn.operands(str_const.getAFlowNode(), op, node)
cn.operands(const.getAFlowNode(), op, node)
or
cn.operands(node, op, str_const.getAFlowNode())
cn.operands(node, op, const.getAFlowNode())
)
or
exists(IterableNode str_const_iterable, Cmpop op |
exists(NameConstant const, Cmpop op |
op = any(Is is_) and branch = true
or
op = any(IsNot isn) and branch = false
|
cn.operands(const.getAFlowNode(), op, node)
or
cn.operands(node, op, const.getAFlowNode())
)
or
exists(IterableNode const_iterable, Cmpop op |
op = any(In in_) and branch = true
or
op = any(NotIn ni) and branch = false
|
forall(ControlFlowNode elem | elem = str_const_iterable.getAnElement() |
elem.getNode() instanceof StringLiteral
forall(ControlFlowNode elem | elem = const_iterable.getAnElement() |
elem.getNode() instanceof ImmutableLiteral
) and
cn.operands(node, op, str_const_iterable)
cn.operands(node, op, const_iterable)
)
)
}
/** A validation of unknown node by comparing with a constant string value. */
class StringConstCompareBarrier extends DataFlow::Node {
StringConstCompareBarrier() {
this = DataFlow::BarrierGuard<stringConstCompare/3>::getABarrierNode()
}
/** A validation of unknown node by comparing with a constant value. */
class ConstCompareBarrier extends DataFlow::Node {
ConstCompareBarrier() { this = DataFlow::BarrierGuard<constCompare/3>::getABarrierNode() }
}
/** DEPRECATED: Use ConstCompareBarrier instead. */
deprecated class StringConstCompareBarrier = ConstCompareBarrier;

View File

@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
predicate observeDiffInformedIncrementalMode() { none() }
}
deprecated private import Impl<Config> as I

View File

@@ -30,6 +30,51 @@ module FastApi {
API::Node instance() { result = cls().getReturn() }
}
/**
* A call to `app.add_middleware` adding a generic middleware.
*/
private class AddMiddlewareCall extends DataFlow::CallCfgNode {
AddMiddlewareCall() { this = App::instance().getMember("add_middleware").getACall() }
/**
* Gets the string corresponding to the middleware
*/
string getMiddlewareName() { result = this.getArg(0).asExpr().(Name).getId() }
}
/**
* A call to `app.add_middleware` adding CORSMiddleware.
*/
class AddCorsMiddlewareCall extends Http::Server::CorsMiddleware::Range, AddMiddlewareCall {
/**
* Gets the string corresponding to the middleware
*/
override string getMiddlewareName() { result = this.getArg(0).asExpr().(Name).getId() }
/**
* Gets the dataflow node corresponding to the allowed CORS origins
*/
override DataFlow::Node getOrigins() { result = this.getArgByName("allow_origins") }
/**
* Gets the boolean value corresponding to if CORS credentials is enabled
* (`true`) or disabled (`false`) by this node.
*/
override DataFlow::Node getCredentialsAllowed() {
result = this.getArgByName("allow_credentials")
}
/**
* Gets the dataflow node corresponding to the allowed CORS methods
*/
DataFlow::Node getMethods() { result = this.getArgByName("allow_methods") }
/**
* Gets the dataflow node corresponding to the allowed CORS headers
*/
DataFlow::Node getHeaders() { result = this.getArgByName("allow_headers") }
}
/**
* Provides models for the `fastapi.APIRouter` class
*

View File

@@ -25,6 +25,74 @@ private import semmle.python.frameworks.data.ModelsAsData
* - https://www.starlette.io/
*/
module Starlette {
/**
* Provides models for the `starlette.app` class
*/
module App {
/** Gets import of `starlette.app`. */
API::Node cls() { result = API::moduleImport("starlette").getMember("app") }
/** Gets a reference to a Starlette application (an instance of `starlette.app`). */
API::Node instance() { result = cls().getAnInstance() }
}
/**
* A call to any of the execute methods on a `app.add_middleware`.
*/
class AddMiddlewareCall extends DataFlow::CallCfgNode {
AddMiddlewareCall() {
this = [App::instance().getMember("add_middleware").getACall(), Middleware::instance()]
}
/**
* Gets the string corresponding to the middleware
*/
string getMiddlewareName() { result = this.getArg(0).asExpr().(Name).getId() }
}
/**
* A call to any of the execute methods on a `app.add_middleware` with CORSMiddleware.
*/
class AddCorsMiddlewareCall extends AddMiddlewareCall, Http::Server::CorsMiddleware::Range {
/**
* Gets the string corresponding to the middleware
*/
override string getMiddlewareName() { result = this.getArg(0).asExpr().(Name).getId() }
override DataFlow::Node getOrigins() { result = this.getArgByName("allow_origins") }
override DataFlow::Node getCredentialsAllowed() {
result = this.getArgByName("allow_credentials")
}
/**
* Gets the dataflow node corresponding to the allowed CORS methods
*/
DataFlow::Node getMethods() { result = this.getArgByName("allow_methods") }
/**
* Gets the dataflow node corresponding to the allowed CORS headers
*/
DataFlow::Node getHeaders() { result = this.getArgByName("allow_headers") }
}
/**
* Provides models for the `starlette.middleware.Middleware` class
*
* See https://www.starlette.io/.
*/
module Middleware {
/** Gets a reference to the `starlette.middleware.Middleware` class. */
API::Node classRef() {
result = API::moduleImport("starlette").getMember("middleware").getMember("Middleware")
or
result = ModelOutput::getATypeNode("starlette.middleware.Middleware~Subclass").getASubclass*()
}
/** Gets a reference to an instance of `starlette.middleware.Middleware`. */
DataFlow::Node instance() { result = classRef().getACall() }
}
/**
* Provides models for the `starlette.websockets.WebSocket` class
*

View File

@@ -54,7 +54,10 @@ module CodeInjection {
}
/**
* A comparison with a constant string, considered as a sanitizer-guard.
* A comparison with a constant, considered as a sanitizer-guard.
*/
class StringConstCompareAsSanitizer extends Sanitizer, StringConstCompareBarrier { }
class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { }
/** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */
deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard;
}

View File

@@ -89,7 +89,10 @@ module CommandInjection {
}
/**
* A comparison with a constant string, considered as a sanitizer-guard.
* A comparison with a constant, considered as a sanitizer-guard.
*/
class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { }
class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { }
/** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */
deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard;
}

View File

@@ -66,15 +66,20 @@ module LdapInjection {
}
/**
* A comparison with a constant string, considered as a sanitizer-guard.
* A comparison with a constant, considered as a sanitizer-guard.
*/
class StringConstCompareAsDnSanitizerGuard extends DnSanitizer, StringConstCompareBarrier { }
class ConstCompareAsDnSanitizerGuard extends DnSanitizer, ConstCompareBarrier { }
/** DEPRECATED: Use ConstCompareAsDnSanitizerGuard instead. */
deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsDnSanitizerGuard;
/**
* A comparison with a constant string, considered as a sanitizer-guard.
* A comparison with a constant, considered as a sanitizer-guard.
*/
class StringConstCompareAsFilterSanitizerGuard extends FilterSanitizer, StringConstCompareBarrier {
}
class ConstCompareAsFilterSanitizerGuard extends FilterSanitizer, ConstCompareBarrier { }
/** DEPRECATED: Use ConstCompareAsFilterSanitizerGuard instead. */
deprecated class StringConstCompareAsFilterSanitizerGuard = ConstCompareAsFilterSanitizerGuard;
/**
* A call to replace line breaks functions as a sanitizer.

View File

@@ -82,9 +82,12 @@ module LogInjection {
}
/**
* A comparison with a constant string, considered as a sanitizer-guard.
* A comparison with a constant, considered as a sanitizer-guard.
*/
class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { }
class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { }
/** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */
deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard;
/**
* A call to replace line breaks, considered as a sanitizer.

View File

@@ -92,7 +92,10 @@ module PathInjection {
}
/**
* A comparison with a constant string, considered as a sanitizer-guard.
* A comparison with a constant, considered as a sanitizer-guard.
*/
class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { }
class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { }
/** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */
deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard;
}

View File

@@ -75,7 +75,10 @@ module PolynomialReDoS {
}
/**
* A comparison with a constant string, considered as a sanitizer-guard.
* A comparison with a constant, considered as a sanitizer-guard.
*/
class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { }
class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { }
/** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */
deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard;
}

View File

@@ -80,7 +80,10 @@ module ReflectedXss {
}
/**
* A comparison with a constant string, considered as a sanitizer-guard.
* A comparison with a constant, considered as a sanitizer-guard.
*/
class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { }
class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { }
/** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */
deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard;
}

View File

@@ -77,9 +77,12 @@ module ServerSideRequestForgery {
}
/**
* A comparison with a constant string, considered as a sanitizer-guard.
* A comparison with a constant, considered as a sanitizer-guard.
*/
class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { }
class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { }
/** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */
deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard;
/**
* A string construction (concat, format, f-string) where the left side is not

View File

@@ -56,9 +56,12 @@ module SqlInjection {
}
/**
* A comparison with a constant string, considered as a sanitizer-guard.
* A comparison with a constant, considered as a sanitizer-guard.
*/
class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { }
class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { }
/** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */
deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard;
private import semmle.python.frameworks.data.ModelsAsData

View File

@@ -59,7 +59,10 @@ module UnsafeDeserialization {
}
/**
* A comparison with a constant string, considered as a sanitizer-guard.
* A comparison with a constant, considered as a sanitizer-guard.
*/
class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { }
class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { }
/** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */
deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard;
}

View File

@@ -145,12 +145,15 @@ module UrlRedirect {
}
/**
* A comparison with a constant string, considered as a sanitizer-guard.
* A comparison with a constant, considered as a sanitizer-guard.
*/
class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier {
class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier {
override predicate sanitizes(FlowState state) {
// sanitize all flow states
any()
}
}
/** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */
deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard;
}