Revert "stash"

This reverts commit bdee99ae88.
This commit is contained in:
am0o0
2024-05-25 12:03:00 +02:00
parent 1860af075d
commit c299b5657a
14 changed files with 262 additions and 342 deletions

View File

@@ -26,23 +26,23 @@ module AWS {
)
}
// /**
// * An expression that is used as an AWS config value: `{ accessKeyId: <user>, secretAccessKey: <password>}`.
// */
// class Credentials extends CredentialsNode {
// string kind;
/**
* An expression that is used as an AWS config value: `{ accessKeyId: <user>, secretAccessKey: <password>}`.
*/
class Credentials extends CredentialsNode {
string kind;
// Credentials() {
// exists(string prop, DataFlow::InvokeNode invk, int i |
// takesConfigurationObject(invk, i) and
// this = invk.getOptionArgument(i, prop)
// |
// prop = "accessKeyId" and kind = "user name"
// or
// prop = "secretAccessKey" and kind = "password"
// )
// }
Credentials() {
exists(string prop, DataFlow::InvokeNode invk, int i |
takesConfigurationObject(invk, i) and
this = invk.getOptionArgument(i, prop)
|
prop = "accessKeyId" and kind = "user name"
or
prop = "secretAccessKey" and kind = "password"
)
}
// override string getCredentialsKind() { result = kind }
// }
override string getCredentialsKind() { result = kind }
}
}

View File

@@ -8,21 +8,21 @@ module Azure {
/**
* An expression that is used for authentication at Azure`.
*/
// class Credentials extends CredentialsNode {
// string kind;
class Credentials extends CredentialsNode {
string kind;
// Credentials() {
// exists(DataFlow::CallNode mce |
// mce =
// DataFlow::moduleMember("ms-rest-azure",
// ["loginWithUsernamePassword", "loginWithServicePrincipalSecret"]).getACall()
// |
// this = mce.getArgument(0) and kind = "user name"
// or
// this = mce.getArgument(1) and kind = "password"
// )
// }
Credentials() {
exists(DataFlow::CallNode mce |
mce =
DataFlow::moduleMember("ms-rest-azure",
["loginWithUsernamePassword", "loginWithServicePrincipalSecret"]).getACall()
|
this = mce.getArgument(0) and kind = "user name"
or
this = mce.getArgument(1) and kind = "password"
)
}
// override string getCredentialsKind() { result = kind }
// }
override string getCredentialsKind() { result = kind }
}
}

View File

@@ -285,21 +285,21 @@ module ClientRequest {
}
/** An expression that is used as a credential in a request. */
// private class AuthorizationHeader extends CredentialsNode {
// AuthorizationHeader() {
// exists(DataFlow::PropWrite write | write.getPropertyName().regexpMatch("(?i)authorization") |
// this = write.getRhs()
// )
// or
// exists(DataFlow::MethodCallNode call | call.getMethodName() = ["append", "set"] |
// call.getNumArgument() = 2 and
// call.getArgument(0).getStringValue().regexpMatch("(?i)authorization") and
// this = call.getArgument(1)
// )
// }
private class AuthorizationHeader extends CredentialsNode {
AuthorizationHeader() {
exists(DataFlow::PropWrite write | write.getPropertyName().regexpMatch("(?i)authorization") |
this = write.getRhs()
)
or
exists(DataFlow::MethodCallNode call | call.getMethodName() = ["append", "set"] |
call.getNumArgument() = 2 and
call.getArgument(0).getStringValue().regexpMatch("(?i)authorization") and
this = call.getArgument(1)
)
}
// override string getCredentialsKind() { result = "authorization header" }
// }
override string getCredentialsKind() { result = "authorization header" }
}
/**
* A model of a URL request made using an implementation of the `fetch` API.

View File

@@ -100,23 +100,23 @@ module Connect {
DataFlow::Node getARouteHandlerNode() { result = this.getAnArgument() }
}
// /** An expression that is passed as `basicAuthConnect(<user>, <password>)`. */
// class Credentials extends CredentialsNode {
// string kind;
/** An expression that is passed as `basicAuthConnect(<user>, <password>)`. */
class Credentials extends CredentialsNode {
string kind;
// Credentials() {
// exists(DataFlow::CallNode call |
// call = DataFlow::moduleImport("basic-auth-connect").getAnInvocation() and
// call.getNumArgument() = 2
// |
// this = call.getArgument(0) and kind = "user name"
// or
// this = call.getArgument(1) and kind = "password"
// )
// }
Credentials() {
exists(DataFlow::CallNode call |
call = DataFlow::moduleImport("basic-auth-connect").getAnInvocation() and
call.getNumArgument() = 2
|
this = call.getArgument(0) and kind = "user name"
or
this = call.getArgument(1) and kind = "password"
)
}
// override string getCredentialsKind() { result = kind }
// }
override string getCredentialsKind() { result = kind }
}
deprecated class RequestExpr = NodeJSLib::RequestExpr;

