mirror of
https://github.com/github/codeql.git
synced 2025-12-24 12:46:34 +01:00
Add initial query for CWE-942
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
@@ -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 |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE-942/CorsPermissiveConfiguration.ql
|
||||
33
javascript/ql/test/query-tests/Security/CWE-942/tst.js
Normal file
33
javascript/ql/test/query-tests/Security/CWE-942/tst.js
Normal file
@@ -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 }
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user