From e171123589612565792a6c45ebc308cef2732ac8 Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Fri, 29 Sep 2023 18:25:58 +0200 Subject: [PATCH 01/29] Add initial query for CWE-942 --- javascript/ql/lib/javascript.qll | 1 + .../javascript/frameworks/ApolloGraphQL.qll | 59 +++++++++++++++++++ ...sPermissiveConfigurationCustomizations.qll | 50 ++++++++++++++++ .../CorsPermissiveConfigurationQuery.qll | 28 +++++++++ .../CWE-942/CorsPermissiveConfiguration.ql | 20 +++++++ .../CorsPermissiveConfiguration.expected | 39 ++++++++++++ .../CWE-942/CorsPermissiveConfiguration.qlref | 1 + .../test/query-tests/Security/CWE-942/tst.js | 33 +++++++++++ 8 files changed, 231 insertions(+) create mode 100644 javascript/ql/lib/semmle/javascript/frameworks/ApolloGraphQL.qll create mode 100644 javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll create mode 100644 javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationQuery.qll create mode 100644 javascript/ql/src/Security/CWE-942/CorsPermissiveConfiguration.ql create mode 100644 javascript/ql/test/query-tests/Security/CWE-942/CorsPermissiveConfiguration.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-942/CorsPermissiveConfiguration.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-942/tst.js diff --git a/javascript/ql/lib/javascript.qll b/javascript/ql/lib/javascript.qll index 07fb759bd655..207336b1cca3 100644 --- a/javascript/ql/lib/javascript.qll +++ b/javascript/ql/lib/javascript.qll @@ -71,6 +71,7 @@ import semmle.javascript.frameworks.ActionsLib import semmle.javascript.frameworks.Angular2 import semmle.javascript.frameworks.AngularJS import semmle.javascript.frameworks.Anser +import semmle.javascript.frameworks.ApolloGraphQL import semmle.javascript.frameworks.AsyncPackage import semmle.javascript.frameworks.AWS import semmle.javascript.frameworks.Azure diff --git a/javascript/ql/lib/semmle/javascript/frameworks/ApolloGraphQL.qll b/javascript/ql/lib/semmle/javascript/frameworks/ApolloGraphQL.qll new file mode 100644 index 000000000000..0a90f38867aa --- /dev/null +++ b/javascript/ql/lib/semmle/javascript/frameworks/ApolloGraphQL.qll @@ -0,0 +1,59 @@ +/** + * Provides classes for working with Apollo GraphQL connectors. + */ + +import javascript + +/** Provides classes modeling concepts of Apollo GraphQL. */ +module ApolloGraphQL { + /** A string-valued expression that is interpreted as a Apollo GraphQL query. */ + abstract class GraphQLString extends DataFlow::Node { } + + /** A string-valued expression that is interpreted as a Apollo GraphQL query. */ + abstract class ApolloGraphQLServer extends DataFlow::Node { } +} + +/** + * Provides classes modeling the apollo packages [@apollo/server](https://npmjs.com/package/@apollo/server`) + */ +private module Apollo { + /** Get an instanceof of `Apollo` */ + private API::Node apollo() { + result = + API::moduleImport([ + "@apollo/server", "apollo/server", "@apollo/apollo-server-express", + "@apollo/apollo-server-core", "apollo-server", "apollo-server-express" + ]).getMember("ApolloServer") + } + + /** Get an instanceof of `gql` */ + private API::Node gql() { + result = + API::moduleImport([ + "@apollo/server", "apollo/server", "@apollo/apollo-server-express", + "@apollo/apollo-server-core", "apollo-server", "apollo-server-express" + ]).getMember("gql") + } + + /** A string that is interpreted as a GraphQL query by a `octokit` package. */ + private class ApolloGraphQLString extends GraphQL::GraphQLString { + ApolloGraphQLString() { this = gql().getACall() } + } + + /** A string that is interpreted as a GraphQL query by a `graphql` package. */ + private class ApolloServer extends ApolloGraphQL::ApolloGraphQLServer { + ApolloServer() { + this = apollo().getAnInstantiation() + // or this = apollo().getAnInstantiation().getOptionArgument(0, "cors") + } + + predicate isPermissive() { + this.(DataFlow::NewNode) + .getOptionArgument(0, "cors") + .getALocalSource() + .getAPropertyWrite("origin") + .getRhs() + .mayHaveBooleanValue(true) + } + } +} diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll new file mode 100644 index 000000000000..dc87acc8a1da --- /dev/null +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll @@ -0,0 +1,50 @@ +/** + * Provides default sources, sinks and sanitizers for reasoning about + * overly permissive CORS configurations, as well as + * extension points for adding your own. + */ + +import javascript + +module CorsPermissiveConfiguration { + /** + * A data flow source for permissive CORS configuration. + */ + abstract class Source extends DataFlow::Node { } + + /** + * A data flow sink for permissive CORS configuration. + */ + abstract class Sink extends DataFlow::Node { } + + /** + * A sanitizer for permissive CORS configuration. + */ + abstract class Sanitizer extends DataFlow::Node { } + + /** A source of remote user input, considered as a flow source for CORS misconfiguration. */ + class RemoteFlowSourceAsSource extends Source instanceof RemoteFlowSource { + RemoteFlowSourceAsSource() { not this instanceof ClientSideRemoteFlowSource } + } + + /** true and null are considered bad values */ + class BadValues extends Source instanceof DataFlow::Node { + BadValues() { this.mayHaveBooleanValue(true) or this.asExpr() instanceof NullLiteral } + } + + /** + * The value of cors origin when initializing the application. + */ + class CorsApolloServer extends Sink, DataFlow::ValueNode { + CorsApolloServer() { + exists(ApolloGraphQL::ApolloGraphQLServer agql | + this = + agql.(DataFlow::NewNode) + .getOptionArgument(0, "cors") + .getALocalSource() + .getAPropertyWrite("origin") + .getRhs() + ) + } + } +} diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationQuery.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationQuery.qll new file mode 100644 index 000000000000..bc39328409f5 --- /dev/null +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationQuery.qll @@ -0,0 +1,28 @@ +/** + * Provides a dataflow taint tracking configuration for reasoning + * about overly permissive CORS configurations. + * + * Note, for performance reasons: only import this file if + * `CorsPermissiveConfiguration::Configuration` is needed, + * otherwise `CorsPermissiveConfigurationCustomizations` should + * be imported instead. + */ + +import javascript +import CorsPermissiveConfigurationCustomizations::CorsPermissiveConfiguration + +/** + * A data flow configuration for overly permissive CORS configuration. + */ +class Configuration extends TaintTracking::Configuration { + Configuration() { this = "CorsPermissiveConfiguration" } + + override predicate isSource(DataFlow::Node source) { source instanceof Source } + + override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + override predicate isSanitizer(DataFlow::Node node) { + super.isSanitizer(node) or + node instanceof Sanitizer + } +} diff --git a/javascript/ql/src/Security/CWE-942/CorsPermissiveConfiguration.ql b/javascript/ql/src/Security/CWE-942/CorsPermissiveConfiguration.ql new file mode 100644 index 000000000000..1cb01c9fe1c6 --- /dev/null +++ b/javascript/ql/src/Security/CWE-942/CorsPermissiveConfiguration.ql @@ -0,0 +1,20 @@ +/** + * @name overly CORS configuration + * @description Misconfiguration of CORS HTTP headers allows CSRF attacks. + * @kind path-problem + * @problem.severity error + * @security-severity 7.5 + * @precision high + * @id js/cors-misconfiguration + * @tags security + * external/cwe/cwe-942 + */ + +import javascript +import semmle.javascript.security.dataflow.CorsPermissiveConfigurationQuery +import DataFlow::PathGraph + +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "$@ misconfiguration due to a $@.", sink.getNode(), + "CORS Origin", source.getNode(), "too permissive or user controlled value" diff --git a/javascript/ql/test/query-tests/Security/CWE-942/CorsPermissiveConfiguration.expected b/javascript/ql/test/query-tests/Security/CWE-942/CorsPermissiveConfiguration.expected new file mode 100644 index 000000000000..7862049eeed6 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-942/CorsPermissiveConfiguration.expected @@ -0,0 +1,39 @@ +nodes +| tst.js:8:9:8:59 | user_origin | +| tst.js:8:23:8:46 | url.par ... , true) | +| tst.js:8:23:8:52 | url.par ... ).query | +| tst.js:8:23:8:59 | url.par ... .origin | +| tst.js:8:33:8:39 | req.url | +| tst.js:8:33:8:39 | req.url | +| tst.js:8:42:8:45 | true | +| tst.js:8:42:8:45 | true | +| tst.js:11:25:11:28 | true | +| tst.js:11:25:11:28 | true | +| tst.js:11:25:11:28 | true | +| tst.js:16:25:16:28 | true | +| tst.js:16:25:16:28 | true | +| tst.js:16:25:16:28 | true | +| tst.js:26:25:26:28 | null | +| tst.js:26:25:26:28 | null | +| tst.js:26:25:26:28 | null | +| tst.js:31:25:31:35 | user_origin | +| tst.js:31:25:31:35 | user_origin | +edges +| tst.js:8:9:8:59 | user_origin | tst.js:31:25:31:35 | user_origin | +| tst.js:8:9:8:59 | user_origin | tst.js:31:25:31:35 | user_origin | +| tst.js:8:23:8:46 | url.par ... , true) | tst.js:8:23:8:52 | url.par ... ).query | +| tst.js:8:23:8:52 | url.par ... ).query | tst.js:8:23:8:59 | url.par ... .origin | +| tst.js:8:23:8:59 | url.par ... .origin | tst.js:8:9:8:59 | user_origin | +| tst.js:8:33:8:39 | req.url | tst.js:8:23:8:46 | url.par ... , true) | +| tst.js:8:33:8:39 | req.url | tst.js:8:23:8:46 | url.par ... , true) | +| tst.js:8:42:8:45 | true | tst.js:8:23:8:46 | url.par ... , true) | +| tst.js:8:42:8:45 | true | tst.js:8:23:8:46 | url.par ... , true) | +| tst.js:11:25:11:28 | true | tst.js:11:25:11:28 | true | +| tst.js:16:25:16:28 | true | tst.js:16:25:16:28 | true | +| tst.js:26:25:26:28 | null | tst.js:26:25:26:28 | null | +#select +| tst.js:11:25:11:28 | true | tst.js:11:25:11:28 | true | tst.js:11:25:11:28 | true | $@ misconfiguration due to a $@. | tst.js:11:25:11:28 | true | CORS Origin | tst.js:11:25:11:28 | true | too permissive or user controlled value | +| tst.js:16:25:16:28 | true | tst.js:16:25:16:28 | true | tst.js:16:25:16:28 | true | $@ misconfiguration due to a $@. | tst.js:16:25:16:28 | true | CORS Origin | tst.js:16:25:16:28 | true | too permissive or user controlled value | +| tst.js:26:25:26:28 | null | tst.js:26:25:26:28 | null | tst.js:26:25:26:28 | null | $@ misconfiguration due to a $@. | tst.js:26:25:26:28 | null | CORS Origin | tst.js:26:25:26:28 | null | too permissive or user controlled value | +| tst.js:31:25:31:35 | user_origin | tst.js:8:33:8:39 | req.url | tst.js:31:25:31:35 | user_origin | $@ misconfiguration due to a $@. | tst.js:31:25:31:35 | user_origin | CORS Origin | tst.js:8:33:8:39 | req.url | too permissive or user controlled value | +| tst.js:31:25:31:35 | user_origin | tst.js:8:42:8:45 | true | tst.js:31:25:31:35 | user_origin | $@ misconfiguration due to a $@. | tst.js:31:25:31:35 | user_origin | CORS Origin | tst.js:8:42:8:45 | true | too permissive or user controlled value | diff --git a/javascript/ql/test/query-tests/Security/CWE-942/CorsPermissiveConfiguration.qlref b/javascript/ql/test/query-tests/Security/CWE-942/CorsPermissiveConfiguration.qlref new file mode 100644 index 000000000000..f8adf3cd38e6 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-942/CorsPermissiveConfiguration.qlref @@ -0,0 +1 @@ +Security/CWE-942/CorsPermissiveConfiguration.ql diff --git a/javascript/ql/test/query-tests/Security/CWE-942/tst.js b/javascript/ql/test/query-tests/Security/CWE-942/tst.js new file mode 100644 index 000000000000..60040e965372 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-942/tst.js @@ -0,0 +1,33 @@ +import { ApolloServer } from 'apollo-server'; +var https = require('https'), + url = require('url'); + +var server = https.createServer(function () { }); + +server.on('request', function (req, res) { + let user_origin = url.parse(req.url, true).query.origin; + // BAD: attacker can choose the value of origin + const server_1 = new ApolloServer({ + cors: { origin: true } + }); + + // BAD: CORS too permissive + const server_2 = new ApolloServer({ + cors: { origin: true } + }); + + // GOOD: restrictive CORS + const server_3 = new ApolloServer({ + cors: false + }); + + // BAD: CORS too permissive + const server_4 = new ApolloServer({ + cors: { origin: null } + }); + + // BAD: CORS is controlled by user + const server_5 = new ApolloServer({ + cors: { origin: user_origin } + }); +}); \ No newline at end of file From 142ab01b48ebf8d49d3a490be4854e5acc56fd3f Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Fri, 29 Sep 2023 18:32:12 +0200 Subject: [PATCH 02/29] Remove comment line --- .../ql/lib/semmle/javascript/frameworks/ApolloGraphQL.qll | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/ApolloGraphQL.qll b/javascript/ql/lib/semmle/javascript/frameworks/ApolloGraphQL.qll index 0a90f38867aa..9dea34df3b0a 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/ApolloGraphQL.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/ApolloGraphQL.qll @@ -42,10 +42,7 @@ private module Apollo { /** A string that is interpreted as a GraphQL query by a `graphql` package. */ private class ApolloServer extends ApolloGraphQL::ApolloGraphQLServer { - ApolloServer() { - this = apollo().getAnInstantiation() - // or this = apollo().getAnInstantiation().getOptionArgument(0, "cors") - } + ApolloServer() { this = apollo().getAnInstantiation() } predicate isPermissive() { this.(DataFlow::NewNode) From 816eebbb515e49a8ea78c95fc0d6b3ae92586ebd Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Mon, 2 Oct 2023 18:05:39 +0200 Subject: [PATCH 03/29] Add `.qhelp` and apply some review changes --- javascript/ql/lib/javascript.qll | 2 +- .../semmle/javascript/frameworks/Apollo.qll | 36 ++++++++++ .../javascript/frameworks/ApolloGraphQL.qll | 56 --------------- ...sPermissiveConfigurationCustomizations.qll | 12 ++-- .../CWE-942/CorsPermissiveConfiguration.qhelp | 71 +++++++++++++++++++ .../CWE-942/CorsPermissiveConfiguration.ql | 4 +- .../CorsPermissiveConfigurationBad.js | 18 +++++ .../CorsPermissiveConfigurationGood.js | 18 +++++ .../CorsPermissiveConfiguration.expected | 34 +++++++++ .../CWE-942/CorsPermissiveConfiguration.qlref | 1 + .../Security/CWE-942/tst.js | 13 ++-- .../CorsPermissiveConfiguration.expected | 39 ---------- .../CWE-942/CorsPermissiveConfiguration.qlref | 1 - 13 files changed, 189 insertions(+), 116 deletions(-) create mode 100644 javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll delete mode 100644 javascript/ql/lib/semmle/javascript/frameworks/ApolloGraphQL.qll create mode 100644 javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfiguration.qhelp rename javascript/ql/src/{ => experimental}/Security/CWE-942/CorsPermissiveConfiguration.ql (76%) create mode 100644 javascript/ql/src/experimental/Security/CWE-942/examples/CorsPermissiveConfigurationBad.js create mode 100644 javascript/ql/src/experimental/Security/CWE-942/examples/CorsPermissiveConfigurationGood.js create mode 100644 javascript/ql/test/experimental/Security/CWE-942/CorsPermissiveConfiguration.expected create mode 100644 javascript/ql/test/experimental/Security/CWE-942/CorsPermissiveConfiguration.qlref rename javascript/ql/test/{query-tests => experimental}/Security/CWE-942/tst.js (80%) delete mode 100644 javascript/ql/test/query-tests/Security/CWE-942/CorsPermissiveConfiguration.expected delete mode 100644 javascript/ql/test/query-tests/Security/CWE-942/CorsPermissiveConfiguration.qlref diff --git a/javascript/ql/lib/javascript.qll b/javascript/ql/lib/javascript.qll index 207336b1cca3..370655df72cc 100644 --- a/javascript/ql/lib/javascript.qll +++ b/javascript/ql/lib/javascript.qll @@ -71,7 +71,7 @@ import semmle.javascript.frameworks.ActionsLib import semmle.javascript.frameworks.Angular2 import semmle.javascript.frameworks.AngularJS import semmle.javascript.frameworks.Anser -import semmle.javascript.frameworks.ApolloGraphQL +import semmle.javascript.frameworks.Apollo import semmle.javascript.frameworks.AsyncPackage import semmle.javascript.frameworks.AWS import semmle.javascript.frameworks.Azure diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll b/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll new file mode 100644 index 000000000000..8c09cca9124d --- /dev/null +++ b/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll @@ -0,0 +1,36 @@ +/** + * Provides classes for working with Apollo GraphQL connectors. + */ + +import javascript + +/** Provides classes modeling the apollo packages [@apollo/server](https://npmjs.com/package/@apollo/server`) */ +module Apollo { + /** Get an instanceof of `Apollo` */ + private API::Node apollo() { + result = + API::moduleImport([ + "@apollo/server", "@apollo/apollo-server-express", "@apollo/apollo-server-core", + "apollo-server", "apollo-server-express" + ]).getMember("ApolloServer") + } + + /** Get an instanceof of the `gql` function that parses GraphQL strings. */ + private API::Node gql() { + result = + API::moduleImport([ + "@apollo/server", "@apollo/apollo-server-express", "@apollo/apollo-server-core", + "apollo-server", "apollo-server-express" + ]).getMember("gql") + } + + /** A string that is interpreted as a GraphQL query by a `graphql` package. */ + class ApolloServer extends API::NewNode { + ApolloServer() { this = apollo().getAnInstantiation() } + } + + /** A string that is interpreted as a GraphQL query by a `apollo` package. */ + class ApolloGraphQLString extends GraphQL::GraphQLString { + ApolloGraphQLString() { this = gql().getACall().getArgument(0) } + } +} diff --git a/javascript/ql/lib/semmle/javascript/frameworks/ApolloGraphQL.qll b/javascript/ql/lib/semmle/javascript/frameworks/ApolloGraphQL.qll deleted file mode 100644 index 9dea34df3b0a..000000000000 --- a/javascript/ql/lib/semmle/javascript/frameworks/ApolloGraphQL.qll +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Provides classes for working with Apollo GraphQL connectors. - */ - -import javascript - -/** Provides classes modeling concepts of Apollo GraphQL. */ -module ApolloGraphQL { - /** A string-valued expression that is interpreted as a Apollo GraphQL query. */ - abstract class GraphQLString extends DataFlow::Node { } - - /** A string-valued expression that is interpreted as a Apollo GraphQL query. */ - abstract class ApolloGraphQLServer extends DataFlow::Node { } -} - -/** - * Provides classes modeling the apollo packages [@apollo/server](https://npmjs.com/package/@apollo/server`) - */ -private module Apollo { - /** Get an instanceof of `Apollo` */ - private API::Node apollo() { - result = - API::moduleImport([ - "@apollo/server", "apollo/server", "@apollo/apollo-server-express", - "@apollo/apollo-server-core", "apollo-server", "apollo-server-express" - ]).getMember("ApolloServer") - } - - /** Get an instanceof of `gql` */ - private API::Node gql() { - result = - API::moduleImport([ - "@apollo/server", "apollo/server", "@apollo/apollo-server-express", - "@apollo/apollo-server-core", "apollo-server", "apollo-server-express" - ]).getMember("gql") - } - - /** A string that is interpreted as a GraphQL query by a `octokit` package. */ - private class ApolloGraphQLString extends GraphQL::GraphQLString { - ApolloGraphQLString() { this = gql().getACall() } - } - - /** A string that is interpreted as a GraphQL query by a `graphql` package. */ - private class ApolloServer extends ApolloGraphQL::ApolloGraphQLServer { - ApolloServer() { this = apollo().getAnInstantiation() } - - predicate isPermissive() { - this.(DataFlow::NewNode) - .getOptionArgument(0, "cors") - .getALocalSource() - .getAPropertyWrite("origin") - .getRhs() - .mayHaveBooleanValue(true) - } - } -} diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll index dc87acc8a1da..0f56bea4347e 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll @@ -27,8 +27,8 @@ module CorsPermissiveConfiguration { RemoteFlowSourceAsSource() { not this instanceof ClientSideRemoteFlowSource } } - /** true and null are considered bad values */ - class BadValues extends Source instanceof DataFlow::Node { + /** An overfly permissive value for `origin` */ + class BadValues extends Source { BadValues() { this.mayHaveBooleanValue(true) or this.asExpr() instanceof NullLiteral } } @@ -37,13 +37,9 @@ module CorsPermissiveConfiguration { */ class CorsApolloServer extends Sink, DataFlow::ValueNode { CorsApolloServer() { - exists(ApolloGraphQL::ApolloGraphQLServer agql | + exists(Apollo::ApolloServer agql | this = - agql.(DataFlow::NewNode) - .getOptionArgument(0, "cors") - .getALocalSource() - .getAPropertyWrite("origin") - .getRhs() + agql.getOptionArgument(0, "cors").getALocalSource().getAPropertyWrite("origin").getRhs() ) } } diff --git a/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfiguration.qhelp b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfiguration.qhelp new file mode 100644 index 000000000000..fc79eee743bf --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfiguration.qhelp @@ -0,0 +1,71 @@ + + + + +

+ + A server can use CORS (Cross-Origin Resource Sharing) to relax the + restrictions imposed by the SOP (Same-Origin Policy), allowing controlled, secure + cross-origin requests when necessary. + + A server with an overly permissive CORS configuration may inadvertently + expose sensitive data or lead to CSRF which is an attack that allows attackers to trick + users into performing unwanted operations in websites they're authenticated to. + +

+ +
+ + +

+ + When the origin is set to true, it signifies that the server + is accepting requests from any origin, potentially exposing the system to + CSRF attacks. This can be fixed using false as origin value or using a whitelist. + +

+

+ + On the other hand, if the origin is + set to null, it can be exploited by an attacker to deceive a user into making + requests from a null origin form, often hosted within a sandboxed iframe. + +

+ +

+ + If the origin value is user controlled, make sure that the data + is properly sanitized. + +

+
+ + +

+ + In the example below, the server_1 accepts requests from any origin + since the value of origin is set to true. + And server_2's origin is user-controlled. + +

+ + + +

+ + In the example below, the server_1 CORS is restrictive so it's not + vulnerable to CSRF attacks. And server_2's is using properly sanitized + user-controlled data. + +

+ + +
+ + +
  • Mozilla Developer Network: CORS, Access-Control-Allow-Origin.
  • +
  • W3C: CORS for developers, Advice for Resource Owners
  • +
    +
    diff --git a/javascript/ql/src/Security/CWE-942/CorsPermissiveConfiguration.ql b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfiguration.ql similarity index 76% rename from javascript/ql/src/Security/CWE-942/CorsPermissiveConfiguration.ql rename to javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfiguration.ql index 1cb01c9fe1c6..7655b6dda8d4 100644 --- a/javascript/ql/src/Security/CWE-942/CorsPermissiveConfiguration.ql +++ b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfiguration.ql @@ -16,5 +16,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasFlowPath(source, sink) -select sink.getNode(), source, sink, "$@ misconfiguration due to a $@.", sink.getNode(), - "CORS Origin", source.getNode(), "too permissive or user controlled value" +select sink.getNode(), source, sink, "CORS Origin misconfiguration due to a $@.", source.getNode(), + "too permissive or user controlled value" diff --git a/javascript/ql/src/experimental/Security/CWE-942/examples/CorsPermissiveConfigurationBad.js b/javascript/ql/src/experimental/Security/CWE-942/examples/CorsPermissiveConfigurationBad.js new file mode 100644 index 000000000000..68317486a99d --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-942/examples/CorsPermissiveConfigurationBad.js @@ -0,0 +1,18 @@ +import { ApolloServer } from 'apollo-server'; +var https = require('https'), + url = require('url'); + +var server = https.createServer(function () { }); + +server.on('request', function (req, res) { + // BAD: origin is too permissive + const server_1 = new ApolloServer({ + cors: { origin: true } + }); + + let user_origin = url.parse(req.url, true).query.origin; + // BAD: CORS is controlled by user + const server_2 = new ApolloServer({ + cors: { origin: user_origin } + }); +}); \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-942/examples/CorsPermissiveConfigurationGood.js b/javascript/ql/src/experimental/Security/CWE-942/examples/CorsPermissiveConfigurationGood.js new file mode 100644 index 000000000000..5e084d089b75 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-942/examples/CorsPermissiveConfigurationGood.js @@ -0,0 +1,18 @@ +import { ApolloServer } from 'apollo-server'; +var https = require('https'), + url = require('url'); + +var server = https.createServer(function () { }); + +server.on('request', function (req, res) { + // GOOD: origin is restrictive + const server_1 = new ApolloServer({ + cors: { origin: false } + }); + + let user_origin = url.parse(req.url, true).query.origin; + // GOOD: user data is properly sanitized + const server_2 = new ApolloServer({ + cors: { origin: (user_origin === "https://allowed1.com" || user_origin === "https://allowed2.com") ? user_origin : false } + }); +}); \ No newline at end of file diff --git a/javascript/ql/test/experimental/Security/CWE-942/CorsPermissiveConfiguration.expected b/javascript/ql/test/experimental/Security/CWE-942/CorsPermissiveConfiguration.expected new file mode 100644 index 000000000000..f6571bd7e87b --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-942/CorsPermissiveConfiguration.expected @@ -0,0 +1,34 @@ +nodes +| tst.js:8:9:8:59 | user_origin | +| tst.js:8:23:8:46 | url.par ... , true) | +| tst.js:8:23:8:52 | url.par ... ).query | +| tst.js:8:23:8:59 | url.par ... .origin | +| tst.js:8:33:8:39 | req.url | +| tst.js:8:33:8:39 | req.url | +| tst.js:8:42:8:45 | true | +| tst.js:8:42:8:45 | true | +| tst.js:11:25:11:28 | true | +| tst.js:11:25:11:28 | true | +| tst.js:11:25:11:28 | true | +| tst.js:21:25:21:28 | null | +| tst.js:21:25:21:28 | null | +| tst.js:21:25:21:28 | null | +| tst.js:26:25:26:35 | user_origin | +| tst.js:26:25:26:35 | user_origin | +edges +| tst.js:8:9:8:59 | user_origin | tst.js:26:25:26:35 | user_origin | +| tst.js:8:9:8:59 | user_origin | tst.js:26:25:26:35 | user_origin | +| tst.js:8:23:8:46 | url.par ... , true) | tst.js:8:23:8:52 | url.par ... ).query | +| tst.js:8:23:8:52 | url.par ... ).query | tst.js:8:23:8:59 | url.par ... .origin | +| tst.js:8:23:8:59 | url.par ... .origin | tst.js:8:9:8:59 | user_origin | +| tst.js:8:33:8:39 | req.url | tst.js:8:23:8:46 | url.par ... , true) | +| tst.js:8:33:8:39 | req.url | tst.js:8:23:8:46 | url.par ... , true) | +| tst.js:8:42:8:45 | true | tst.js:8:23:8:46 | url.par ... , true) | +| tst.js:8:42:8:45 | true | tst.js:8:23:8:46 | url.par ... , true) | +| tst.js:11:25:11:28 | true | tst.js:11:25:11:28 | true | +| tst.js:21:25:21:28 | null | tst.js:21:25:21:28 | null | +#select +| tst.js:11:25:11:28 | true | tst.js:11:25:11:28 | true | tst.js:11:25:11:28 | true | CORS Origin misconfiguration due to a $@. | tst.js:11:25:11:28 | true | too permissive or user controlled value | +| tst.js:21:25:21:28 | null | tst.js:21:25:21:28 | null | tst.js:21:25:21:28 | null | CORS Origin misconfiguration due to a $@. | tst.js:21:25:21:28 | null | too permissive or user controlled value | +| tst.js:26:25:26:35 | user_origin | tst.js:8:33:8:39 | req.url | tst.js:26:25:26:35 | user_origin | CORS Origin misconfiguration due to a $@. | tst.js:8:33:8:39 | req.url | too permissive or user controlled value | +| tst.js:26:25:26:35 | user_origin | tst.js:8:42:8:45 | true | tst.js:26:25:26:35 | user_origin | CORS Origin misconfiguration due to a $@. | tst.js:8:42:8:45 | true | too permissive or user controlled value | diff --git a/javascript/ql/test/experimental/Security/CWE-942/CorsPermissiveConfiguration.qlref b/javascript/ql/test/experimental/Security/CWE-942/CorsPermissiveConfiguration.qlref new file mode 100644 index 000000000000..1e6a39679c0d --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-942/CorsPermissiveConfiguration.qlref @@ -0,0 +1 @@ +./experimental/Security/CWE-942/CorsPermissiveConfiguration.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-942/tst.js b/javascript/ql/test/experimental/Security/CWE-942/tst.js similarity index 80% rename from javascript/ql/test/query-tests/Security/CWE-942/tst.js rename to javascript/ql/test/experimental/Security/CWE-942/tst.js index 60040e965372..f55d5dc2c3ec 100644 --- a/javascript/ql/test/query-tests/Security/CWE-942/tst.js +++ b/javascript/ql/test/experimental/Security/CWE-942/tst.js @@ -6,28 +6,23 @@ var server = https.createServer(function () { }); server.on('request', function (req, res) { let user_origin = url.parse(req.url, true).query.origin; - // BAD: attacker can choose the value of origin + // BAD: CORS too permissive const server_1 = new ApolloServer({ cors: { origin: true } }); - // BAD: CORS too permissive - const server_2 = new ApolloServer({ - cors: { origin: true } - }); - // GOOD: restrictive CORS - const server_3 = new ApolloServer({ + const server_2 = new ApolloServer({ cors: false }); // BAD: CORS too permissive - const server_4 = new ApolloServer({ + const server_3 = new ApolloServer({ cors: { origin: null } }); // BAD: CORS is controlled by user - const server_5 = new ApolloServer({ + const server_4 = new ApolloServer({ cors: { origin: user_origin } }); }); \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-942/CorsPermissiveConfiguration.expected b/javascript/ql/test/query-tests/Security/CWE-942/CorsPermissiveConfiguration.expected deleted file mode 100644 index 7862049eeed6..000000000000 --- a/javascript/ql/test/query-tests/Security/CWE-942/CorsPermissiveConfiguration.expected +++ /dev/null @@ -1,39 +0,0 @@ -nodes -| tst.js:8:9:8:59 | user_origin | -| tst.js:8:23:8:46 | url.par ... , true) | -| tst.js:8:23:8:52 | url.par ... ).query | -| tst.js:8:23:8:59 | url.par ... .origin | -| tst.js:8:33:8:39 | req.url | -| tst.js:8:33:8:39 | req.url | -| tst.js:8:42:8:45 | true | -| tst.js:8:42:8:45 | true | -| tst.js:11:25:11:28 | true | -| tst.js:11:25:11:28 | true | -| tst.js:11:25:11:28 | true | -| tst.js:16:25:16:28 | true | -| tst.js:16:25:16:28 | true | -| tst.js:16:25:16:28 | true | -| tst.js:26:25:26:28 | null | -| tst.js:26:25:26:28 | null | -| tst.js:26:25:26:28 | null | -| tst.js:31:25:31:35 | user_origin | -| tst.js:31:25:31:35 | user_origin | -edges -| tst.js:8:9:8:59 | user_origin | tst.js:31:25:31:35 | user_origin | -| tst.js:8:9:8:59 | user_origin | tst.js:31:25:31:35 | user_origin | -| tst.js:8:23:8:46 | url.par ... , true) | tst.js:8:23:8:52 | url.par ... ).query | -| tst.js:8:23:8:52 | url.par ... ).query | tst.js:8:23:8:59 | url.par ... .origin | -| tst.js:8:23:8:59 | url.par ... .origin | tst.js:8:9:8:59 | user_origin | -| tst.js:8:33:8:39 | req.url | tst.js:8:23:8:46 | url.par ... , true) | -| tst.js:8:33:8:39 | req.url | tst.js:8:23:8:46 | url.par ... , true) | -| tst.js:8:42:8:45 | true | tst.js:8:23:8:46 | url.par ... , true) | -| tst.js:8:42:8:45 | true | tst.js:8:23:8:46 | url.par ... , true) | -| tst.js:11:25:11:28 | true | tst.js:11:25:11:28 | true | -| tst.js:16:25:16:28 | true | tst.js:16:25:16:28 | true | -| tst.js:26:25:26:28 | null | tst.js:26:25:26:28 | null | -#select -| tst.js:11:25:11:28 | true | tst.js:11:25:11:28 | true | tst.js:11:25:11:28 | true | $@ misconfiguration due to a $@. | tst.js:11:25:11:28 | true | CORS Origin | tst.js:11:25:11:28 | true | too permissive or user controlled value | -| tst.js:16:25:16:28 | true | tst.js:16:25:16:28 | true | tst.js:16:25:16:28 | true | $@ misconfiguration due to a $@. | tst.js:16:25:16:28 | true | CORS Origin | tst.js:16:25:16:28 | true | too permissive or user controlled value | -| tst.js:26:25:26:28 | null | tst.js:26:25:26:28 | null | tst.js:26:25:26:28 | null | $@ misconfiguration due to a $@. | tst.js:26:25:26:28 | null | CORS Origin | tst.js:26:25:26:28 | null | too permissive or user controlled value | -| tst.js:31:25:31:35 | user_origin | tst.js:8:33:8:39 | req.url | tst.js:31:25:31:35 | user_origin | $@ misconfiguration due to a $@. | tst.js:31:25:31:35 | user_origin | CORS Origin | tst.js:8:33:8:39 | req.url | too permissive or user controlled value | -| tst.js:31:25:31:35 | user_origin | tst.js:8:42:8:45 | true | tst.js:31:25:31:35 | user_origin | $@ misconfiguration due to a $@. | tst.js:31:25:31:35 | user_origin | CORS Origin | tst.js:8:42:8:45 | true | too permissive or user controlled value | diff --git a/javascript/ql/test/query-tests/Security/CWE-942/CorsPermissiveConfiguration.qlref b/javascript/ql/test/query-tests/Security/CWE-942/CorsPermissiveConfiguration.qlref deleted file mode 100644 index f8adf3cd38e6..000000000000 --- a/javascript/ql/test/query-tests/Security/CWE-942/CorsPermissiveConfiguration.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/CWE-942/CorsPermissiveConfiguration.ql From ed066281b92a00a7295f50656504e40878f86adf Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Fri, 6 Oct 2023 18:22:31 +0200 Subject: [PATCH 04/29] Add documentation string for `CorsPermissiveConfiguration` --- .../dataflow/CorsPermissiveConfigurationCustomizations.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll index 0f56bea4347e..14031e75a291 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll @@ -6,6 +6,7 @@ import javascript +/** Module containing sources, sinks, and sanitizers for overly permissive CORS configurations. */ module CorsPermissiveConfiguration { /** * A data flow source for permissive CORS configuration. From 07ad596f7759ab104e2cfdfbc6dfd07c9905ecdf Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Mon, 16 Oct 2023 16:48:32 +0200 Subject: [PATCH 05/29] Add coverage for `express` --- .../lib/semmle/javascript/frameworks/Cors.qll | 24 +++++++++++++ .../semmle/javascript/frameworks/Express.qll | 20 +++++++++++ ...sPermissiveConfigurationCustomizations.qll | 7 ++++ .../CWE-942/{tst.js => apollo-test.js} | 0 .../Security/CWE-942/express-test | 36 +++++++++++++++++++ 5 files changed, 87 insertions(+) create mode 100644 javascript/ql/lib/semmle/javascript/frameworks/Cors.qll rename javascript/ql/test/experimental/Security/CWE-942/{tst.js => apollo-test.js} (100%) create mode 100644 javascript/ql/test/experimental/Security/CWE-942/express-test diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll b/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll new file mode 100644 index 000000000000..57ec67b1f387 --- /dev/null +++ b/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll @@ -0,0 +1,24 @@ +/** + * Provides classes for working with Cors connectors. + */ + +import javascript + +/** Provides classes modeling [cors package](https://npmjs.com/package/cors) */ +module Cors { + class Cors extends DataFlow::CallNode { + /** Get an instanceof of `cors` */ + Cors() { this = DataFlow::moduleImport("cors").getAnInvocation() } + + /** Get Cors configuration */ + DataFlow::Node getCorsArgument() { result = this.getArgument(0) } + + /** Holds if cors is using default configuration */ + predicate isDefault() { this.getNumArgument() = 0 } + + /** The value of origin */ + DataFlow::Node getOrigin() { + result = this.getCorsArgument().getALocalSource().getAPropertyWrite("origin").getRhs() + } + } +} diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index c39d19d4375c..dadebb314851 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -5,6 +5,7 @@ import javascript import semmle.javascript.frameworks.HTTP import semmle.javascript.frameworks.ExpressModules +import semmle.javascript.frameworks.Cors private import semmle.javascript.dataflow.InferredTypes private import semmle.javascript.frameworks.ConnectExpressShared::ConnectExpressShared @@ -1071,4 +1072,23 @@ module Express { override predicate definitelyResumesDispatch() { none() } } + + class CorsConfiguration extends DataFlow::MethodCallNode { + /** Get an `app.use` with a cors object as argument */ + CorsConfiguration() { + this = appCreation().getAMethodCall("use") and this.getArgument(0) instanceof Cors::Cors + } + + /** Get Cors */ + private Cors::Cors cors() { result = this.getArgument(0).(Cors::Cors) } + + /** Get Cors configuration */ + DataFlow::Node getCorsArgument() { result = cors().getCorsArgument() } + + /** Holds if cors is using default configuration */ + predicate isDefault() { cors().isDefault() } + + /** Get Cors origin value */ + DataFlow::Node getOrigin() { result = cors().getOrigin() } + } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll index 14031e75a291..a05573ece74c 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll @@ -44,4 +44,11 @@ module CorsPermissiveConfiguration { ) } } + + /** + * The value of cors origin when initializing the application. + */ + class ExpressCors extends Sink, DataFlow::ValueNode { + ExpressCors() { exists(Express::CorsConfiguration config | this = config.getOrigin()) } + } } diff --git a/javascript/ql/test/experimental/Security/CWE-942/tst.js b/javascript/ql/test/experimental/Security/CWE-942/apollo-test.js similarity index 100% rename from javascript/ql/test/experimental/Security/CWE-942/tst.js rename to javascript/ql/test/experimental/Security/CWE-942/apollo-test.js diff --git a/javascript/ql/test/experimental/Security/CWE-942/express-test b/javascript/ql/test/experimental/Security/CWE-942/express-test new file mode 100644 index 000000000000..3ad31a6a31a8 --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-942/express-test @@ -0,0 +1,36 @@ +const cors = require('cors'); +var express = require('express'); + +var https = require('https'), + url = require('url'); + +var server = https.createServer(function () { }); + +server.on('request', function (req, res) { + let user_origin = url.parse(req.url, true).query.origin; + + // BAD: CORS too permissive, default value is * + var app1 = express(); + app1.use(cors()); + + // GOOD: restrictive CORS + var app2 = express(); + var corsOptions2 = { + origin: ["https://example1.com", "https://example2.com"], + }; + app2.use(cors(corsOptions2)); + + // BAD: CORS too permissive + var app3 = express(); + var corsOption3 = { + origin: '*' + }; + app3.use(cors(corsOption3)); + + // BAD: CORS is controlled by user + var app4 = express(); + var corsOption4 = { + origin: user_origin + }; + app4.use(cors(corsOption4)); +}); \ No newline at end of file From acac534ed094ace3f49b74b0a9eea686d1787181 Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Mon, 16 Oct 2023 19:29:57 +0200 Subject: [PATCH 06/29] Forgot `.js` --- .../Security/CWE-942/{express-test => express-test.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename javascript/ql/test/experimental/Security/CWE-942/{express-test => express-test.js} (100%) diff --git a/javascript/ql/test/experimental/Security/CWE-942/express-test b/javascript/ql/test/experimental/Security/CWE-942/express-test.js similarity index 100% rename from javascript/ql/test/experimental/Security/CWE-942/express-test rename to javascript/ql/test/experimental/Security/CWE-942/express-test.js From d661f7f4827353c6d36312b272b8418ed3c15d3b Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Wed, 22 Nov 2023 19:50:16 +0100 Subject: [PATCH 07/29] Add Flow Labels --- ...sPermissiveConfigurationCustomizations.qll | 25 +++++- .../CorsPermissiveConfigurationQuery.qll | 22 +++++- .../CorsPermissiveConfiguration.expected | 78 +++++++++++-------- 3 files changed, 89 insertions(+), 36 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll index a05573ece74c..7f376cae4f2b 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll @@ -28,9 +28,28 @@ module CorsPermissiveConfiguration { RemoteFlowSourceAsSource() { not this instanceof ClientSideRemoteFlowSource } } - /** An overfly permissive value for `origin` */ - class BadValues extends Source { - BadValues() { this.mayHaveBooleanValue(true) or this.asExpr() instanceof NullLiteral } + /** A flow label representing `true` and `null` values. */ + abstract class TrueAndNull extends DataFlow::FlowLabel { + TrueAndNull() { this = "TrueAndNull" } + } + + TrueAndNull truenullLabel() { any() } + + /** A flow label representing `*` value. */ + abstract class Wildcard extends DataFlow::FlowLabel { + Wildcard() { this = "Wildcard" } + } + + Wildcard wildcardLabel() { any() } + + /** An overly permissive value for `origin` (Apollo) */ + class TrueNullValue extends Source { + TrueNullValue() { this.mayHaveBooleanValue(true) or this.asExpr() instanceof NullLiteral } + } + + /** An overly permissive value for `origin` (Express) */ + class WildcardValue extends Source { + WildcardValue() { this.mayHaveStringValue("*") } } /** diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationQuery.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationQuery.qll index bc39328409f5..4d56365aafe7 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationQuery.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationQuery.qll @@ -17,12 +17,30 @@ import CorsPermissiveConfigurationCustomizations::CorsPermissiveConfiguration class Configuration extends TaintTracking::Configuration { Configuration() { this = "CorsPermissiveConfiguration" } - override predicate isSource(DataFlow::Node source) { source instanceof Source } + override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) { + source instanceof TrueNullValue and label = truenullLabel() + or + source instanceof WildcardValue and label = wildcardLabel() + or + source instanceof RemoteFlowSource and label = DataFlow::FlowLabel::taint() + } - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) { + sink instanceof CorsApolloServer and label = [DataFlow::FlowLabel::taint(), truenullLabel()] + or + sink instanceof ExpressCors and label = [DataFlow::FlowLabel::taint(), wildcardLabel()] + } override predicate isSanitizer(DataFlow::Node node) { super.isSanitizer(node) or node instanceof Sanitizer } } + +private class WildcardActivated extends DataFlow::FlowLabel, Wildcard { + WildcardActivated() { this = this } +} + +private class TrueAndNullActivated extends DataFlow::FlowLabel, TrueAndNull { + TrueAndNullActivated() { this = this } +} diff --git a/javascript/ql/test/experimental/Security/CWE-942/CorsPermissiveConfiguration.expected b/javascript/ql/test/experimental/Security/CWE-942/CorsPermissiveConfiguration.expected index f6571bd7e87b..965fc4c722b4 100644 --- a/javascript/ql/test/experimental/Security/CWE-942/CorsPermissiveConfiguration.expected +++ b/javascript/ql/test/experimental/Security/CWE-942/CorsPermissiveConfiguration.expected @@ -1,34 +1,50 @@ nodes -| tst.js:8:9:8:59 | user_origin | -| tst.js:8:23:8:46 | url.par ... , true) | -| tst.js:8:23:8:52 | url.par ... ).query | -| tst.js:8:23:8:59 | url.par ... .origin | -| tst.js:8:33:8:39 | req.url | -| tst.js:8:33:8:39 | req.url | -| tst.js:8:42:8:45 | true | -| tst.js:8:42:8:45 | true | -| tst.js:11:25:11:28 | true | -| tst.js:11:25:11:28 | true | -| tst.js:11:25:11:28 | true | -| tst.js:21:25:21:28 | null | -| tst.js:21:25:21:28 | null | -| tst.js:21:25:21:28 | null | -| tst.js:26:25:26:35 | user_origin | -| tst.js:26:25:26:35 | user_origin | +| apollo-test.js:8:9:8:59 | user_origin | +| apollo-test.js:8:23:8:46 | url.par ... , true) | +| apollo-test.js:8:23:8:52 | url.par ... ).query | +| apollo-test.js:8:23:8:59 | url.par ... .origin | +| apollo-test.js:8:33:8:39 | req.url | +| apollo-test.js:8:33:8:39 | req.url | +| apollo-test.js:11:25:11:28 | true | +| apollo-test.js:11:25:11:28 | true | +| apollo-test.js:11:25:11:28 | true | +| apollo-test.js:21:25:21:28 | null | +| apollo-test.js:21:25:21:28 | null | +| apollo-test.js:21:25:21:28 | null | +| apollo-test.js:26:25:26:35 | user_origin | +| apollo-test.js:26:25:26:35 | user_origin | +| express-test.js:10:9:10:59 | user_origin | +| express-test.js:10:23:10:46 | url.par ... , true) | +| express-test.js:10:23:10:52 | url.par ... ).query | +| express-test.js:10:23:10:59 | url.par ... .origin | +| express-test.js:10:33:10:39 | req.url | +| express-test.js:10:33:10:39 | req.url | +| express-test.js:26:17:26:19 | '*' | +| express-test.js:26:17:26:19 | '*' | +| express-test.js:26:17:26:19 | '*' | +| express-test.js:33:17:33:27 | user_origin | +| express-test.js:33:17:33:27 | user_origin | edges -| tst.js:8:9:8:59 | user_origin | tst.js:26:25:26:35 | user_origin | -| tst.js:8:9:8:59 | user_origin | tst.js:26:25:26:35 | user_origin | -| tst.js:8:23:8:46 | url.par ... , true) | tst.js:8:23:8:52 | url.par ... ).query | -| tst.js:8:23:8:52 | url.par ... ).query | tst.js:8:23:8:59 | url.par ... .origin | -| tst.js:8:23:8:59 | url.par ... .origin | tst.js:8:9:8:59 | user_origin | -| tst.js:8:33:8:39 | req.url | tst.js:8:23:8:46 | url.par ... , true) | -| tst.js:8:33:8:39 | req.url | tst.js:8:23:8:46 | url.par ... , true) | -| tst.js:8:42:8:45 | true | tst.js:8:23:8:46 | url.par ... , true) | -| tst.js:8:42:8:45 | true | tst.js:8:23:8:46 | url.par ... , true) | -| tst.js:11:25:11:28 | true | tst.js:11:25:11:28 | true | -| tst.js:21:25:21:28 | null | tst.js:21:25:21:28 | null | +| apollo-test.js:8:9:8:59 | user_origin | apollo-test.js:26:25:26:35 | user_origin | +| apollo-test.js:8:9:8:59 | user_origin | apollo-test.js:26:25:26:35 | user_origin | +| apollo-test.js:8:23:8:46 | url.par ... , true) | apollo-test.js:8:23:8:52 | url.par ... ).query | +| apollo-test.js:8:23:8:52 | url.par ... ).query | apollo-test.js:8:23:8:59 | url.par ... .origin | +| apollo-test.js:8:23:8:59 | url.par ... .origin | apollo-test.js:8:9:8:59 | user_origin | +| apollo-test.js:8:33:8:39 | req.url | apollo-test.js:8:23:8:46 | url.par ... , true) | +| apollo-test.js:8:33:8:39 | req.url | apollo-test.js:8:23:8:46 | url.par ... , true) | +| apollo-test.js:11:25:11:28 | true | apollo-test.js:11:25:11:28 | true | +| apollo-test.js:21:25:21:28 | null | apollo-test.js:21:25:21:28 | null | +| express-test.js:10:9:10:59 | user_origin | express-test.js:33:17:33:27 | user_origin | +| express-test.js:10:9:10:59 | user_origin | express-test.js:33:17:33:27 | user_origin | +| express-test.js:10:23:10:46 | url.par ... , true) | express-test.js:10:23:10:52 | url.par ... ).query | +| express-test.js:10:23:10:52 | url.par ... ).query | express-test.js:10:23:10:59 | url.par ... .origin | +| express-test.js:10:23:10:59 | url.par ... .origin | express-test.js:10:9:10:59 | user_origin | +| express-test.js:10:33:10:39 | req.url | express-test.js:10:23:10:46 | url.par ... , true) | +| express-test.js:10:33:10:39 | req.url | express-test.js:10:23:10:46 | url.par ... , true) | +| express-test.js:26:17:26:19 | '*' | express-test.js:26:17:26:19 | '*' | #select -| tst.js:11:25:11:28 | true | tst.js:11:25:11:28 | true | tst.js:11:25:11:28 | true | CORS Origin misconfiguration due to a $@. | tst.js:11:25:11:28 | true | too permissive or user controlled value | -| tst.js:21:25:21:28 | null | tst.js:21:25:21:28 | null | tst.js:21:25:21:28 | null | CORS Origin misconfiguration due to a $@. | tst.js:21:25:21:28 | null | too permissive or user controlled value | -| tst.js:26:25:26:35 | user_origin | tst.js:8:33:8:39 | req.url | tst.js:26:25:26:35 | user_origin | CORS Origin misconfiguration due to a $@. | tst.js:8:33:8:39 | req.url | too permissive or user controlled value | -| tst.js:26:25:26:35 | user_origin | tst.js:8:42:8:45 | true | tst.js:26:25:26:35 | user_origin | CORS Origin misconfiguration due to a $@. | tst.js:8:42:8:45 | true | too permissive or user controlled value | +| apollo-test.js:11:25:11:28 | true | apollo-test.js:11:25:11:28 | true | apollo-test.js:11:25:11:28 | true | CORS Origin misconfiguration due to a $@. | apollo-test.js:11:25:11:28 | true | too permissive or user controlled value | +| apollo-test.js:21:25:21:28 | null | apollo-test.js:21:25:21:28 | null | apollo-test.js:21:25:21:28 | null | CORS Origin misconfiguration due to a $@. | apollo-test.js:21:25:21:28 | null | too permissive or user controlled value | +| apollo-test.js:26:25:26:35 | user_origin | apollo-test.js:8:33:8:39 | req.url | apollo-test.js:26:25:26:35 | user_origin | CORS Origin misconfiguration due to a $@. | apollo-test.js:8:33:8:39 | req.url | too permissive or user controlled value | +| express-test.js:26:17:26:19 | '*' | express-test.js:26:17:26:19 | '*' | express-test.js:26:17:26:19 | '*' | CORS Origin misconfiguration due to a $@. | express-test.js:26:17:26:19 | '*' | too permissive or user controlled value | +| express-test.js:33:17:33:27 | user_origin | express-test.js:10:33:10:39 | req.url | express-test.js:33:17:33:27 | user_origin | CORS Origin misconfiguration due to a $@. | express-test.js:10:33:10:39 | req.url | too permissive or user controlled value | From 413c11171ea6b64b4a600c92717ef81c54df2c6b Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Thu, 23 Nov 2023 11:00:47 +0100 Subject: [PATCH 08/29] Move to `/experimental` --- .../CorsPermissiveConfigurationCustomizations.qll | 0 .../CorsPermissiveConfigurationQuery.qll | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename javascript/ql/{lib/semmle/javascript/security/dataflow => experimental}/CorsPermissiveConfigurationCustomizations.qll (100%) rename javascript/ql/{lib/semmle/javascript/security/dataflow => experimental}/CorsPermissiveConfigurationQuery.qll (100%) diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll b/javascript/ql/experimental/CorsPermissiveConfigurationCustomizations.qll similarity index 100% rename from javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll rename to javascript/ql/experimental/CorsPermissiveConfigurationCustomizations.qll diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationQuery.qll b/javascript/ql/experimental/CorsPermissiveConfigurationQuery.qll similarity index 100% rename from javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationQuery.qll rename to javascript/ql/experimental/CorsPermissiveConfigurationQuery.qll From abd53e98a9b8fcee62fc06b85f493ba8ef6fb543 Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Thu, 23 Nov 2023 13:17:54 +0100 Subject: [PATCH 09/29] Fix minor issues --- .../ql/lib/semmle/javascript/frameworks/Cors.qll | 5 ++++- .../ql/lib/semmle/javascript/frameworks/Express.qll | 12 ++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll b/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll index 57ec67b1f387..f9fa2f950dbe 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll @@ -6,6 +6,9 @@ import javascript /** Provides classes modeling [cors package](https://npmjs.com/package/cors) */ module Cors { + /** + * An expression that creates a new CORS configuration. + */ class Cors extends DataFlow::CallNode { /** Get an instanceof of `cors` */ Cors() { this = DataFlow::moduleImport("cors").getAnInvocation() } @@ -16,7 +19,7 @@ module Cors { /** Holds if cors is using default configuration */ predicate isDefault() { this.getNumArgument() = 0 } - /** The value of origin */ + /** Gets the value of origin */ DataFlow::Node getOrigin() { result = this.getCorsArgument().getALocalSource().getAPropertyWrite("origin").getRhs() } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index dadebb314851..0996e12e944a 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -1073,22 +1073,22 @@ module Express { override predicate definitelyResumesDispatch() { none() } } + /** + * The CORS configuration used in Express + */ class CorsConfiguration extends DataFlow::MethodCallNode { /** Get an `app.use` with a cors object as argument */ CorsConfiguration() { this = appCreation().getAMethodCall("use") and this.getArgument(0) instanceof Cors::Cors } - /** Get Cors */ - private Cors::Cors cors() { result = this.getArgument(0).(Cors::Cors) } - /** Get Cors configuration */ - DataFlow::Node getCorsArgument() { result = cors().getCorsArgument() } + DataFlow::Node getCorsArgument() { result = this.getArgument(0).(Cors::Cors).getCorsArgument() } /** Holds if cors is using default configuration */ - predicate isDefault() { cors().isDefault() } + predicate isDefault() { this.getArgument(0).(Cors::Cors).isDefault() } /** Get Cors origin value */ - DataFlow::Node getOrigin() { result = cors().getOrigin() } + DataFlow::Node getOrigin() { result = this.getArgument(0).(Cors::Cors).getOrigin() } } } From 4ef4c92e2ccda1ef6f1a1cc703ca415a2d3acbdf Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Thu, 23 Nov 2023 21:29:09 +0100 Subject: [PATCH 10/29] Move Customizations and Query --- .../Security/CWE-942/CorsPermissiveConfiguration.ql | 2 +- .../CWE-942}/CorsPermissiveConfigurationCustomizations.qll | 0 .../Security/CWE-942}/CorsPermissiveConfigurationQuery.qll | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename javascript/ql/{experimental => src/experimental/Security/CWE-942}/CorsPermissiveConfigurationCustomizations.qll (100%) rename javascript/ql/{experimental => src/experimental/Security/CWE-942}/CorsPermissiveConfigurationQuery.qll (100%) diff --git a/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfiguration.ql b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfiguration.ql index 7655b6dda8d4..e82d0e85ade5 100644 --- a/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfiguration.ql +++ b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfiguration.ql @@ -11,7 +11,7 @@ */ import javascript -import semmle.javascript.security.dataflow.CorsPermissiveConfigurationQuery +import CorsPermissiveConfigurationQuery import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink diff --git a/javascript/ql/experimental/CorsPermissiveConfigurationCustomizations.qll b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll similarity index 100% rename from javascript/ql/experimental/CorsPermissiveConfigurationCustomizations.qll rename to javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll diff --git a/javascript/ql/experimental/CorsPermissiveConfigurationQuery.qll b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationQuery.qll similarity index 100% rename from javascript/ql/experimental/CorsPermissiveConfigurationQuery.qll rename to javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationQuery.qll From aa24ce5532cbe2081303cc815df31fdd457db7c1 Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Mon, 27 Nov 2023 17:48:21 +0200 Subject: [PATCH 11/29] Apply suggestions from code review Co-authored-by: Erik Krogh Kristensen --- .../ql/lib/semmle/javascript/frameworks/Apollo.qll | 4 ++-- javascript/ql/lib/semmle/javascript/frameworks/Cors.qll | 9 ++++----- .../ql/lib/semmle/javascript/frameworks/Express.qll | 9 ++++----- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll b/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll index 8c09cca9124d..5d43c95a0858 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll @@ -6,7 +6,7 @@ import javascript /** Provides classes modeling the apollo packages [@apollo/server](https://npmjs.com/package/@apollo/server`) */ module Apollo { - /** Get an instanceof of `Apollo` */ + /** Get a reference to the `ApolloServer` class. */ private API::Node apollo() { result = API::moduleImport([ @@ -30,7 +30,7 @@ module Apollo { } /** A string that is interpreted as a GraphQL query by a `apollo` package. */ - class ApolloGraphQLString extends GraphQL::GraphQLString { + private class ApolloGraphQLString extends GraphQL::GraphQLString { ApolloGraphQLString() { this = gql().getACall().getArgument(0) } } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll b/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll index f9fa2f950dbe..8c4d7e836b9a 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll @@ -4,24 +4,23 @@ import javascript -/** Provides classes modeling [cors package](https://npmjs.com/package/cors) */ +/** Provides classes modeling [cors](https://npmjs.com/package/cors) library. */ module Cors { /** * An expression that creates a new CORS configuration. */ class Cors extends DataFlow::CallNode { - /** Get an instanceof of `cors` */ Cors() { this = DataFlow::moduleImport("cors").getAnInvocation() } - /** Get Cors configuration */ - DataFlow::Node getCorsArgument() { result = this.getArgument(0) } + /** Get the options used to configure Cors */ + DataFlow::Node getOptionsArgument() { result = this.getArgument(0) } /** Holds if cors is using default configuration */ predicate isDefault() { this.getNumArgument() = 0 } /** Gets the value of origin */ DataFlow::Node getOrigin() { - result = this.getCorsArgument().getALocalSource().getAPropertyWrite("origin").getRhs() + result = this.getOptionArgument(0, "origin") } } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 0996e12e944a..c94dfbbdeb6a 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -1074,21 +1074,20 @@ module Express { } /** - * The CORS configuration used in Express + * An express route setup configured with the `cors` package. */ class CorsConfiguration extends DataFlow::MethodCallNode { - /** Get an `app.use` with a cors object as argument */ CorsConfiguration() { this = appCreation().getAMethodCall("use") and this.getArgument(0) instanceof Cors::Cors } - /** Get Cors configuration */ + /** Gets the options used to configure `cors`. */ DataFlow::Node getCorsArgument() { result = this.getArgument(0).(Cors::Cors).getCorsArgument() } - /** Holds if cors is using default configuration */ + /** Holds if cors is using its default configuration. */ predicate isDefault() { this.getArgument(0).(Cors::Cors).isDefault() } - /** Get Cors origin value */ + /** Gets the `origin` option that the call to `cors` is configured with. */ DataFlow::Node getOrigin() { result = this.getArgument(0).(Cors::Cors).getOrigin() } } } From bb6ef72e6751f0222581d86371225ca32846abd1 Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Mon, 27 Nov 2023 19:36:49 +0200 Subject: [PATCH 12/29] `getArgument` returns `Cors::Cors` --- .../ql/lib/semmle/javascript/frameworks/Express.qll | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index c94dfbbdeb6a..d6cc1f7774a1 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -1081,13 +1081,15 @@ module Express { this = appCreation().getAMethodCall("use") and this.getArgument(0) instanceof Cors::Cors } + Cors::Cors getArgument() { result = this.getArgument(0) } + /** Gets the options used to configure `cors`. */ - DataFlow::Node getCorsArgument() { result = this.getArgument(0).(Cors::Cors).getCorsArgument() } + DataFlow::Node getCorsArgument() { result = this.getArgument().getOptionsArgument() } /** Holds if cors is using its default configuration. */ - predicate isDefault() { this.getArgument(0).(Cors::Cors).isDefault() } + predicate isDefault() { this.getArgument().isDefault() } /** Gets the `origin` option that the call to `cors` is configured with. */ - DataFlow::Node getOrigin() { result = this.getArgument(0).(Cors::Cors).getOrigin() } + DataFlow::Node getOrigin() { result = this.getArgument().getOrigin() } } } From f623db461aa6bf48ade85e4f9333dae9f48ec909 Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Mon, 27 Nov 2023 19:51:13 +0200 Subject: [PATCH 13/29] Change qldoc --- javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll b/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll index 5d43c95a0858..e8d249607ebe 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll @@ -15,7 +15,7 @@ module Apollo { ]).getMember("ApolloServer") } - /** Get an instanceof of the `gql` function that parses GraphQL strings. */ + /** Gets a reference to the `gql` function that parses GraphQL strings. */ private API::Node gql() { result = API::moduleImport([ From 3bcb411d1af77e7c7c89bc5b00a4bbf28efb006e Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Mon, 27 Nov 2023 20:31:19 +0200 Subject: [PATCH 14/29] Using `Express::RouteSetup` --- javascript/ql/lib/semmle/javascript/frameworks/Express.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index d6cc1f7774a1..0fdc7aa95aa4 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -1077,9 +1077,7 @@ module Express { * An express route setup configured with the `cors` package. */ class CorsConfiguration extends DataFlow::MethodCallNode { - CorsConfiguration() { - this = appCreation().getAMethodCall("use") and this.getArgument(0) instanceof Cors::Cors - } + CorsConfiguration() { exists(Express::RouteSetup setup | this = setup | setup.isUseCall()) } Cors::Cors getArgument() { result = this.getArgument(0) } From 6a3cdc90e27b3ff385f3e03a8aa6bcb642e53c6b Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Mon, 27 Nov 2023 20:58:47 +0200 Subject: [PATCH 15/29] Add `change-node` --- .../change-notes/2023-11-27-cors-permissive-configuarion.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 javascript/ql/lib/change-notes/2023-11-27-cors-permissive-configuarion.md diff --git a/javascript/ql/lib/change-notes/2023-11-27-cors-permissive-configuarion.md b/javascript/ql/lib/change-notes/2023-11-27-cors-permissive-configuarion.md new file mode 100644 index 000000000000..95af10659529 --- /dev/null +++ b/javascript/ql/lib/change-notes/2023-11-27-cors-permissive-configuarion.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added a new experimental query, `js/cors-misconfiguration` covering `cors` and `apollo`. \ No newline at end of file From e6c7fc0ead0533b146af9f2ef03715a458b7d32b Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Wed, 29 Nov 2023 19:45:08 +0200 Subject: [PATCH 16/29] Fixes CI --- javascript/ql/lib/semmle/javascript/frameworks/Cors.qll | 4 +--- javascript/ql/lib/semmle/javascript/frameworks/Express.qll | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll b/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll index 8c4d7e836b9a..90b5ada00755 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll @@ -19,8 +19,6 @@ module Cors { predicate isDefault() { this.getNumArgument() = 0 } /** Gets the value of origin */ - DataFlow::Node getOrigin() { - result = this.getOptionArgument(0, "origin") - } + DataFlow::Node getOrigin() { result = this.getOptionArgument(0, "origin") } } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 0fdc7aa95aa4..7b21137fe915 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -1079,6 +1079,7 @@ module Express { class CorsConfiguration extends DataFlow::MethodCallNode { CorsConfiguration() { exists(Express::RouteSetup setup | this = setup | setup.isUseCall()) } + /** Gets the cors argument */ Cors::Cors getArgument() { result = this.getArgument(0) } /** Gets the options used to configure `cors`. */ From 83cbbd70430de042d3ff4d340e69260359db3274 Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Tue, 5 Dec 2023 09:05:29 +0100 Subject: [PATCH 17/29] Apply docstring changes Co-authored-by: Erik Krogh Kristensen --- .../change-notes/2023-11-27-cors-permissive-configuarion.md | 2 +- javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll | 2 +- javascript/ql/lib/semmle/javascript/frameworks/Cors.qll | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/ql/lib/change-notes/2023-11-27-cors-permissive-configuarion.md b/javascript/ql/lib/change-notes/2023-11-27-cors-permissive-configuarion.md index 95af10659529..877a54a9d8e8 100644 --- a/javascript/ql/lib/change-notes/2023-11-27-cors-permissive-configuarion.md +++ b/javascript/ql/lib/change-notes/2023-11-27-cors-permissive-configuarion.md @@ -1,4 +1,4 @@ --- category: minorAnalysis --- -* Added a new experimental query, `js/cors-misconfiguration` covering `cors` and `apollo`. \ No newline at end of file +* Added a new experimental query, `js/cors-misconfiguration`, which detects misconfigured CORS HTTP headers in the `cors` and `apollo` libraries. \ No newline at end of file diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll b/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll index e8d249607ebe..59818d421086 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll @@ -24,7 +24,7 @@ module Apollo { ]).getMember("gql") } - /** A string that is interpreted as a GraphQL query by a `graphql` package. */ + /** An instantiation of an `ApolloServer`. */ class ApolloServer extends API::NewNode { ApolloServer() { this = apollo().getAnInstantiation() } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll b/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll index 90b5ada00755..cc190e6f4294 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll @@ -4,7 +4,7 @@ import javascript -/** Provides classes modeling [cors](https://npmjs.com/package/cors) library. */ +/** Provides classes modeling the [cors](https://npmjs.com/package/cors) library. */ module Cors { /** * An expression that creates a new CORS configuration. @@ -18,7 +18,7 @@ module Cors { /** Holds if cors is using default configuration */ predicate isDefault() { this.getNumArgument() = 0 } - /** Gets the value of origin */ + /** Gets the value of the `origin` option used to configure this Cors instance. */ DataFlow::Node getOrigin() { result = this.getOptionArgument(0, "origin") } } } From 87cac2a4e355d09c233ff1838b504026f156aaaa Mon Sep 17 00:00:00 2001 From: maikypedia Date: Thu, 7 Dec 2023 23:01:41 +0100 Subject: [PATCH 18/29] Express Argument has to be Cors --- .../ql/lib/semmle/javascript/frameworks/Express.qll | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 7b21137fe915..6956c7cbaa4c 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -1077,7 +1077,13 @@ module Express { * An express route setup configured with the `cors` package. */ class CorsConfiguration extends DataFlow::MethodCallNode { - CorsConfiguration() { exists(Express::RouteSetup setup | this = setup | setup.isUseCall()) } + CorsConfiguration() { + exists(Express::RouteSetup setup | this = setup | + setup.isUseCall() and setup.getArgument(0) instanceof Cors::Cors + or + not setup.isUseCall() and setup.getAnArgument() instanceof Cors::Cors + ) + } /** Gets the cors argument */ Cors::Cors getArgument() { result = this.getArgument(0) } From 4f68f60db203dbeb6631af42f767990159011571 Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Mon, 18 Dec 2023 12:37:05 +0100 Subject: [PATCH 19/29] Apply review Co-authored-by: Erik Krogh Kristensen --- .../semmle/javascript/frameworks/Express.qll | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 6956c7cbaa4c..062fb0419ee3 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -1077,24 +1077,17 @@ module Express { * An express route setup configured with the `cors` package. */ class CorsConfiguration extends DataFlow::MethodCallNode { + Cors::Cors corsConfig; + CorsConfiguration() { exists(Express::RouteSetup setup | this = setup | - setup.isUseCall() and setup.getArgument(0) instanceof Cors::Cors - or - not setup.isUseCall() and setup.getAnArgument() instanceof Cors::Cors + if setup.isUseCall() + then corsConfig = setup.getArgument(0) + else corsConfig = setup.getArgument(any(int i | i > 0)) ) } - /** Gets the cors argument */ - Cors::Cors getArgument() { result = this.getArgument(0) } - - /** Gets the options used to configure `cors`. */ - DataFlow::Node getCorsArgument() { result = this.getArgument().getOptionsArgument() } - - /** Holds if cors is using its default configuration. */ - predicate isDefault() { this.getArgument().isDefault() } - - /** Gets the `origin` option that the call to `cors` is configured with. */ - DataFlow::Node getOrigin() { result = this.getArgument().getOrigin() } + /** Gets the expression that configures `cors` on this route setup. */ + Cors::Cors getCorsConfiguration() { result = corsConfig } } } From 191766a47bf16653231f3dd843568d897878bdb2 Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Mon, 18 Dec 2023 12:38:39 +0100 Subject: [PATCH 20/29] Use `config.getCorsConfiguration().getOrigin())` Co-authored-by: Erik Krogh Kristensen --- .../CWE-942/CorsPermissiveConfigurationCustomizations.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll index 7f376cae4f2b..abeacfd8658f 100644 --- a/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll +++ b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll @@ -68,6 +68,8 @@ module CorsPermissiveConfiguration { * The value of cors origin when initializing the application. */ class ExpressCors extends Sink, DataFlow::ValueNode { - ExpressCors() { exists(Express::CorsConfiguration config | this = config.getOrigin()) } + ExpressCors() { + exists(Express::CorsConfiguration config | this = config.getCorsConfiguration().getOrigin()) + } } } From 7662b2bd244bb01b0b912a5cb8c3880f83ddf969 Mon Sep 17 00:00:00 2001 From: maikypedia Date: Tue, 19 Dec 2023 13:23:05 +0100 Subject: [PATCH 21/29] format --- javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll b/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll index 59818d421086..983c0a8ac89c 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll @@ -24,7 +24,7 @@ module Apollo { ]).getMember("gql") } - /** An instantiation of an `ApolloServer`. */ + /** An instantiation of an `ApolloServer`. */ class ApolloServer extends API::NewNode { ApolloServer() { this = apollo().getAnInstantiation() } } From 78e7793e011c45065c67b6cd3ee0d3012db066bd Mon Sep 17 00:00:00 2001 From: maikypedia Date: Tue, 9 Jan 2024 01:11:58 +0100 Subject: [PATCH 22/29] Move to experimental --- .../semmle/javascript/frameworks/Express.qll | 19 ----------------- .../experimental/Security/CWE-942}/Cors.qll | 0 ...sPermissiveConfigurationCustomizations.qll | 21 ++++++++++++++++++- 3 files changed, 20 insertions(+), 20 deletions(-) rename javascript/ql/{lib/semmle/javascript/frameworks => src/experimental/Security/CWE-942}/Cors.qll (100%) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 062fb0419ee3..c39d19d4375c 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -5,7 +5,6 @@ import javascript import semmle.javascript.frameworks.HTTP import semmle.javascript.frameworks.ExpressModules -import semmle.javascript.frameworks.Cors private import semmle.javascript.dataflow.InferredTypes private import semmle.javascript.frameworks.ConnectExpressShared::ConnectExpressShared @@ -1072,22 +1071,4 @@ module Express { override predicate definitelyResumesDispatch() { none() } } - - /** - * An express route setup configured with the `cors` package. - */ - class CorsConfiguration extends DataFlow::MethodCallNode { - Cors::Cors corsConfig; - - CorsConfiguration() { - exists(Express::RouteSetup setup | this = setup | - if setup.isUseCall() - then corsConfig = setup.getArgument(0) - else corsConfig = setup.getArgument(any(int i | i > 0)) - ) - } - - /** Gets the expression that configures `cors` on this route setup. */ - Cors::Cors getCorsConfiguration() { result = corsConfig } - } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Cors.qll b/javascript/ql/src/experimental/Security/CWE-942/Cors.qll similarity index 100% rename from javascript/ql/lib/semmle/javascript/frameworks/Cors.qll rename to javascript/ql/src/experimental/Security/CWE-942/Cors.qll diff --git a/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll index abeacfd8658f..8dc8c8badb39 100644 --- a/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll +++ b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll @@ -5,6 +5,7 @@ */ import javascript +import Cors /** Module containing sources, sinks, and sanitizers for overly permissive CORS configurations. */ module CorsPermissiveConfiguration { @@ -69,7 +70,25 @@ module CorsPermissiveConfiguration { */ class ExpressCors extends Sink, DataFlow::ValueNode { ExpressCors() { - exists(Express::CorsConfiguration config | this = config.getCorsConfiguration().getOrigin()) + exists(CorsConfiguration config | this = config.getCorsConfiguration().getOrigin()) } } + + /** + * An express route setup configured with the `cors` package. + */ + class CorsConfiguration extends DataFlow::MethodCallNode { + Cors::Cors corsConfig; + + CorsConfiguration() { + exists(Express::RouteSetup setup | this = setup | + if setup.isUseCall() + then corsConfig = setup.getArgument(0) + else corsConfig = setup.getArgument(any(int i | i > 0)) + ) + } + + /** Gets the expression that configures `cors` on this route setup. */ + Cors::Cors getCorsConfiguration() { result = corsConfig } + } } From 699d8d4719e50e24b1c35f8c7516eae71cc277b5 Mon Sep 17 00:00:00 2001 From: maikypedia Date: Thu, 7 Mar 2024 18:15:22 +0100 Subject: [PATCH 23/29] x --- .../CWE-942/CorsPermissiveConfigurationCustomizations.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll index 8dc8c8badb39..b073ea0b6468 100644 --- a/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll +++ b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll @@ -91,4 +91,4 @@ module CorsPermissiveConfiguration { /** Gets the expression that configures `cors` on this route setup. */ Cors::Cors getCorsConfiguration() { result = corsConfig } } -} +} \ No newline at end of file From c1fd7a61904f7dfc72eed9a09cef9e5d49094477 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Tue, 12 Mar 2024 15:09:45 +0100 Subject: [PATCH 24/29] autoformat --- .../CWE-942/CorsPermissiveConfigurationCustomizations.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll index b073ea0b6468..8dc8c8badb39 100644 --- a/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll +++ b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll @@ -91,4 +91,4 @@ module CorsPermissiveConfiguration { /** Gets the expression that configures `cors` on this route setup. */ Cors::Cors getCorsConfiguration() { result = corsConfig } } -} \ No newline at end of file +} From f2d6640003339e3823c68fb339acd37138b55ac1 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Tue, 12 Mar 2024 15:15:50 +0100 Subject: [PATCH 25/29] fix ambiguous import. It could refer both to a module or a file --- .../CWE-942/CorsPermissiveConfigurationCustomizations.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll index 8dc8c8badb39..23ce2a7af114 100644 --- a/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll +++ b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll @@ -5,7 +5,7 @@ */ import javascript -import Cors +import Cors::Cors /** Module containing sources, sinks, and sanitizers for overly permissive CORS configurations. */ module CorsPermissiveConfiguration { @@ -78,7 +78,7 @@ module CorsPermissiveConfiguration { * An express route setup configured with the `cors` package. */ class CorsConfiguration extends DataFlow::MethodCallNode { - Cors::Cors corsConfig; + Cors corsConfig; CorsConfiguration() { exists(Express::RouteSetup setup | this = setup | @@ -89,6 +89,6 @@ module CorsPermissiveConfiguration { } /** Gets the expression that configures `cors` on this route setup. */ - Cors::Cors getCorsConfiguration() { result = corsConfig } + Cors getCorsConfiguration() { result = corsConfig } } } From cfd7c7a47c45236db2d52a8e88bfaf66ad8bcbf0 Mon Sep 17 00:00:00 2001 From: maikypedia Date: Mon, 27 May 2024 11:57:05 +0200 Subject: [PATCH 26/29] move change-note to `javascript/ql/src/change-notes` --- .../change-notes/2023-11-27-cors-permissive-configuarion.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename javascript/ql/{lib => src}/change-notes/2023-11-27-cors-permissive-configuarion.md (100%) diff --git a/javascript/ql/lib/change-notes/2023-11-27-cors-permissive-configuarion.md b/javascript/ql/src/change-notes/2023-11-27-cors-permissive-configuarion.md similarity index 100% rename from javascript/ql/lib/change-notes/2023-11-27-cors-permissive-configuarion.md rename to javascript/ql/src/change-notes/2023-11-27-cors-permissive-configuarion.md From e96c3a36ad1bb902ebb57662853e26fcfb35280c Mon Sep 17 00:00:00 2001 From: maikypedia Date: Mon, 27 May 2024 12:24:48 +0200 Subject: [PATCH 27/29] Move `Apollo` to experimental --- javascript/ql/lib/javascript.qll | 1 - .../frameworks => src/experimental/Security/CWE-942}/Apollo.qll | 0 .../CWE-942/CorsPermissiveConfigurationCustomizations.qll | 1 + 3 files changed, 1 insertion(+), 1 deletion(-) rename javascript/ql/{lib/semmle/javascript/frameworks => src/experimental/Security/CWE-942}/Apollo.qll (100%) diff --git a/javascript/ql/lib/javascript.qll b/javascript/ql/lib/javascript.qll index 370655df72cc..07fb759bd655 100644 --- a/javascript/ql/lib/javascript.qll +++ b/javascript/ql/lib/javascript.qll @@ -71,7 +71,6 @@ import semmle.javascript.frameworks.ActionsLib import semmle.javascript.frameworks.Angular2 import semmle.javascript.frameworks.AngularJS import semmle.javascript.frameworks.Anser -import semmle.javascript.frameworks.Apollo import semmle.javascript.frameworks.AsyncPackage import semmle.javascript.frameworks.AWS import semmle.javascript.frameworks.Azure diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll b/javascript/ql/src/experimental/Security/CWE-942/Apollo.qll similarity index 100% rename from javascript/ql/lib/semmle/javascript/frameworks/Apollo.qll rename to javascript/ql/src/experimental/Security/CWE-942/Apollo.qll diff --git a/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll index 23ce2a7af114..8e4e3b8e7c0a 100644 --- a/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll +++ b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll @@ -6,6 +6,7 @@ import javascript import Cors::Cors +import Apollo /** Module containing sources, sinks, and sanitizers for overly permissive CORS configurations. */ module CorsPermissiveConfiguration { From 4be5cf4e7863c4d523519ba4d0835f3280013c9a Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Wed, 12 Jun 2024 19:38:02 +0200 Subject: [PATCH 28/29] Update javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll Co-authored-by: Erik Krogh Kristensen --- .../CWE-942/CorsPermissiveConfigurationCustomizations.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll index 8e4e3b8e7c0a..e002b0c81aff 100644 --- a/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll +++ b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll @@ -6,7 +6,7 @@ import javascript import Cors::Cors -import Apollo +import Apollo::Apollo /** Module containing sources, sinks, and sanitizers for overly permissive CORS configurations. */ module CorsPermissiveConfiguration { From 8ba7ac678de67e0c065e2eb2d44042484bfdba18 Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Wed, 12 Jun 2024 19:38:13 +0200 Subject: [PATCH 29/29] Update javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll Co-authored-by: Erik Krogh Kristensen --- .../CWE-942/CorsPermissiveConfigurationCustomizations.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll index e002b0c81aff..045d1c1ef549 100644 --- a/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll +++ b/javascript/ql/src/experimental/Security/CWE-942/CorsPermissiveConfigurationCustomizations.qll @@ -59,7 +59,7 @@ module CorsPermissiveConfiguration { */ class CorsApolloServer extends Sink, DataFlow::ValueNode { CorsApolloServer() { - exists(Apollo::ApolloServer agql | + exists(ApolloServer agql | this = agql.getOptionArgument(0, "cors").getALocalSource().getAPropertyWrite("origin").getRhs() )