View File

@@ -34,9 +34,9 @@ abstract class CryptographicKeyCreation extends DataFlow::Node {
/**
* A key used in a cryptographic algorithm, viewed as a `CredentialsNode`.
*/
// class CryptographicKeyCredentialsExpr extends CredentialsNode instanceof CryptographicKey {
// override string getCredentialsKind() { result = "key" }
// }
class CryptographicKeyCredentialsExpr extends CredentialsNode instanceof CryptographicKey {
override string getCredentialsKind() { result = "key" }
}
// Holds if `algorithm` is an `EncryptionAlgorithm` that uses a block cipher
private predicate isBlockEncryptionAlgorithm(CryptographicAlgorithm algorithm) {

View File

@@ -8,17 +8,17 @@ module DigitalOcean {
/**
* An expression that is used for authentication at DigitalOcean: `digitalocean.client(<token>)`.
*/
// class Credentials extends CredentialsNode {
// string kind;
class Credentials extends CredentialsNode {
string kind;
// Credentials() {
// exists(DataFlow::CallNode mce |
// mce = DataFlow::moduleMember("digitalocean", "client").getACall()
// |
// this = mce.getArgument(0) and kind = "token"
// )
// }
Credentials() {
exists(DataFlow::CallNode mce |
mce = DataFlow::moduleMember("digitalocean", "client").getACall()
|
this = mce.getArgument(0) and kind = "token"
)
}
// override string getCredentialsKind() { result = kind }
// }
override string getCredentialsKind() { result = kind }
}
}

View File

@@ -1007,27 +1007,27 @@ module Express {
}
}
// /** An expression that is passed as `expressBasicAuth({ users: { <user>: <password> }})`. */
// class Credentials extends CredentialsNode {
// string kind;
/** An expression that is passed as `expressBasicAuth({ users: { <user>: <password> }})`. */
class Credentials extends CredentialsNode {
string kind;
// Credentials() {
// exists(DataFlow::CallNode call, DataFlow::ModuleImportNode mod |
// mod.getPath() = "express-basic-auth" and
// call = mod.getAnInvocation() and
// exists(DataFlow::ObjectLiteralNode usersSrc, DataFlow::PropWrite pwn |
// usersSrc.flowsTo(call.getOptionArgument(0, "users")) and
// usersSrc.flowsTo(pwn.getBase())
// |
// this = pwn.getPropertyNameExpr().flow() and kind = "user name"
// or
// this = pwn.getRhs() and kind = "password"
// )
// )
// }
Credentials() {
exists(DataFlow::CallNode call, DataFlow::ModuleImportNode mod |
mod.getPath() = "express-basic-auth" and
call = mod.getAnInvocation() and
exists(DataFlow::ObjectLiteralNode usersSrc, DataFlow::PropWrite pwn |
usersSrc.flowsTo(call.getOptionArgument(0, "users")) and
usersSrc.flowsTo(pwn.getBase())
|
this = pwn.getPropertyNameExpr().flow() and kind = "user name"
or
this = pwn.getRhs() and kind = "password"
)
)
}
// override string getCredentialsKind() { result = kind }
// }
override string getCredentialsKind() { result = kind }
}
/** A call to `response.sendFile`, considered as a file system access. */
private class ResponseSendFileAsFileSystemAccess extends FileSystemReadAccess,

View File

@@ -44,7 +44,8 @@ private module JsonWebToken {
*/
private class JwtKey extends CredentialsNode {
JwtKey() {
this = API::moduleImport("jsonwebtoken").getMember(["verify"]).getParameter(1).asSink()
this =
API::moduleImport("jsonwebtoken").getMember(["sign", "verify"]).getParameter(1).asSink()
}
override string getCredentialsKind() { result = "key" }

View File

@@ -77,22 +77,22 @@ private module MongoDB {
result = API::Node::ofType("mongoose", "ConnectOptions")
}
// /**
// * An expression passed to `mongodb` or `mongoose` to supply credentials.
// */
// class Credentials extends CredentialsNode {
// string kind;
/**
* An expression passed to `mongodb` or `mongoose` to supply credentials.
*/
class Credentials extends CredentialsNode {
string kind;
// Credentials() {
// exists(string prop | this = credentialsObject().getMember(prop).asSink() |
// prop = "user" and kind = "user name"
// or
// prop = "pass" and kind = "password"
// )
// }
Credentials() {
exists(string prop | this = credentialsObject().getMember(prop).asSink() |
prop = "user" and kind = "user name"
or
prop = "pass" and kind = "password"
)
}
// override string getCredentialsKind() { result = kind }
// }
override string getCredentialsKind() { result = kind }
}
}
private module Mongoose {

View File

@@ -425,16 +425,16 @@ module NodeJSLib {
ServerDefinition() { isCreateServer(this) }
}
// /** An expression that is passed as `http.request({ auth: <expr> }, ...)`. */
// class Credentials extends CredentialsNode {
// Credentials() {
// exists(string http | http = "http" or http = "https" |
// this = DataFlow::moduleMember(http, "request").getACall().getOptionArgument(0, "auth")
// )
// }
/** An expression that is passed as `http.request({ auth: <expr> }, ...)`. */
class Credentials extends CredentialsNode {
Credentials() {
exists(string http | http = "http" or http = "https" |
this = DataFlow::moduleMember(http, "request").getACall().getOptionArgument(0, "auth")
)
}
// override string getCredentialsKind() { result = "credentials" }
// }
override string getCredentialsKind() { result = "credentials" }
}
/**
* A call a process-terminating function, such as `process.exit`.
@@ -1035,27 +1035,27 @@ module NodeJSLib {
}
}
// /**
// * A data flow node that is the username passed to the login callback provided by an HTTP or HTTPS request made by a Node.js process, for example `username` in `http.request(url).on('login', (res, cb) => {cb(username, password)})`.
// */
// private class ClientRequestLoginUsername extends CredentialsNode {
// ClientRequestLoginUsername() {
// exists(ClientRequestLoginCallback callback | this = callback.getACall().getArgument(0))
// }
/**
* A data flow node that is the username passed to the login callback provided by an HTTP or HTTPS request made by a Node.js process, for example `username` in `http.request(url).on('login', (res, cb) => {cb(username, password)})`.
*/
private class ClientRequestLoginUsername extends CredentialsNode {
ClientRequestLoginUsername() {
exists(ClientRequestLoginCallback callback | this = callback.getACall().getArgument(0))
}
// override string getCredentialsKind() { result = "Node.js http(s) client login username" }
// }
override string getCredentialsKind() { result = "Node.js http(s) client login username" }
}
// /**
// * A data flow node that is the password passed to the login callback provided by an HTTP or HTTPS request made by a Node.js process, for example `password` in `http.request(url).on('login', (res, cb) => {cb(username, password)})`.
// */
// private class ClientRequestLoginPassword extends CredentialsNode {
// ClientRequestLoginPassword() {
// exists(ClientRequestLoginCallback callback | this = callback.getACall().getArgument(1))
// }
/**
* A data flow node that is the password passed to the login callback provided by an HTTP or HTTPS request made by a Node.js process, for example `password` in `http.request(url).on('login', (res, cb) => {cb(username, password)})`.
*/
private class ClientRequestLoginPassword extends CredentialsNode {
ClientRequestLoginPassword() {
exists(ClientRequestLoginCallback callback | this = callback.getACall().getArgument(1))
}
// override string getCredentialsKind() { result = "Node.js http(s) client login password" }
// }
override string getCredentialsKind() { result = "Node.js http(s) client login password" }
}
/**
* A data flow node that is the parameter of an error callback for an HTTP or HTTPS request made by a Node.js process, for example `err` in `http.request(url).on('error', (err) => {})`.

View File

@@ -28,43 +28,43 @@ module PkgCloud {
)
}
// /**
// * An expression that is used for authentication through pkgcloud.
// */
// class Credentials extends CredentialsNode {
// string kind;
/**
* An expression that is used for authentication through pkgcloud.
*/
class Credentials extends CredentialsNode {
string kind;
// Credentials() {
// exists(string propertyName, DataFlow::InvokeNode invk |
// takesConfigurationObject(invk, _) and
// this = invk.getOptionArgument(0, propertyName)
// |
// /*
// * Catch-all support for the following providers:
// * - Amazon
// * - Azure
// * - DigitalOcean
// * - HP Helion
// * - Joyent
// * - OpenStack
// * - Rackspace
// * - IrisCouch
// * - MongoLab
// * - MongoHQ
// * - RedisToGo
// */
Credentials() {
exists(string propertyName, DataFlow::InvokeNode invk |
takesConfigurationObject(invk, _) and
this = invk.getOptionArgument(0, propertyName)
|
/*
* Catch-all support for the following providers:
* - Amazon
* - Azure
* - DigitalOcean
* - HP Helion
* - Joyent
* - OpenStack
* - Rackspace
* - IrisCouch
* - MongoLab
* - MongoHQ
* - RedisToGo
*/
// kind = "user name" and
// propertyName = ["account", "keyId", "storageAccount", "username"]
// or
// kind = "password" and
// propertyName = ["key", "apiKey", "storageAccessKey", "password"]
// or
// kind = "token" and
// propertyName = "token"
// )
// }
kind = "user name" and
propertyName = ["account", "keyId", "storageAccount", "username"]
or
kind = "password" and
propertyName = ["key", "apiKey", "storageAccessKey", "password"]
or
kind = "token" and
propertyName = "token"
)
}
// override string getCredentialsKind() { result = kind }
// }
override string getCredentialsKind() { result = kind }
}
}

View File

@@ -5,49 +5,49 @@
import javascript
module Request {
// /** A credentials expression that is used for authentication. */
// class Credentials extends CredentialsNode {
// string kind;
/** A credentials expression that is used for authentication. */
class Credentials extends CredentialsNode {
string kind;
// Credentials() {
// exists(DataFlow::ModuleImportNode mod, DataFlow::CallNode action |
// mod.getPath() = "request" and
// (
// // default form: `request(...)`
// action = mod.getAnInvocation()
// or
// // specialized form: `request.get(...)`
// action = mod.getAMemberCall(any(Http::RequestMethodName n).toLowerCase())
// )
// |
// exists(DataFlow::MethodCallNode auth, int argIndex |
// // request.get(url).auth('username', 'password', _, 'token');
// auth = action.getAMemberCall("auth") and
// this = auth.getArgument(argIndex)
// |
// argIndex = 0 and kind = "user name"
// or
// argIndex = 1 and kind = "password"
// or
// argIndex = 3 and kind = "token"
// )
// or
// exists(DataFlow::ObjectLiteralNode auth, string propertyName |
// // request.get(url, { auth: {user: 'username', pass: 'password', bearer: 'token'}})
// auth.flowsTo(action.getOptionArgument(1, "auth")) and
// auth.hasPropertyWrite(propertyName, this)
// |
// (propertyName = "user" or propertyName = "username") and
// kind = "user name"
// or
// (propertyName = "pass" or propertyName = "password") and
// kind = "password"
// or
// propertyName = "bearer" and kind = "token"
// )
// )
// }
Credentials() {
exists(DataFlow::ModuleImportNode mod, DataFlow::CallNode action |
mod.getPath() = "request" and
(
// default form: `request(...)`
action = mod.getAnInvocation()
or
// specialized form: `request.get(...)`
action = mod.getAMemberCall(any(Http::RequestMethodName n).toLowerCase())
)
|
exists(DataFlow::MethodCallNode auth, int argIndex |
// request.get(url).auth('username', 'password', _, 'token');
auth = action.getAMemberCall("auth") and
this = auth.getArgument(argIndex)
|
argIndex = 0 and kind = "user name"
or
argIndex = 1 and kind = "password"
or
argIndex = 3 and kind = "token"
)
or
exists(DataFlow::ObjectLiteralNode auth, string propertyName |
// request.get(url, { auth: {user: 'username', pass: 'password', bearer: 'token'}})
auth.flowsTo(action.getOptionArgument(1, "auth")) and
auth.hasPropertyWrite(propertyName, this)
|
(propertyName = "user" or propertyName = "username") and
kind = "user name"
or
(propertyName = "pass" or propertyName = "password") and
kind = "password"
or
propertyName = "bearer" and kind = "token"
)
)
}
// override string getCredentialsKind() { result = kind }
// }
override string getCredentialsKind() { result = kind }
}
}

View File

@@ -70,23 +70,23 @@ private module MySql {
result = API::Node::ofType(moduleName(), "ConnectionOptions")
}
// /** An expression that is passed as user name or password to `mysql.createConnection`. */
// class Credentials extends CredentialsNode {
// string kind;
/** An expression that is passed as user name or password to `mysql.createConnection`. */
class Credentials extends CredentialsNode {
string kind;
// Credentials() {
// exists(string prop |
// this = connectionOptions().getMember(prop).asSink() and
// (
// prop = "user" and kind = "user name"
// or
// prop = "password" and kind = prop
// )
// )
// }
Credentials() {
exists(string prop |
this = connectionOptions().getMember(prop).asSink() and
(
prop = "user" and kind = "user name"
or
prop = "password" and kind = prop
)
)
}
// override string getCredentialsKind() { result = kind }
// }
override string getCredentialsKind() { result = kind }
}
}
/**
@@ -129,24 +129,24 @@ private module Postgres {
}
}
// /** An expression that is passed as user name or password when creating a client or a pool. */
// class Credentials extends CredentialsNode {
// string kind;
/** An expression that is passed as user name or password when creating a client or a pool. */
class Credentials extends CredentialsNode {
string kind;
// Credentials() {
// exists(string prop |
// this = clientOrPoolConstructor().getParameter(0).getMember(prop).asSink()
// or
// this = pgPromise().getParameter(0).getMember(prop).asSink()
// |
// prop = "user" and kind = "user name"
// or
// prop = "password" and kind = prop
// )
// }
Credentials() {
exists(string prop |
this = clientOrPoolConstructor().getParameter(0).getMember(prop).asSink()
or
this = pgPromise().getParameter(0).getMember(prop).asSink()
|
prop = "user" and kind = "user name"
or
prop = "password" and kind = prop
)
}
// override string getCredentialsKind() { result = kind }
// }
override string getCredentialsKind() { result = kind }
}
/** Gets a node referring to the `pg-promise` library (which is not itself a Promise). */
API::Node pgPromise() { result = API::moduleImport("pg-promise") }
@@ -331,23 +331,23 @@ private module MsSql {
}
}
// /** An expression that is passed as user name or password when creating a client or a pool. */
// class Credentials extends CredentialsNode {
// string kind;
/** An expression that is passed as user name or password when creating a client or a pool. */
class Credentials extends CredentialsNode {
string kind;
// Credentials() {
// exists(string prop |
// this = config().getMember(prop).asSink() and
// (
// prop = "user" and kind = "user name"
// or
// prop = "password" and kind = prop
// )
// )
// }
Credentials() {
exists(string prop |
this = config().getMember(prop).asSink() and
(
prop = "user" and kind = "user name"
or
prop = "password" and kind = prop
)
)
}
// override string getCredentialsKind() { result = kind }
// }
override string getCredentialsKind() { result = kind }
}
}
/**

View File

@@ -1,81 +0,0 @@
/**
* @name Usage of Constant Secret key for decoding JWT
* @description Hardcoded Secrets leakage can lead to authentication or authorization bypass
* @kind path-problem
* @problem.severity error
* @precision high
* @id javascript/jwt-hardcoded-key
* @tags security
* experimental
* external/cwe/CWE-321
*/
import javascript
import DataFlow::PathGraph
import DataFlow
class JWTDecodeConfig extends TaintTracking::Configuration {
JWTDecodeConfig() { this = "JWTConfig" }
override predicate isSource(DataFlow::Node source) {
source.asExpr() instanceof ConstantString and not source.asExpr().mayHaveStringValue(["", " "])
}
override predicate isSanitizer(DataFlow::Node node) {
node.getFile()
.getLocation()
.hasLocationInfo(any(string s | s.matches(["%test%", "%demo%", "%example%", "%sample%"])),
_, _, _, _)
}
override predicate isSink(DataFlow::Node sink) {
sink = API::moduleImport("jsonwebtoken").getMember(["sign", "verify"]).getParameter(1).asSink() or
sink = API::moduleImport("jose").getMember("jwtVerify").getParameter(1).asSink() or
sink = API::moduleImport("jwt-simple").getMember("decode").getParameter(1).asSink() or
sink = API::moduleImport("next-auth").getParameter(0).getMember("secret").asSink() or
sink = API::moduleImport("koa-jwt").getParameter(0).getMember("secret").asSink() or
sink =
API::moduleImport("express-jwt")
.getMember("expressjwt")
.getParameter(0)
.getMember("secret")
.asSink() or
sink =
API::moduleImport("passport-jwt")
.getMember("Strategy")
.getParameter(0)
.getMember("secretOrKey")
.asSink()
}
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(DataFlow::CallNode n, DataFlow::NewNode nn |
n.getCalleeName() = "encode" and
nn.flowsTo(n.getReceiver()) and
nn.getCalleeName() = "TextEncoder"
|
pred = n.getArgument(0) and
succ = n
)
or
exists(API::Node n | n = API::moduleImport("jose").getMember("importSPKI") |
pred = n.getACall().getArgument(0) and
succ = n.getReturn().getPromised().asSource()
)
or
exists(API::Node n | n = API::moduleImport("jose").getMember("base64url").getMember("decode") |
pred = n.getACall().getArgument(0) and
succ = n.getACall()
)
or
exists(DataFlow::CallNode n | n = DataFlow::globalVarRef("Buffer").getAMemberCall("from") |
pred = n.getArgument(0) and
succ = [n, n.getAChainedMethodCall(["toString", "toJSON"])]
)
}
}
from JWTDecodeConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "this $@. is used as a secret key", source.getNode(),
"Constant"