mirror of
https://github.com/github/codeql.git
synced 2026-05-03 04:39:29 +02:00
3
python/change-notes/2021-12-17-add-SSRF-queries.md
Normal file
3
python/change-notes/2021-12-17-add-SSRF-queries.md
Normal file
@@ -0,0 +1,3 @@
|
||||
lgtm,codescanning
|
||||
* Two new queries have been added for detecting Server-side request forgery (SSRF). _Full server-side request forgery_ (`py/full-ssrf`) will only alert when the URL is fully user-controlled, and _Partial server-side request forgery_ (`py/partial-ssrf`) will alert when any part of the URL is user-controlled. Only `py/full-ssrf` will be run by default.
|
||||
* To support the new SSRF queries, the PyPI package `requests` have been modeled, along with `http.client.HTTP[S]Connection` from the standard library.
|
||||
@@ -812,6 +812,72 @@ module HTTP {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides classes for modeling HTTP clients. */
|
||||
module Client {
|
||||
/**
|
||||
* A data-flow node that makes an outgoing HTTP request.
|
||||
*
|
||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||
* extend `HTTP::Client::Request::Range` instead.
|
||||
*/
|
||||
class Request extends DataFlow::Node instanceof Request::Range {
|
||||
/**
|
||||
* Gets a data-flow node that contributes to the URL of the request.
|
||||
* Depending on the framework, a request may have multiple nodes which contribute to the URL.
|
||||
*/
|
||||
DataFlow::Node getAUrlPart() { result = super.getAUrlPart() }
|
||||
|
||||
/** Gets a string that identifies the framework used for this request. */
|
||||
string getFramework() { result = super.getFramework() }
|
||||
|
||||
/**
|
||||
* Holds if this request is made using a mode that disables SSL/TLS
|
||||
* certificate validation, where `disablingNode` represents the point at
|
||||
* which the validation was disabled, and `argumentOrigin` represents the origin
|
||||
* of the argument that disabled the validation (which could be the same node as
|
||||
* `disablingNode`).
|
||||
*/
|
||||
predicate disablesCertificateValidation(
|
||||
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||
) {
|
||||
super.disablesCertificateValidation(disablingNode, argumentOrigin)
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides a class for modeling new HTTP requests. */
|
||||
module Request {
|
||||
/**
|
||||
* A data-flow node that makes an outgoing HTTP request.
|
||||
*
|
||||
* Extend this class to model new APIs. If you want to refine existing API models,
|
||||
* extend `HTTP::Client::Request` instead.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/**
|
||||
* Gets a data-flow node that contributes to the URL of the request.
|
||||
* Depending on the framework, a request may have multiple nodes which contribute to the URL.
|
||||
*/
|
||||
abstract DataFlow::Node getAUrlPart();
|
||||
|
||||
/** Gets a string that identifies the framework used for this request. */
|
||||
abstract string getFramework();
|
||||
|
||||
/**
|
||||
* Holds if this request is made using a mode that disables SSL/TLS
|
||||
* certificate validation, where `disablingNode` represents the point at
|
||||
* which the validation was disabled, and `argumentOrigin` represents the origin
|
||||
* of the argument that disabled the validation (which could be the same node as
|
||||
* `disablingNode`).
|
||||
*/
|
||||
abstract predicate disablesCertificateValidation(
|
||||
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||
);
|
||||
}
|
||||
}
|
||||
// TODO: investigate whether we should treat responses to client requests as
|
||||
// remote-flow-sources in general.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,6 +30,7 @@ private import semmle.python.frameworks.Peewee
|
||||
private import semmle.python.frameworks.Psycopg2
|
||||
private import semmle.python.frameworks.Pydantic
|
||||
private import semmle.python.frameworks.PyMySQL
|
||||
private import semmle.python.frameworks.Requests
|
||||
private import semmle.python.frameworks.RestFramework
|
||||
private import semmle.python.frameworks.Rsa
|
||||
private import semmle.python.frameworks.RuamelYaml
|
||||
|
||||
171
python/ql/lib/semmle/python/frameworks/Requests.qll
Normal file
171
python/ql/lib/semmle/python/frameworks/Requests.qll
Normal file
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* Provides classes modeling security-relevant aspects of the `requests` PyPI package.
|
||||
*
|
||||
* See
|
||||
* - https://pypi.org/project/requests/
|
||||
* - https://docs.python-requests.org/en/latest/
|
||||
*/
|
||||
|
||||
private import python
|
||||
private import semmle.python.Concepts
|
||||
private import semmle.python.ApiGraphs
|
||||
private import semmle.python.dataflow.new.DataFlow
|
||||
private import semmle.python.dataflow.new.TaintTracking
|
||||
private import semmle.python.frameworks.internal.InstanceTaintStepsHelper
|
||||
private import semmle.python.frameworks.Stdlib
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Provides models for the `requests` PyPI package.
|
||||
*
|
||||
* See
|
||||
* - https://pypi.org/project/requests/
|
||||
* - https://docs.python-requests.org/en/latest/
|
||||
*/
|
||||
private module Requests {
|
||||
private class OutgoingRequestCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
|
||||
string methodName;
|
||||
|
||||
OutgoingRequestCall() {
|
||||
methodName in [HTTP::httpVerbLower(), "request"] and
|
||||
(
|
||||
this = API::moduleImport("requests").getMember(methodName).getACall()
|
||||
or
|
||||
exists(API::Node moduleExporting, API::Node sessionInstance |
|
||||
moduleExporting in [
|
||||
API::moduleImport("requests"), //
|
||||
API::moduleImport("requests").getMember("sessions")
|
||||
] and
|
||||
sessionInstance = moduleExporting.getMember(["Session", "session"]).getReturn()
|
||||
|
|
||||
this = sessionInstance.getMember(methodName).getACall()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAUrlPart() {
|
||||
result = this.getArgByName("url")
|
||||
or
|
||||
not methodName = "request" and
|
||||
result = this.getArg(0)
|
||||
or
|
||||
methodName = "request" and
|
||||
result = this.getArg(1)
|
||||
}
|
||||
|
||||
/** Gets the `verify` argument to this outgoing requests call. */
|
||||
DataFlow::Node getVerifyArg() { result = this.getArgByName("verify") }
|
||||
|
||||
override predicate disablesCertificateValidation(
|
||||
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||
) {
|
||||
disablingNode = this.getVerifyArg() and
|
||||
argumentOrigin = verifyArgBacktracker(disablingNode) and
|
||||
argumentOrigin.asExpr().(ImmutableLiteral).booleanValue() = false and
|
||||
not argumentOrigin.asExpr() instanceof None
|
||||
}
|
||||
|
||||
override string getFramework() { result = "requests" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra taint propagation for outgoing requests calls,
|
||||
* to ensure that responses to user-controlled URL are tainted.
|
||||
*/
|
||||
private class OutgoingRequestCallTaintStep extends TaintTracking::AdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
nodeFrom = nodeTo.(OutgoingRequestCall).getAUrlPart()
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets a back-reference to the verify argument `arg`. */
|
||||
private DataFlow::TypeTrackingNode verifyArgBacktracker(
|
||||
DataFlow::TypeBackTracker t, DataFlow::Node arg
|
||||
) {
|
||||
t.start() and
|
||||
arg = any(OutgoingRequestCall c).getVerifyArg() and
|
||||
result = arg.getALocalSource()
|
||||
or
|
||||
exists(DataFlow::TypeBackTracker t2 | result = verifyArgBacktracker(t2, arg).backtrack(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a back-reference to the verify argument `arg`. */
|
||||
private DataFlow::LocalSourceNode verifyArgBacktracker(DataFlow::Node arg) {
|
||||
result = verifyArgBacktracker(DataFlow::TypeBackTracker::end(), arg)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Response
|
||||
// ---------------------------------------------------------------------------
|
||||
/**
|
||||
* Provides models for the `requests.models.Response` class
|
||||
*
|
||||
* See https://docs.python-requests.org/en/latest/api/#requests.Response.
|
||||
*/
|
||||
module Response {
|
||||
/** Gets a reference to the `requests.models.Response` class. */
|
||||
private API::Node classRef() {
|
||||
result = API::moduleImport("requests").getMember("models").getMember("Response")
|
||||
or
|
||||
result = API::moduleImport("requests").getMember("Response")
|
||||
}
|
||||
|
||||
/**
|
||||
* A source of instances of `requests.models.Response`, extend this class to model new instances.
|
||||
*
|
||||
* This can include instantiations of the class, return values from function
|
||||
* calls, or a special parameter that will be set when functions are called by an external
|
||||
* library.
|
||||
*
|
||||
* Use the predicate `Response::instance()` to get references to instances of `requests.models.Response`.
|
||||
*/
|
||||
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
|
||||
|
||||
/** A direct instantiation of `requests.models.Response`. */
|
||||
private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
|
||||
ClassInstantiation() { this = classRef().getACall() }
|
||||
}
|
||||
|
||||
/** Return value from making a reuqest. */
|
||||
private class RequestReturnValue extends InstanceSource, DataFlow::Node {
|
||||
RequestReturnValue() { this = any(OutgoingRequestCall c) }
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `requests.models.Response`. */
|
||||
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result instanceof InstanceSource
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `requests.models.Response`. */
|
||||
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
|
||||
|
||||
/**
|
||||
* Taint propagation for `requests.models.Response`.
|
||||
*/
|
||||
private class InstanceTaintSteps extends InstanceTaintStepsHelper {
|
||||
InstanceTaintSteps() { this = "requests.models.Response" }
|
||||
|
||||
override DataFlow::Node getInstance() { result = instance() }
|
||||
|
||||
override string getAttributeName() {
|
||||
result in ["text", "content", "raw", "links", "cookies", "headers"]
|
||||
}
|
||||
|
||||
override string getMethodName() { result in ["json", "iter_content", "iter_lines"] }
|
||||
|
||||
override string getAsyncMethodName() { none() }
|
||||
}
|
||||
|
||||
/** An attribute read that is a file-like instance. */
|
||||
private class FileLikeInstances extends Stdlib::FileLikeObject::InstanceSource {
|
||||
FileLikeInstances() {
|
||||
this.(DataFlow::AttrRead).getObject() = instance() and
|
||||
this.(DataFlow::AttrRead).getAttributeName() = "raw"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2091,6 +2091,201 @@ private module StdlibPrivate {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// http.client (Python 3)
|
||||
// httplib (Python 2)
|
||||
// ---------------------------------------------------------------------------
|
||||
/**
|
||||
* Provides models for the `http.client.HTTPConnection` and `HTTPSConnection` classes
|
||||
*
|
||||
* See
|
||||
* - https://docs.python.org/3.10/library/http.client.html#http.client.HTTPConnection
|
||||
* - https://docs.python.org/3.10/library/http.client.html#http.client.HTTPSConnection
|
||||
* - https://docs.python.org/2.7/library/httplib.html#httplib.HTTPConnection
|
||||
* - https://docs.python.org/2.7/library/httplib.html#httplib.HTTPSConnection
|
||||
*/
|
||||
module HTTPConnection {
|
||||
/** Gets a reference to the `http.client.HTTPConnection` class. */
|
||||
private API::Node classRef() {
|
||||
exists(string className | className in ["HTTPConnection", "HTTPSConnection"] |
|
||||
// Python 3
|
||||
result = API::moduleImport("http").getMember("client").getMember(className)
|
||||
or
|
||||
// Python 2
|
||||
result = API::moduleImport("httplib").getMember(className)
|
||||
or
|
||||
result =
|
||||
API::moduleImport("six").getMember("moves").getMember("http_client").getMember(className)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A source of instances of `http.client.HTTPConnection`, extend this class to model new instances.
|
||||
*
|
||||
* This can include instantiations of the class, return values from function
|
||||
* calls, or a special parameter that will be set when functions are called by an external
|
||||
* library.
|
||||
*
|
||||
* Use the predicate `HTTPConnection::instance()` to get references to instances of `http.client.HTTPConnection`.
|
||||
*/
|
||||
abstract class InstanceSource extends DataFlow::LocalSourceNode {
|
||||
/** Gets the argument that specified the host, if any. */
|
||||
abstract DataFlow::Node getHostArgument();
|
||||
}
|
||||
|
||||
/** A direct instantiation of `http.client.HTTPConnection`. */
|
||||
private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
|
||||
ClassInstantiation() { this = classRef().getACall() }
|
||||
|
||||
override DataFlow::Node getHostArgument() {
|
||||
result in [this.getArg(0), this.getArgByName("host")]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to an instance of `http.client.HTTPConnection`,
|
||||
* that was instantiated with host argument `hostArg`.
|
||||
*/
|
||||
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t, DataFlow::Node hostArg) {
|
||||
t.start() and
|
||||
hostArg = result.(InstanceSource).getHostArgument()
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = instance(t2, hostArg).track(t2, t))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to an instance of `http.client.HTTPConnection`,
|
||||
* that was instantiated with host argument `hostArg`.
|
||||
*/
|
||||
DataFlow::Node instance(DataFlow::Node hostArg) {
|
||||
instance(DataFlow::TypeTracker::end(), hostArg).flowsTo(result)
|
||||
}
|
||||
|
||||
/** A method call on a HTTPConnection that sends off a request */
|
||||
private class RequestCall extends HTTP::Client::Request::Range, DataFlow::MethodCallNode {
|
||||
RequestCall() { this.calls(instance(_), ["request", "_send_request", "putrequest"]) }
|
||||
|
||||
DataFlow::Node getUrlArg() { result in [this.getArg(1), this.getArgByName("url")] }
|
||||
|
||||
override DataFlow::Node getAUrlPart() {
|
||||
result = this.getUrlArg()
|
||||
or
|
||||
this.getObject() = instance(result)
|
||||
}
|
||||
|
||||
override string getFramework() { result = "http.client.HTTP[S]Connection" }
|
||||
|
||||
override predicate disablesCertificateValidation(
|
||||
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||
) {
|
||||
// TODO: Proper alerting of insecure verification settings on SSLContext.
|
||||
// Because that is not restricted to HTTP[S]Connection usage, we need something
|
||||
// more general, and I would like to tackle that in future PR.
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to the `getresponse` method. */
|
||||
private class HttpConnectionGetResponseCall extends DataFlow::MethodCallNode,
|
||||
HTTPResponse::InstanceSource {
|
||||
HttpConnectionGetResponseCall() { this.calls(instance(_), "getresponse") }
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra taint propagation for `http.client.HTTPConnection`,
|
||||
* to ensure that responses to user-controlled URL are tainted.
|
||||
*/
|
||||
private class AdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
// constructor
|
||||
exists(InstanceSource instanceSource |
|
||||
nodeFrom = instanceSource.getHostArgument() and
|
||||
nodeTo = instanceSource
|
||||
)
|
||||
or
|
||||
// a request method
|
||||
exists(RequestCall call |
|
||||
nodeFrom = call.getUrlArg() and
|
||||
nodeTo.(DataFlow::PostUpdateNode).getPreUpdateNode() = call.getObject()
|
||||
)
|
||||
or
|
||||
// `getresponse` call
|
||||
exists(HttpConnectionGetResponseCall call |
|
||||
nodeFrom = call.getObject() and
|
||||
nodeTo = call
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides models for the `http.client.HTTPResponse` class
|
||||
*
|
||||
* See
|
||||
* - https://docs.python.org/3.10/library/http.client.html#httpresponse-objects
|
||||
* - https://docs.python.org/3/library/http.client.html#http.client.HTTPResponse.
|
||||
*/
|
||||
module HTTPResponse {
|
||||
/** Gets a reference to the `http.client.HTTPResponse` class. */
|
||||
private API::Node classRef() {
|
||||
result = API::moduleImport("http").getMember("client").getMember("HTTPResponse")
|
||||
}
|
||||
|
||||
/**
|
||||
* A source of instances of `http.client.HTTPResponse`, extend this class to model new instances.
|
||||
*
|
||||
* A `http.client.HTTPResponse` is itself a file-like object.
|
||||
*
|
||||
* This can include instantiations of the class, return values from function
|
||||
* calls, or a special parameter that will be set when functions are called by an external
|
||||
* library.
|
||||
*
|
||||
* Use the predicate `HTTPResponse::instance()` to get references to instances of `http.client.HTTPResponse`.
|
||||
*/
|
||||
abstract class InstanceSource extends Stdlib::FileLikeObject::InstanceSource,
|
||||
DataFlow::LocalSourceNode { }
|
||||
|
||||
/** A direct instantiation of `http.client.HTTPResponse`. */
|
||||
private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
|
||||
ClassInstantiation() { this = classRef().getACall() }
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `http.client.HTTPResponse`. */
|
||||
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result instanceof InstanceSource
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `http.client.HTTPResponse`. */
|
||||
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
|
||||
|
||||
/**
|
||||
* Taint propagation for `http.client.HTTPResponse`.
|
||||
*/
|
||||
private class InstanceTaintSteps extends InstanceTaintStepsHelper {
|
||||
InstanceTaintSteps() { this = "http.client.HTTPResponse" }
|
||||
|
||||
override DataFlow::Node getInstance() { result = instance() }
|
||||
|
||||
override string getAttributeName() { result in ["headers", "msg", "reason", "url"] }
|
||||
|
||||
override string getMethodName() { result in ["getheader", "getheaders", "info", "geturl",] }
|
||||
|
||||
override string getAsyncMethodName() { none() }
|
||||
}
|
||||
|
||||
/** An attribute read that is a HTTPMessage instance. */
|
||||
private class HTTPMessageInstances extends Stdlib::HTTPMessage::InstanceSource {
|
||||
HTTPMessageInstances() {
|
||||
this.(DataFlow::AttrRead).accesses(instance(), ["headers", "msg"])
|
||||
or
|
||||
this.(DataFlow::MethodCallNode).calls(instance(), "info")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// sqlite3
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Provides a taint-tracking configuration for detecting "Server-side request forgery" vulnerabilities.
|
||||
*
|
||||
* Note, for performance reasons: only import this file if
|
||||
* `ServerSideRequestForgery::Configuration` is needed, otherwise
|
||||
* `ServerSideRequestForgeryCustomizations` should be imported instead.
|
||||
*/
|
||||
|
||||
private import python
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
import semmle.python.dataflow.new.TaintTracking
|
||||
import semmle.python.Concepts
|
||||
|
||||
/**
|
||||
* Provides a taint-tracking configuration for detecting "Server-side request forgery" vulnerabilities.
|
||||
*
|
||||
* This configuration has a sanitizer to limit results to cases where attacker has full control of URL.
|
||||
* See `PartialServerSideRequestForgery` for a variant without this requirement.
|
||||
*
|
||||
* You should use the `partOfFullyControlledRequest` to only select results where all
|
||||
* URL parts are fully controlled.
|
||||
*/
|
||||
module FullServerSideRequestForgery {
|
||||
import ServerSideRequestForgeryCustomizations::ServerSideRequestForgery
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for detecting "Server-side request forgery" vulnerabilities.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "FullServerSideRequestForgery" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
node instanceof Sanitizer
|
||||
or
|
||||
node instanceof FullUrlControlSanitizer
|
||||
}
|
||||
|
||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
||||
guard instanceof SanitizerGuard
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if all URL parts of `request` is fully user controlled.
|
||||
*/
|
||||
predicate fullyControlledRequest(HTTP::Client::Request request) {
|
||||
exists(FullServerSideRequestForgery::Configuration fullConfig |
|
||||
forall(DataFlow::Node urlPart | urlPart = request.getAUrlPart() |
|
||||
fullConfig.hasFlow(_, urlPart)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a taint-tracking configuration for detecting "Server-side request forgery" vulnerabilities.
|
||||
*
|
||||
* This configuration has results, even when the attacker does not have full control over the URL.
|
||||
* See `FullServerSideRequestForgery` for variant that has this requirement.
|
||||
*/
|
||||
module PartialServerSideRequestForgery {
|
||||
import ServerSideRequestForgeryCustomizations::ServerSideRequestForgery
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for detecting "Server-side request forgery" vulnerabilities.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "PartialServerSideRequestForgery" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
|
||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
||||
guard instanceof SanitizerGuard
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for detecting
|
||||
* "Server-side request forgery"
|
||||
* vulnerabilities, as well as extension points for adding your own.
|
||||
*/
|
||||
|
||||
private import python
|
||||
private import semmle.python.dataflow.new.DataFlow
|
||||
private import semmle.python.Concepts
|
||||
private import semmle.python.dataflow.new.RemoteFlowSources
|
||||
private import semmle.python.dataflow.new.BarrierGuards
|
||||
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for detecting
|
||||
* "Server-side request forgery"
|
||||
* vulnerabilities, as well as extension points for adding your own.
|
||||
*/
|
||||
module ServerSideRequestForgery {
|
||||
/**
|
||||
* A data flow source for "Server-side request forgery" vulnerabilities.
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A data flow sink for "Server-side request forgery" vulnerabilities.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::Node {
|
||||
/**
|
||||
* Gets the request this sink belongs to.
|
||||
*/
|
||||
abstract HTTP::Client::Request getRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sanitizer for "Server-side request forgery" vulnerabilities.
|
||||
*/
|
||||
abstract class Sanitizer extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A sanitizer for "Server-side request forgery" vulnerabilities,
|
||||
* that ensures the attacker does not have full control of the URL. (that is, might
|
||||
* still be able to control path or query parameters).
|
||||
*/
|
||||
abstract class FullUrlControlSanitizer extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A sanitizer guard for "Server-side request forgery" vulnerabilities.
|
||||
*/
|
||||
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
|
||||
|
||||
/**
|
||||
* A source of remote user input, considered as a flow source.
|
||||
*/
|
||||
class RemoteFlowSourceAsSource extends Source, RemoteFlowSource { }
|
||||
|
||||
/** The URL of an HTTP request, considered as a sink. */
|
||||
class HttpRequestUrlAsSink extends Sink {
|
||||
HTTP::Client::Request req;
|
||||
|
||||
HttpRequestUrlAsSink() {
|
||||
req.getAUrlPart() = this and
|
||||
// if we extract the stdlib code for HTTPConnection, we will also find calls that
|
||||
// make requests within the HTTPConnection implementation -- for example the
|
||||
// `request` method calls the `_send_request` method internally. So without this
|
||||
// extra bit of code, we would give alerts within the HTTPConnection
|
||||
// implementation as well, which is just annoying.
|
||||
//
|
||||
// Notice that we're excluding based on the request location, and not the URL part
|
||||
// location, since the URL part would be in user code for the scenario above.
|
||||
//
|
||||
// See comment for command injection sinks for more details.
|
||||
not req.getScope().getEnclosingModule().getName() in ["http.client", "httplib"]
|
||||
}
|
||||
|
||||
override HTTP::Client::Request getRequest() { result = req }
|
||||
}
|
||||
|
||||
/**
|
||||
* A comparison with a constant string, considered as a sanitizer-guard.
|
||||
*/
|
||||
class StringConstCompareAsSanitizerGuard extends SanitizerGuard, StringConstCompare { }
|
||||
|
||||
/**
|
||||
* A string construction (concat, format, f-string) where the left side is not
|
||||
* user-controlled.
|
||||
*
|
||||
* For all of these cases, we try to allow `http://` or `https://` on the left side
|
||||
* since that will still allow full URL control.
|
||||
*/
|
||||
class StringConstructionAsFullUrlControlSanitizer extends FullUrlControlSanitizer {
|
||||
StringConstructionAsFullUrlControlSanitizer() {
|
||||
// string concat
|
||||
exists(BinaryExprNode add |
|
||||
add.getOp() instanceof Add and
|
||||
add.getRight() = this.asCfgNode() and
|
||||
not add.getLeft().getNode().(StrConst).getText().toLowerCase() in ["http://", "https://"]
|
||||
)
|
||||
or
|
||||
// % formatting
|
||||
exists(BinaryExprNode fmt |
|
||||
fmt.getOp() instanceof Mod and
|
||||
fmt.getRight() = this.asCfgNode() and
|
||||
// detecting %-formatting is not super easy, so we simplify it to only handle
|
||||
// when there is a **single** substitution going on.
|
||||
not fmt.getLeft().getNode().(StrConst).getText().regexpMatch("^(?i)https?://%s[^%]*$")
|
||||
)
|
||||
or
|
||||
// arguments to a format call
|
||||
exists(DataFlow::MethodCallNode call, string httpPrefixRe |
|
||||
httpPrefixRe = "^(?i)https?://(?:(\\{\\})|\\{([0-9]+)\\}|\\{([^0-9].*)\\}).*$"
|
||||
|
|
||||
call.getMethodName() = "format" and
|
||||
(
|
||||
if call.getObject().asExpr().(StrConst).getText().regexpMatch(httpPrefixRe)
|
||||
then
|
||||
exists(string text | text = call.getObject().asExpr().(StrConst).getText() |
|
||||
// `http://{}...`
|
||||
exists(text.regexpCapture(httpPrefixRe, 1)) and
|
||||
this in [call.getArg(any(int i | i >= 1)), call.getArgByName(_)]
|
||||
or
|
||||
// `http://{123}...`
|
||||
exists(int safeArgIndex | safeArgIndex = text.regexpCapture(httpPrefixRe, 2).toInt() |
|
||||
this in [call.getArg(any(int i | i != safeArgIndex)), call.getArgByName(_)]
|
||||
)
|
||||
or
|
||||
// `http://{abc}...`
|
||||
exists(string safeArgName | safeArgName = text.regexpCapture(httpPrefixRe, 3) |
|
||||
this in [call.getArg(_), call.getArgByName(any(string s | s != safeArgName))]
|
||||
)
|
||||
)
|
||||
else this in [call.getArg(_), call.getArgByName(_)]
|
||||
)
|
||||
)
|
||||
or
|
||||
// f-string
|
||||
exists(Fstring fstring |
|
||||
if fstring.getValue(0).(StrConst).getText().toLowerCase() in ["http://", "https://"]
|
||||
then fstring.getValue(any(int i | i >= 2)) = this.asExpr()
|
||||
else fstring.getValue(any(int i | i >= 1)) = this.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<include src="ServerSideRequestForgery-start.inc.qhelp" />
|
||||
|
||||
<!-- query specific -->
|
||||
<p>This query covers full SSRF, to find partial SSRF use the <code>py/partial-ssrf</code> query.</p>
|
||||
</overview>
|
||||
<include src="ServerSideRequestForgery-end.inc.qhelp" />
|
||||
</qhelp>
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @name Full server-side request forgery
|
||||
* @description Making a network request to a URL that is fully user-controlled allows for request forgery attacks.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 9.1
|
||||
* @precision high
|
||||
* @id py/full-ssrf
|
||||
* @tags security
|
||||
* external/cwe/cwe-918
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.dataflow.ServerSideRequestForgery
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from
|
||||
FullServerSideRequestForgery::Configuration fullConfig, DataFlow::PathNode source,
|
||||
DataFlow::PathNode sink, HTTP::Client::Request request
|
||||
where
|
||||
request = sink.getNode().(FullServerSideRequestForgery::Sink).getRequest() and
|
||||
fullConfig.hasFlowPath(source, sink) and
|
||||
fullyControlledRequest(request)
|
||||
select request, source, sink, "The full URL of this request depends on $@.", source.getNode(),
|
||||
"a user-provided value"
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<include src="ServerSideRequestForgery-start.inc.qhelp" />
|
||||
|
||||
<!-- query specific -->
|
||||
<p>This query covers partial SSRF, to find full SSRF use the <code>py/full-ssrf</code> query.</p>
|
||||
</overview>
|
||||
<include src="ServerSideRequestForgery-end.inc.qhelp" />
|
||||
</qhelp>
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @name Partial server-side request forgery
|
||||
* @description Making a network request to a URL that is partially user-controlled allows for request forgery attacks.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 9.1
|
||||
* @precision medium
|
||||
* @id py/partial-ssrf
|
||||
* @tags security
|
||||
* external/cwe/cwe-918
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.dataflow.ServerSideRequestForgery
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from
|
||||
PartialServerSideRequestForgery::Configuration partialConfig, DataFlow::PathNode source,
|
||||
DataFlow::PathNode sink, HTTP::Client::Request request
|
||||
where
|
||||
request = sink.getNode().(PartialServerSideRequestForgery::Sink).getRequest() and
|
||||
partialConfig.hasFlowPath(source, sink) and
|
||||
not fullyControlledRequest(request)
|
||||
select request, source, sink, "Part of the URL of this request depends on $@.", source.getNode(),
|
||||
"a user-provided value"
|
||||
@@ -0,0 +1,47 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<recommendation>
|
||||
|
||||
<p>To guard against SSRF attacks you should avoid putting user-provided input directly
|
||||
into a request URL. Instead, either maintain a list of authorized URLs on the server and choose
|
||||
from that list based on the input provided, or perform proper validation of the input.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<p>The following example shows code vulnerable to a full SSRF attack, because it
|
||||
uses untrusted input (HTTP request parameter) directly to construct a URL. By using
|
||||
<code>evil.com#</code> as the <code>target</code> value, the requested URL will be
|
||||
<code>https://evil.com#.example.com/data/</code>. It also shows how to remedy the
|
||||
problem by using the user input select a known fixed string.
|
||||
</p>
|
||||
|
||||
<sample src="examples/ServerSideRequestForgery_full.py" />
|
||||
|
||||
</example>
|
||||
<example>
|
||||
|
||||
<p>
|
||||
The following example shows code vulnerable to a partial SSRF attack, because it
|
||||
uses untrusted input (HTTP request parameter) directly to construct a URL. By
|
||||
using <code>../transfer-funds-to/123?amount=456</code> as the
|
||||
<code>user_id</code> value, the requested URL will be
|
||||
<code>https://api.example.com/transfer-funds-to/123?amount=456</code>. It also
|
||||
shows how to remedy the problem by validating the input.
|
||||
</p>
|
||||
|
||||
<sample src="examples/ServerSideRequestForgery_partial.py" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
<li>
|
||||
<a href="https://owasp.org/www-community/attacks/Server_Side_Request_Forgery">OWASP SSRF article</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://portswigger.net/web-security/ssrf">PortSwigger SSRF article</a>
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<fragment>
|
||||
<p>Directly incorporating user input into an HTTP request without validating the input
|
||||
can facilitate server-side request forgery (SSRF) attacks. In these attacks, the
|
||||
request may be changed, directed at a different server, or via a different
|
||||
protocol. This can allow the attacker to obtain sensitive information or perform
|
||||
actions with escalated privilege.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
We make a distinctions between how much of the URL an attacker can control:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><b>Full SSRF</b>: where the full URL can be controlled.</li>
|
||||
<li><b>Partial SSRF</b>: where only part of the URL can be controlled, such as the
|
||||
path component of a URL to a hardcoded domain.</li>
|
||||
</ul>
|
||||
|
||||
<p></p>
|
||||
|
||||
<p>
|
||||
Partial control of a URL is often much harder to exploit. Therefore we have created a
|
||||
separate query for each of these.
|
||||
</p>
|
||||
|
||||
</fragment>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,15 @@
|
||||
import requests
|
||||
from flask import Flask, request
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/full_ssrf")
|
||||
def full_ssrf():
|
||||
target = request.args["target"]
|
||||
|
||||
# BAD: user has full control of URL
|
||||
resp = request.get("https://" + target + ".example.com/data/")
|
||||
|
||||
# GOOD: `subdomain` is controlled by the server.
|
||||
subdomain = "europe" if target == "EU" else "world"
|
||||
resp = request.get("https://" + subdomain + ".example.com/data/")
|
||||
@@ -0,0 +1,15 @@
|
||||
import requests
|
||||
from flask import Flask, request
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/partial_ssrf")
|
||||
def partial_ssrf():
|
||||
user_id = request.args["user_id"]
|
||||
|
||||
# BAD: user can fully control the path component of the URL
|
||||
resp = requests.get("https://api.example.com/user_info/" + user_id)
|
||||
|
||||
if user_id.isalnum():
|
||||
# GOOD: user_id is restricted to be alpha-numeric, and cannot alter path component of URL
|
||||
resp = requests.get("https://api.example.com/user_info/" + user_id)
|
||||
@@ -475,3 +475,31 @@ class CryptographicOperationTest extends InlineExpectationsTest {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class HttpClientRequestTest extends InlineExpectationsTest {
|
||||
HttpClientRequestTest() { this = "HttpClientRequestTest" }
|
||||
|
||||
override string getARelevantTag() {
|
||||
result in ["clientRequestUrlPart", "clientRequestCertValidationDisabled"]
|
||||
}
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(HTTP::Client::Request req, DataFlow::Node url |
|
||||
url = req.getAUrlPart() and
|
||||
location = url.getLocation() and
|
||||
element = url.toString() and
|
||||
value = prettyNodeForInlineTest(url) and
|
||||
tag = "clientRequestUrlPart"
|
||||
)
|
||||
or
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(HTTP::Client::Request req |
|
||||
req.disablesCertificateValidation(_, _) and
|
||||
location = req.getLocation() and
|
||||
element = req.toString() and
|
||||
value = "" and
|
||||
tag = "clientRequestCertValidationDisabled"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
import python
|
||||
import experimental.meta.ConceptsTest
|
||||
@@ -0,0 +1,3 @@
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
failures
|
||||
@@ -0,0 +1 @@
|
||||
import experimental.meta.InlineTaintTest
|
||||
@@ -0,0 +1,55 @@
|
||||
import requests
|
||||
|
||||
from flask import Flask, request
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
@app.route("/taint_test") # $ routeSetup="/taint_test"
|
||||
def test_taint(): # $ requestHandler
|
||||
url = request.args['untrusted_input']
|
||||
|
||||
# response from a request to a user-controlled URL should be considered
|
||||
# user-controlled as well.
|
||||
resp = requests.get(url) # $ clientRequestUrlPart=url
|
||||
|
||||
requests.Response
|
||||
requests.models.Response
|
||||
|
||||
ensure_tainted(
|
||||
url, # $ tainted
|
||||
# see https://docs.python-requests.org/en/latest/api/#requests.Response
|
||||
resp, # $ tainted
|
||||
resp.text, # $ tainted
|
||||
resp.content, # $ tainted
|
||||
resp.json(), # $ tainted
|
||||
|
||||
# file-like
|
||||
resp.raw, # $ tainted
|
||||
resp.raw.read(), # $ tainted
|
||||
|
||||
resp.links, # $ tainted
|
||||
resp.links['key'], # $ tainted
|
||||
resp.links.get('key'), # $ tainted
|
||||
|
||||
resp.cookies, # $ tainted
|
||||
resp.cookies['key'], # $ tainted
|
||||
resp.cookies.get('key'), # $ tainted
|
||||
|
||||
resp.headers, # $ tainted
|
||||
resp.headers['key'], # $ tainted
|
||||
resp.headers.get('key'), # $ tainted
|
||||
)
|
||||
|
||||
for content_chunk in resp.iter_content():
|
||||
ensure_tainted(content_chunk) # $ tainted
|
||||
|
||||
for line in resp.iter_lines():
|
||||
ensure_tainted(line) # $ tainted
|
||||
|
||||
# for now, we don't assume that the response to ANY outgoing request is a remote
|
||||
# flow source, since this could lead to FPs.
|
||||
# TODO: investigate whether we should consider this a remote flow source.
|
||||
trusted_url = "https://internal-api-that-i-trust.com"
|
||||
resp = requests.get(trusted_url) # $ clientRequestUrlPart=trusted_url
|
||||
ensure__not_tainted(resp)
|
||||
50
python/ql/test/library-tests/frameworks/requests/test.py
Normal file
50
python/ql/test/library-tests/frameworks/requests/test.py
Normal file
@@ -0,0 +1,50 @@
|
||||
import requests
|
||||
|
||||
resp = requests.get("url") # $ clientRequestUrlPart="url"
|
||||
resp = requests.get(url="url") # $ clientRequestUrlPart="url"
|
||||
|
||||
resp = requests.request("GET", "url") # $ clientRequestUrlPart="url"
|
||||
|
||||
with requests.Session() as session:
|
||||
resp = session.get("url") # $ clientRequestUrlPart="url"
|
||||
resp = session.request(method="GET", url="url") # $ clientRequestUrlPart="url"
|
||||
|
||||
s = requests.Session()
|
||||
resp = s.get("url") # $ clientRequestUrlPart="url"
|
||||
|
||||
s = requests.session()
|
||||
resp = s.get("url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# test full import path for Session
|
||||
with requests.sessions.Session() as session:
|
||||
resp = session.get("url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# Low level access
|
||||
req = requests.Request("GET", "url") # $ MISSING: clientRequestUrlPart="url"
|
||||
resp = s.send(req.prepare())
|
||||
|
||||
# other methods than GET
|
||||
resp = requests.post("url") # $ clientRequestUrlPart="url"
|
||||
resp = requests.patch("url") # $ clientRequestUrlPart="url"
|
||||
resp = requests.options("url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# ==============================================================================
|
||||
# Disabling certificate validation
|
||||
# ==============================================================================
|
||||
|
||||
resp = requests.get("url", verify=False) # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
|
||||
def make_get(verify_arg):
|
||||
resp = requests.get("url", verify=verify_arg) # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
|
||||
make_get(False)
|
||||
|
||||
|
||||
with requests.Session() as session:
|
||||
# see https://github.com/psf/requests/blob/39d0fdd9096f7dceccbc8f82e1eda7dd64717a8e/requests/sessions.py#L621
|
||||
session.verify = False
|
||||
resp = session.get("url") # $ clientRequestUrlPart="url" MISSING: clientRequestCertValidationDisabled
|
||||
resp = session.get("url", verify=True) # $ clientRequestUrlPart="url"
|
||||
|
||||
req = requests.Request("GET", "url") # $ MISSING: clientRequestUrlPart="url"
|
||||
resp = session.send(req.prepare()) # $ MISSING: clientRequestCertValidationDisabled
|
||||
170
python/ql/test/library-tests/frameworks/stdlib/http_client.py
Normal file
170
python/ql/test/library-tests/frameworks/stdlib/http_client.py
Normal file
@@ -0,0 +1,170 @@
|
||||
import sys
|
||||
import ssl
|
||||
|
||||
PY2 = sys.version_info[0] == 2
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
if PY2:
|
||||
from httplib import HTTPConnection, HTTPSConnection
|
||||
if PY3:
|
||||
from http.client import HTTPConnection, HTTPSConnection
|
||||
|
||||
|
||||
# NOTE: the URL may be relative to host, or may be full URL.
|
||||
conn = HTTPConnection("example.com") # $ clientRequestUrlPart="example.com"
|
||||
conn.request("GET", "/") # $ clientRequestUrlPart="/"
|
||||
url = "http://example.com/"
|
||||
conn.request("GET", url) # $ clientRequestUrlPart=url
|
||||
|
||||
# kwargs
|
||||
conn = HTTPConnection(host="example.com") # $ clientRequestUrlPart="example.com"
|
||||
conn.request(method="GET", url="/") # $ clientRequestUrlPart="/"
|
||||
|
||||
# using internal method... you shouldn't but you can
|
||||
conn._send_request("GET", "url", body=None, headers={}, encode_chunked=False) # $ clientRequestUrlPart="url"
|
||||
|
||||
# low level sending of request
|
||||
conn.putrequest("GET", "url") # $ clientRequestUrlPart="url"
|
||||
conn.putheader("X-Foo", "value")
|
||||
conn.endheaders(message_body=None)
|
||||
|
||||
# HTTPS
|
||||
conn = HTTPSConnection("host") # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# six aliases
|
||||
import six
|
||||
|
||||
conn = six.moves.http_client.HTTPConnection("host") # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url"
|
||||
|
||||
conn = six.moves.http_client.HTTPSConnection("host") # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# ==============================================================================
|
||||
# Certificate validation disabled
|
||||
# ==============================================================================
|
||||
|
||||
# default SSL context is the one given by `_create_default_https_context`
|
||||
context = ssl._create_default_https_context()
|
||||
assert context.check_hostname == True
|
||||
assert context.verify_mode == ssl.CERT_REQUIRED
|
||||
|
||||
conn = HTTPSConnection("host", context=context) # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# `_create_default_https_context` is currently just an alias for `create_default_context`
|
||||
# which creates a context for SERVER_AUTH purpose.
|
||||
context = ssl.create_default_context()
|
||||
assert context.check_hostname == True
|
||||
assert context.verify_mode == ssl.CERT_REQUIRED
|
||||
|
||||
conn = HTTPSConnection("host", context=context) # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# however, if you supply your own SSLContext, you need to set it manually
|
||||
context = ssl.SSLContext()
|
||||
assert context.check_hostname == False
|
||||
assert context.verify_mode == ssl.CERT_NONE
|
||||
|
||||
conn = HTTPSConnection("host", context=context) # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url" MISSING: clientRequestCertValidationDisabled
|
||||
|
||||
# and if you misunderstood whether to use server/client in the purpose, you will also
|
||||
# get a context without hostname verification.
|
||||
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
||||
assert context.check_hostname == False
|
||||
assert context.verify_mode == ssl.CERT_NONE
|
||||
|
||||
conn = HTTPSConnection("host", context=context) # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url" MISSING: clientRequestCertValidationDisabled
|
||||
|
||||
# NOTICE that current documentation says
|
||||
#
|
||||
# > Enabling hostname checking automatically sets verify_mode from CERT_NONE to
|
||||
# > CERT_REQUIRED. It cannot be set back to CERT_NONE as long as hostname checking is
|
||||
# > enabled.
|
||||
# - https://docs.python.org/3.10/library/ssl.html#ssl.SSLContext.check_hostname
|
||||
|
||||
context = ssl.SSLContext()
|
||||
context.check_hostname = True
|
||||
assert context.verify_mode == ssl.CERT_REQUIRED
|
||||
|
||||
conn = HTTPSConnection("host", context=context) # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# only setting verify_mode is not enough, since check_hostname is not enabled
|
||||
|
||||
context = ssl.SSLContext()
|
||||
context.verify_mode = ssl.CERT_REQUIRED
|
||||
assert context.check_hostname == False
|
||||
|
||||
conn = HTTPSConnection("host", context=context) # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url" MISSING: clientRequestCertValidationDisabled
|
||||
|
||||
# ==============================================================================
|
||||
# taint test
|
||||
# ==============================================================================
|
||||
|
||||
from flask import request
|
||||
|
||||
def taint_test():
|
||||
host = request.args['host']
|
||||
url = request.args['url']
|
||||
|
||||
conn = HTTPConnection(host) # $ clientRequestUrlPart=host
|
||||
conn.request("GET", url) # $ clientRequestUrlPart=url
|
||||
|
||||
resp = conn.getresponse()
|
||||
|
||||
ensure_tainted(
|
||||
# see
|
||||
# https://docs.python.org/3.10/library/http.client.html#httpresponse-objects
|
||||
# https://docs.python.org/3/library/http.client.html#http.client.HTTPResponse
|
||||
|
||||
# a HTTPResponse itself is file-like
|
||||
resp, # $ tainted
|
||||
resp.read(), # $ tainted
|
||||
|
||||
resp.getheader("name"), # $ tainted
|
||||
resp.getheaders(), # $ tainted
|
||||
|
||||
# http.client.HTTPMessage
|
||||
resp.headers, # $ tainted
|
||||
resp.headers.get_all(), # $ tainted
|
||||
|
||||
# Alias for .headers
|
||||
# http.client.HTTPMessage
|
||||
resp.msg, # $ tainted
|
||||
resp.msg.get_all(), # $ tainted
|
||||
|
||||
# Alias for .headers
|
||||
resp.info(), # $ tainted
|
||||
resp.info().get_all(), # $ tainted
|
||||
|
||||
# although this would usually be the textual version of the status
|
||||
# ("OK" for 200), it is possible to put your own evil data in here.
|
||||
resp.reason, # $ tainted
|
||||
|
||||
# the URL of the recourse that was visited, if redirects were followed.
|
||||
# I don't see any reason this could not contain evil data.
|
||||
resp.url, # $ tainted
|
||||
resp.geturl(), # $ tainted
|
||||
)
|
||||
|
||||
ensure_not_tainted(
|
||||
resp.status,
|
||||
resp.code,
|
||||
resp.getcode(),
|
||||
)
|
||||
|
||||
# check that only setting either host/url is enough to propagate taint
|
||||
conn = HTTPConnection("host") # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", url) # $ clientRequestUrlPart=url
|
||||
resp = conn.getresponse()
|
||||
ensure_tainted(resp) # $ tainted
|
||||
|
||||
conn = HTTPConnection(host) # $ clientRequestUrlPart=host
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url"
|
||||
resp = conn.getresponse()
|
||||
ensure_tainted(resp) # $ tainted
|
||||
@@ -0,0 +1,274 @@
|
||||
edges
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:8:17:8:23 | ControlFlowNode for request |
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:8:17:8:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute | full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute | full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:13:18:13:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:13:18:13:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:19:18:19:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:19:18:19:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:23:18:23:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:23:18:23:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:8:17:8:23 | ControlFlowNode for request | full_partial_test.py:8:17:8:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:8:17:8:28 | ControlFlowNode for Attribute | full_partial_test.py:8:17:8:41 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:8:17:8:41 | ControlFlowNode for Subscript | full_partial_test.py:23:18:23:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:38:17:38:23 | ControlFlowNode for request |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:38:17:38:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute | full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute | full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:42:18:42:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:42:18:42:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:45:18:45:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:45:18:45:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:48:18:48:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:48:18:48:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:51:18:51:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:51:18:51:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:54:18:54:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:54:18:54:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:38:17:38:23 | ControlFlowNode for request | full_partial_test.py:38:17:38:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:38:17:38:28 | ControlFlowNode for Attribute | full_partial_test.py:38:17:38:41 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:38:17:38:41 | ControlFlowNode for Subscript | full_partial_test.py:48:18:48:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:58:17:58:23 | ControlFlowNode for request |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:58:17:58:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute | full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute | full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:62:18:62:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:62:18:62:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:65:18:65:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:65:18:65:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:67:38:67:58 | ControlFlowNode for Tuple |
|
||||
| full_partial_test.py:58:17:58:23 | ControlFlowNode for request | full_partial_test.py:58:17:58:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:58:17:58:28 | ControlFlowNode for Attribute | full_partial_test.py:58:17:58:41 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:58:17:58:41 | ControlFlowNode for Subscript | full_partial_test.py:67:38:67:58 | ControlFlowNode for Tuple |
|
||||
| full_partial_test.py:67:38:67:58 | ControlFlowNode for Tuple | full_partial_test.py:68:18:68:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:72:17:72:23 | ControlFlowNode for request |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:72:17:72:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute | full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute | full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:76:18:76:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:76:18:76:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:79:18:79:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:79:18:79:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:82:18:82:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:82:18:82:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:72:17:72:23 | ControlFlowNode for request | full_partial_test.py:72:17:72:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:72:17:72:28 | ControlFlowNode for Attribute | full_partial_test.py:72:17:72:41 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:72:17:72:41 | ControlFlowNode for Subscript | full_partial_test.py:82:18:82:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:86:18:86:24 | ControlFlowNode for request | full_partial_test.py:86:18:86:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:86:18:86:29 | ControlFlowNode for Attribute | full_partial_test.py:86:18:86:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:86:18:86:48 | ControlFlowNode for Subscript | full_partial_test.py:89:18:89:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:92:18:92:24 | ControlFlowNode for request | full_partial_test.py:92:18:92:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:92:18:92:29 | ControlFlowNode for Attribute | full_partial_test.py:92:18:92:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:92:18:92:48 | ControlFlowNode for Subscript | full_partial_test.py:95:18:95:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:98:18:98:24 | ControlFlowNode for request | full_partial_test.py:98:18:98:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:98:18:98:29 | ControlFlowNode for Attribute | full_partial_test.py:98:18:98:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:98:18:98:48 | ControlFlowNode for Subscript | full_partial_test.py:101:18:101:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:104:18:104:24 | ControlFlowNode for request | full_partial_test.py:104:18:104:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:104:18:104:29 | ControlFlowNode for Attribute | full_partial_test.py:104:18:104:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:104:18:104:48 | ControlFlowNode for Subscript | full_partial_test.py:107:18:107:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:110:18:110:24 | ControlFlowNode for request | full_partial_test.py:110:18:110:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:110:18:110:29 | ControlFlowNode for Attribute | full_partial_test.py:110:18:110:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:110:18:110:48 | ControlFlowNode for Subscript | full_partial_test.py:116:18:116:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:119:18:119:24 | ControlFlowNode for request | full_partial_test.py:119:18:119:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:119:18:119:29 | ControlFlowNode for Attribute | full_partial_test.py:119:18:119:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:119:18:119:48 | ControlFlowNode for Subscript | full_partial_test.py:122:18:122:20 | ControlFlowNode for url |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:10:19:10:25 | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:10:19:10:25 | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:11:18:11:24 | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute | test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute | test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:11:18:11:24 | ControlFlowNode for request |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute | test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute | test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:11:18:11:24 | ControlFlowNode for request | test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute | test_http_client.py:11:18:11:48 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:11:18:11:48 | ControlFlowNode for Subscript | test_http_client.py:33:25:33:28 | ControlFlowNode for path |
|
||||
| test_http_client.py:11:18:11:48 | ControlFlowNode for Subscript | test_http_client.py:37:25:37:28 | ControlFlowNode for path |
|
||||
| test_requests.py:6:18:6:24 | ControlFlowNode for request | test_requests.py:6:18:6:29 | ControlFlowNode for Attribute |
|
||||
| test_requests.py:6:18:6:24 | ControlFlowNode for request | test_requests.py:6:18:6:29 | ControlFlowNode for Attribute |
|
||||
| test_requests.py:6:18:6:29 | ControlFlowNode for Attribute | test_requests.py:6:18:6:48 | ControlFlowNode for Subscript |
|
||||
| test_requests.py:6:18:6:29 | ControlFlowNode for Attribute | test_requests.py:6:18:6:48 | ControlFlowNode for Subscript |
|
||||
| test_requests.py:6:18:6:48 | ControlFlowNode for Subscript | test_requests.py:8:18:8:27 | ControlFlowNode for user_input |
|
||||
| test_requests.py:6:18:6:48 | ControlFlowNode for Subscript | test_requests.py:8:18:8:27 | ControlFlowNode for user_input |
|
||||
nodes
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:8:17:8:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:8:17:8:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:8:17:8:41 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input |
|
||||
| full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input |
|
||||
| full_partial_test.py:13:18:13:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:13:18:13:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:19:18:19:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:19:18:19:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:23:18:23:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:23:18:23:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:38:17:38:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:38:17:38:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:38:17:38:41 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:42:18:42:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:42:18:42:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:45:18:45:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:45:18:45:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:48:18:48:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:48:18:48:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:51:18:51:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:51:18:51:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:54:18:54:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:54:18:54:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:58:17:58:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:58:17:58:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:58:17:58:41 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:62:18:62:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:62:18:62:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:65:18:65:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:65:18:65:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:67:38:67:58 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple |
|
||||
| full_partial_test.py:68:18:68:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:72:17:72:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:72:17:72:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:72:17:72:41 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:76:18:76:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:76:18:76:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:79:18:79:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:79:18:79:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:82:18:82:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:82:18:82:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:86:18:86:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:86:18:86:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:86:18:86:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:89:18:89:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:92:18:92:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:92:18:92:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:92:18:92:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:95:18:95:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:98:18:98:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:98:18:98:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:98:18:98:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:101:18:101:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:104:18:104:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:104:18:104:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:104:18:104:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:107:18:107:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:110:18:110:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:110:18:110:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:110:18:110:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:116:18:116:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:119:18:119:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:119:18:119:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:119:18:119:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:122:18:122:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:11:18:11:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:11:18:11:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:33:25:33:28 | ControlFlowNode for path | semmle.label | ControlFlowNode for path |
|
||||
| test_http_client.py:37:25:37:28 | ControlFlowNode for path | semmle.label | ControlFlowNode for path |
|
||||
| test_requests.py:6:18:6:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_requests.py:6:18:6:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_requests.py:6:18:6:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_requests.py:6:18:6:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_requests.py:6:18:6:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_requests.py:6:18:6:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_requests.py:8:18:8:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input |
|
||||
| test_requests.py:8:18:8:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input |
|
||||
subpaths
|
||||
#select
|
||||
| full_partial_test.py:10:5:10:28 | ControlFlowNode for Attribute() | full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input | The full URL of this request depends on $@. | full_partial_test.py:7:18:7:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:13:5:13:21 | ControlFlowNode for Attribute() | full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:13:18:13:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:7:18:7:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:19:5:19:21 | ControlFlowNode for Attribute() | full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:19:18:19:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:7:18:7:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:23:5:23:21 | ControlFlowNode for Attribute() | full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:23:18:23:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:7:18:7:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:42:5:42:21 | ControlFlowNode for Attribute() | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:42:18:42:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:45:5:45:21 | ControlFlowNode for Attribute() | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:45:18:45:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:48:5:48:21 | ControlFlowNode for Attribute() | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:48:18:48:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:51:5:51:21 | ControlFlowNode for Attribute() | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:51:18:51:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:54:5:54:21 | ControlFlowNode for Attribute() | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:54:18:54:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:62:5:62:21 | ControlFlowNode for Attribute() | full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:62:18:62:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:57:18:57:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:65:5:65:21 | ControlFlowNode for Attribute() | full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:65:18:65:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:57:18:57:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:76:5:76:21 | ControlFlowNode for Attribute() | full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:76:18:76:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:71:18:71:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:79:5:79:21 | ControlFlowNode for Attribute() | full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:79:18:79:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:71:18:71:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:82:5:82:21 | ControlFlowNode for Attribute() | full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:82:18:82:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:71:18:71:24 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:14:5:14:36 | ControlFlowNode for Attribute() | test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host | The full URL of this request depends on $@. | test_http_client.py:9:19:9:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:14:5:14:36 | ControlFlowNode for Attribute() | test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path | The full URL of this request depends on $@. | test_http_client.py:9:19:9:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:14:5:14:36 | ControlFlowNode for Attribute() | test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path | The full URL of this request depends on $@. | test_http_client.py:10:19:10:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:19:5:19:36 | ControlFlowNode for Attribute() | test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host | The full URL of this request depends on $@. | test_http_client.py:9:19:9:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:19:5:19:36 | ControlFlowNode for Attribute() | test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path | The full URL of this request depends on $@. | test_http_client.py:9:19:9:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:19:5:19:36 | ControlFlowNode for Attribute() | test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path | The full URL of this request depends on $@. | test_http_client.py:10:19:10:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_requests.py:8:5:8:28 | ControlFlowNode for Attribute() | test_requests.py:6:18:6:24 | ControlFlowNode for request | test_requests.py:8:18:8:27 | ControlFlowNode for user_input | The full URL of this request depends on $@. | test_requests.py:6:18:6:24 | ControlFlowNode for request | a user-provided value |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE-918/FullServerSideRequestForgery.ql
|
||||
@@ -0,0 +1,271 @@
|
||||
edges
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:8:17:8:23 | ControlFlowNode for request |
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:8:17:8:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute | full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute | full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:13:18:13:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:13:18:13:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:19:18:19:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:19:18:19:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:23:18:23:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:23:18:23:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:8:17:8:23 | ControlFlowNode for request | full_partial_test.py:8:17:8:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:8:17:8:28 | ControlFlowNode for Attribute | full_partial_test.py:8:17:8:41 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:8:17:8:41 | ControlFlowNode for Subscript | full_partial_test.py:23:18:23:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:38:17:38:23 | ControlFlowNode for request |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:38:17:38:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute | full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute | full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:42:18:42:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:42:18:42:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:45:18:45:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:45:18:45:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:48:18:48:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:48:18:48:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:51:18:51:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:51:18:51:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:54:18:54:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:54:18:54:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:38:17:38:23 | ControlFlowNode for request | full_partial_test.py:38:17:38:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:38:17:38:28 | ControlFlowNode for Attribute | full_partial_test.py:38:17:38:41 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:38:17:38:41 | ControlFlowNode for Subscript | full_partial_test.py:48:18:48:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:58:17:58:23 | ControlFlowNode for request |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:58:17:58:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute | full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute | full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:62:18:62:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:62:18:62:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:65:18:65:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:65:18:65:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:67:38:67:58 | ControlFlowNode for Tuple |
|
||||
| full_partial_test.py:58:17:58:23 | ControlFlowNode for request | full_partial_test.py:58:17:58:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:58:17:58:28 | ControlFlowNode for Attribute | full_partial_test.py:58:17:58:41 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:58:17:58:41 | ControlFlowNode for Subscript | full_partial_test.py:67:38:67:58 | ControlFlowNode for Tuple |
|
||||
| full_partial_test.py:67:38:67:58 | ControlFlowNode for Tuple | full_partial_test.py:68:18:68:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:72:17:72:23 | ControlFlowNode for request |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:72:17:72:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute | full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute | full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:76:18:76:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:76:18:76:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:79:18:79:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:79:18:79:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:82:18:82:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:82:18:82:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:72:17:72:23 | ControlFlowNode for request | full_partial_test.py:72:17:72:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:72:17:72:28 | ControlFlowNode for Attribute | full_partial_test.py:72:17:72:41 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:72:17:72:41 | ControlFlowNode for Subscript | full_partial_test.py:82:18:82:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:86:18:86:24 | ControlFlowNode for request | full_partial_test.py:86:18:86:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:86:18:86:29 | ControlFlowNode for Attribute | full_partial_test.py:86:18:86:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:86:18:86:48 | ControlFlowNode for Subscript | full_partial_test.py:89:18:89:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:92:18:92:24 | ControlFlowNode for request | full_partial_test.py:92:18:92:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:92:18:92:29 | ControlFlowNode for Attribute | full_partial_test.py:92:18:92:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:92:18:92:48 | ControlFlowNode for Subscript | full_partial_test.py:95:18:95:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:98:18:98:24 | ControlFlowNode for request | full_partial_test.py:98:18:98:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:98:18:98:29 | ControlFlowNode for Attribute | full_partial_test.py:98:18:98:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:98:18:98:48 | ControlFlowNode for Subscript | full_partial_test.py:101:18:101:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:104:18:104:24 | ControlFlowNode for request | full_partial_test.py:104:18:104:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:104:18:104:29 | ControlFlowNode for Attribute | full_partial_test.py:104:18:104:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:104:18:104:48 | ControlFlowNode for Subscript | full_partial_test.py:107:18:107:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:110:18:110:24 | ControlFlowNode for request | full_partial_test.py:110:18:110:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:110:18:110:29 | ControlFlowNode for Attribute | full_partial_test.py:110:18:110:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:110:18:110:48 | ControlFlowNode for Subscript | full_partial_test.py:116:18:116:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:119:18:119:24 | ControlFlowNode for request | full_partial_test.py:119:18:119:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:119:18:119:29 | ControlFlowNode for Attribute | full_partial_test.py:119:18:119:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:119:18:119:48 | ControlFlowNode for Subscript | full_partial_test.py:122:18:122:20 | ControlFlowNode for url |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:10:19:10:25 | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:10:19:10:25 | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:11:18:11:24 | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute | test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute | test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:11:18:11:24 | ControlFlowNode for request |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute | test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute | test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:11:18:11:24 | ControlFlowNode for request | test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute | test_http_client.py:11:18:11:48 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:11:18:11:48 | ControlFlowNode for Subscript | test_http_client.py:33:25:33:28 | ControlFlowNode for path |
|
||||
| test_http_client.py:11:18:11:48 | ControlFlowNode for Subscript | test_http_client.py:37:25:37:28 | ControlFlowNode for path |
|
||||
| test_requests.py:6:18:6:24 | ControlFlowNode for request | test_requests.py:6:18:6:29 | ControlFlowNode for Attribute |
|
||||
| test_requests.py:6:18:6:24 | ControlFlowNode for request | test_requests.py:6:18:6:29 | ControlFlowNode for Attribute |
|
||||
| test_requests.py:6:18:6:29 | ControlFlowNode for Attribute | test_requests.py:6:18:6:48 | ControlFlowNode for Subscript |
|
||||
| test_requests.py:6:18:6:29 | ControlFlowNode for Attribute | test_requests.py:6:18:6:48 | ControlFlowNode for Subscript |
|
||||
| test_requests.py:6:18:6:48 | ControlFlowNode for Subscript | test_requests.py:8:18:8:27 | ControlFlowNode for user_input |
|
||||
| test_requests.py:6:18:6:48 | ControlFlowNode for Subscript | test_requests.py:8:18:8:27 | ControlFlowNode for user_input |
|
||||
nodes
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:8:17:8:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:8:17:8:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:8:17:8:41 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input |
|
||||
| full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input |
|
||||
| full_partial_test.py:13:18:13:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:13:18:13:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:19:18:19:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:19:18:19:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:23:18:23:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:23:18:23:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:38:17:38:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:38:17:38:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:38:17:38:41 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:42:18:42:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:42:18:42:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:45:18:45:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:45:18:45:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:48:18:48:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:48:18:48:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:51:18:51:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:51:18:51:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:54:18:54:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:54:18:54:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:58:17:58:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:58:17:58:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:58:17:58:41 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:62:18:62:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:62:18:62:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:65:18:65:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:65:18:65:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:67:38:67:58 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple |
|
||||
| full_partial_test.py:68:18:68:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:72:17:72:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:72:17:72:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:72:17:72:41 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:76:18:76:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:76:18:76:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:79:18:79:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:79:18:79:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:82:18:82:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:82:18:82:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:86:18:86:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:86:18:86:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:86:18:86:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:89:18:89:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:92:18:92:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:92:18:92:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:92:18:92:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:95:18:95:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:98:18:98:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:98:18:98:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:98:18:98:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:101:18:101:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:104:18:104:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:104:18:104:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:104:18:104:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:107:18:107:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:110:18:110:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:110:18:110:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:110:18:110:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:116:18:116:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:119:18:119:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:119:18:119:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:119:18:119:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:122:18:122:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:11:18:11:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:11:18:11:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:33:25:33:28 | ControlFlowNode for path | semmle.label | ControlFlowNode for path |
|
||||
| test_http_client.py:37:25:37:28 | ControlFlowNode for path | semmle.label | ControlFlowNode for path |
|
||||
| test_requests.py:6:18:6:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_requests.py:6:18:6:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_requests.py:6:18:6:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_requests.py:6:18:6:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_requests.py:6:18:6:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_requests.py:6:18:6:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_requests.py:8:18:8:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input |
|
||||
| test_requests.py:8:18:8:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input |
|
||||
subpaths
|
||||
#select
|
||||
| full_partial_test.py:68:5:68:21 | ControlFlowNode for Attribute() | full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:68:18:68:20 | ControlFlowNode for url | Part of the URL of this request depends on $@. | full_partial_test.py:57:18:57:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:68:5:68:21 | ControlFlowNode for Attribute() | full_partial_test.py:58:17:58:23 | ControlFlowNode for request | full_partial_test.py:68:18:68:20 | ControlFlowNode for url | Part of the URL of this request depends on $@. | full_partial_test.py:58:17:58:23 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:89:5:89:21 | ControlFlowNode for Attribute() | full_partial_test.py:86:18:86:24 | ControlFlowNode for request | full_partial_test.py:89:18:89:20 | ControlFlowNode for url | Part of the URL of this request depends on $@. | full_partial_test.py:86:18:86:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:95:5:95:21 | ControlFlowNode for Attribute() | full_partial_test.py:92:18:92:24 | ControlFlowNode for request | full_partial_test.py:95:18:95:20 | ControlFlowNode for url | Part of the URL of this request depends on $@. | full_partial_test.py:92:18:92:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:101:5:101:21 | ControlFlowNode for Attribute() | full_partial_test.py:98:18:98:24 | ControlFlowNode for request | full_partial_test.py:101:18:101:20 | ControlFlowNode for url | Part of the URL of this request depends on $@. | full_partial_test.py:98:18:98:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:107:5:107:21 | ControlFlowNode for Attribute() | full_partial_test.py:104:18:104:24 | ControlFlowNode for request | full_partial_test.py:107:18:107:20 | ControlFlowNode for url | Part of the URL of this request depends on $@. | full_partial_test.py:104:18:104:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:116:5:116:21 | ControlFlowNode for Attribute() | full_partial_test.py:110:18:110:24 | ControlFlowNode for request | full_partial_test.py:116:18:116:20 | ControlFlowNode for url | Part of the URL of this request depends on $@. | full_partial_test.py:110:18:110:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:122:5:122:21 | ControlFlowNode for Attribute() | full_partial_test.py:119:18:119:24 | ControlFlowNode for request | full_partial_test.py:122:18:122:20 | ControlFlowNode for url | Part of the URL of this request depends on $@. | full_partial_test.py:119:18:119:24 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:22:5:22:31 | ControlFlowNode for Attribute() | test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host | Part of the URL of this request depends on $@. | test_http_client.py:9:19:9:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:26:5:26:31 | ControlFlowNode for Attribute() | test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host | Part of the URL of this request depends on $@. | test_http_client.py:9:19:9:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:29:5:29:36 | ControlFlowNode for Attribute() | test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path | Part of the URL of this request depends on $@. | test_http_client.py:9:19:9:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:29:5:29:36 | ControlFlowNode for Attribute() | test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path | Part of the URL of this request depends on $@. | test_http_client.py:10:19:10:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:33:5:33:29 | ControlFlowNode for Attribute() | test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:33:25:33:28 | ControlFlowNode for path | Part of the URL of this request depends on $@. | test_http_client.py:9:19:9:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:33:5:33:29 | ControlFlowNode for Attribute() | test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:33:25:33:28 | ControlFlowNode for path | Part of the URL of this request depends on $@. | test_http_client.py:10:19:10:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:33:5:33:29 | ControlFlowNode for Attribute() | test_http_client.py:11:18:11:24 | ControlFlowNode for request | test_http_client.py:33:25:33:28 | ControlFlowNode for path | Part of the URL of this request depends on $@. | test_http_client.py:11:18:11:24 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:37:5:37:29 | ControlFlowNode for Attribute() | test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:37:25:37:28 | ControlFlowNode for path | Part of the URL of this request depends on $@. | test_http_client.py:9:19:9:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:37:5:37:29 | ControlFlowNode for Attribute() | test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:37:25:37:28 | ControlFlowNode for path | Part of the URL of this request depends on $@. | test_http_client.py:10:19:10:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:37:5:37:29 | ControlFlowNode for Attribute() | test_http_client.py:11:18:11:24 | ControlFlowNode for request | test_http_client.py:37:25:37:28 | ControlFlowNode for path | Part of the URL of this request depends on $@. | test_http_client.py:11:18:11:24 | ControlFlowNode for request | a user-provided value |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE-918/PartialServerSideRequestForgery.ql
|
||||
@@ -0,0 +1,122 @@
|
||||
from flask import request
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
def full_ssrf():
|
||||
user_input = request.args['untrusted_input']
|
||||
query_val = request.args['query_val']
|
||||
|
||||
requests.get(user_input) # NOT OK -- user has full control
|
||||
|
||||
url = "https://" + user_input
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
# although the path `/foo` is added here, this can be circumvented such that the
|
||||
# final URL is `https://evil.com/#/foo" -- since the fragment (#) is not sent to the
|
||||
# server.
|
||||
url = "https://" + user_input + "/foo"
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
# this might seem like a dummy test, but it serves to check how our sanitizers work.
|
||||
url = "https://" + user_input + "/foo?key=" + query_val
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
# taint-steps are added as `fromNode -> toNode`, but when adding a sanitizer it's
|
||||
# currently only possible to so on either `fromNode` or `toNode` (either all edges in
|
||||
# and out, or just the edges in or out). The sanitizers for full URL control is applied
|
||||
# on the `fromNode`, since for `"https://{}/{}".format(user_input1, user_input2)` there
|
||||
# is still a valid taint-step for `user_input1` -- if we made `toNode` a sanitizer that
|
||||
# would also remove this flow that we actually want. When coupled with use-use flow,
|
||||
# this means that later uses of a sanitized value will no longer be tainted, so
|
||||
# `requests.get(user_input2)` would no longer give an alert. To overcome this problem,
|
||||
# we split these tests into multiple functions, so we do not get this use-use flow, and
|
||||
# therefore know we are able to see where the sanitizers are applied.
|
||||
|
||||
def full_ssrf_format():
|
||||
user_input = request.args['untrusted_input']
|
||||
query_val = request.args['query_val']
|
||||
|
||||
# using .format
|
||||
url = "https://{}".format(user_input)
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
url = "https://{}/foo".format(user_input)
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
url = "https://{}/foo?key={}".format(user_input, query_val)
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
url = "https://{x}".format(x=user_input)
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
url = "https://{1}".format(0, user_input)
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
def full_ssrf_percent_format():
|
||||
user_input = request.args['untrusted_input']
|
||||
query_val = request.args['query_val']
|
||||
|
||||
# using %-formatting
|
||||
url = "https://%s" % user_input
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
url = "https://%s/foo" % user_input
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
url = "https://%s/foo/key=%s" % (user_input, query_val)
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
def full_ssrf_f_strings():
|
||||
user_input = request.args['untrusted_input']
|
||||
query_val = request.args['query_val']
|
||||
|
||||
# using f-strings
|
||||
url = f"https://{user_input}"
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
url = f"https://{user_input}/foo"
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
url = f"https://{user_input}/foo?key={query_val}"
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
|
||||
def partial_ssrf_1():
|
||||
user_input = request.args['untrusted_input']
|
||||
|
||||
url = "https://example.com/foo?" + user_input
|
||||
requests.get(url) # NOT OK -- user controls query parameters
|
||||
|
||||
def partial_ssrf_2():
|
||||
user_input = request.args['untrusted_input']
|
||||
|
||||
url = "https://example.com/" + user_input
|
||||
requests.get(url) # NOT OK -- user controls path
|
||||
|
||||
def partial_ssrf_3():
|
||||
user_input = request.args['untrusted_input']
|
||||
|
||||
url = "https://example.com/" + user_input
|
||||
requests.get(url) # NOT OK -- user controls path
|
||||
|
||||
def partial_ssrf_4():
|
||||
user_input = request.args['untrusted_input']
|
||||
|
||||
url = "https://example.com/foo#{}".format(user_input)
|
||||
requests.get(url) # NOT OK -- user contollred fragment
|
||||
|
||||
def partial_ssrf_5():
|
||||
user_input = request.args['untrusted_input']
|
||||
|
||||
# this is probably the least interesting one, since it's only the fragment that is
|
||||
# controlled
|
||||
|
||||
url = "https://example.com/foo#%s" % user_input
|
||||
requests.get(url) # NOT OK -- user contollred fragment
|
||||
|
||||
def partial_ssrf_6():
|
||||
user_input = request.args['untrusted_input']
|
||||
|
||||
url = f"https://example.com/foo#{user_input}"
|
||||
requests.get(url) # NOT OK -- user only controlled fragment
|
||||
@@ -0,0 +1 @@
|
||||
semmle-extractor-options: --lang=3 --max-import-depth=1
|
||||
@@ -0,0 +1,37 @@
|
||||
from flask import Flask, request
|
||||
|
||||
from http.client import HTTPConnection
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/ssrf_test") # $ routeSetup="/ssrf_test"
|
||||
def ssrf_test():
|
||||
unsafe_host = request.args["host"]
|
||||
unsafe_path = request.args["path"]
|
||||
user_input = request.args['untrusted_input']
|
||||
|
||||
conn = HTTPConnection(unsafe_host)
|
||||
conn.request("GET", unsafe_path) # NOT OK -- user has full control
|
||||
|
||||
# Full SSRF variant, where there is ALSO made a request with fixed URL on the same
|
||||
# connection later on. This should not change anything on the overall SSRF alerts.
|
||||
conn = HTTPConnection(unsafe_host)
|
||||
conn.request("GET", unsafe_path) # NOT OK -- user has full control
|
||||
|
||||
# partial SSRF on SAME connection
|
||||
conn.request("GET", "/foo") # NOT OK -- user has control of host
|
||||
|
||||
# the rest are partial SSRF
|
||||
conn = HTTPConnection(unsafe_host)
|
||||
conn.request("GET", "/foo") # NOT OK -- user controlled domain
|
||||
|
||||
conn = HTTPConnection("example.com")
|
||||
conn.request("GET", unsafe_path) # NOT OK -- user controlled path
|
||||
|
||||
path = "foo?" + user_input
|
||||
conn = HTTPConnection("example.com")
|
||||
conn.request("GET", path) # NOT OK -- user controlled query parameters
|
||||
|
||||
path = "foo#" + user_input
|
||||
conn = HTTPConnection("example.com")
|
||||
conn.request("GET", path) # NOT OK -- user controlled fragment
|
||||
@@ -0,0 +1,11 @@
|
||||
from flask import request
|
||||
|
||||
import requests
|
||||
|
||||
def ssrf_test():
|
||||
user_input = request.args['untrusted_input']
|
||||
|
||||
requests.get(user_input) # NOT OK -- user has full control
|
||||
|
||||
# since `requests`` always uses complete URLs, it's not interesting to test more of
|
||||
# the framework directly. See `full_partial_test.py` for different ways to do SSRF.
|
||||
Reference in New Issue
Block a user