Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
65b9774
V1
am0o0 Aug 29, 2023
4f04dc8
add test cases
am0o0 Aug 29, 2023
3f64cc8
fix qhelps
am0o0 Aug 29, 2023
7a577dd
change Source to ConstantString, it seems that we have some duplicate…
am0o0 Aug 30, 2023
7891e64
add sanitizers to hardcoded query
am0o0 Oct 15, 2023
8e0f52c
remove noverification query
am0o0 Oct 19, 2023
e1d42fa
move new secret key sinks to existing CredentialsNode class,
am0o0 Nov 2, 2023
01fb29e
remove my Hardcoded secret key query in favor of CWE-798:HardcodedCre…
am0o0 Nov 2, 2023
bdee99a
stash
am0o0 Dec 10, 2023
1860af0
fix conflict
am0o0 May 25, 2024
c299b56
Revert "stash"
am0o0 May 25, 2024
20c087c
update tests
am0o0 May 25, 2024
4e365e2
fix conflict
am0o0 May 25, 2024
2226f51
Merge branch 'main' into amammad-js-hardcodedJWTKey
am0o0 May 25, 2024
d775135
update tests
am0o0 May 25, 2024
5d98ec3
stash: add debug query
am0o0 May 25, 2024
c2f96a1
fix a document
am0o0 May 25, 2024
71dfdfa
remove the debug query
am0o0 May 27, 2024
61a11c6
Or to or in docs
am0o0 Jun 6, 2024
ee05ec0
remove sanitnzer and add a where condition instead
am0o0 Jun 6, 2024
e4ffdb8
add tests for new where condition, update expected test results
am0o0 Jun 6, 2024
5a69bbf
use isTestFile from ClassifyFiles module file instead previous where …
am0o0 Jun 7, 2024
65fdb8c
move jose SharedTaintStep to a local taint step, add more additional …
am0o0 Jul 1, 2024
60aa711
implement TextEncoderStep taint step with globalVarRef predicate
am0o0 Jul 1, 2024
fa8c457
move the TextEncoder and Buffer jose.base64url taint steps to a local…
am0o0 Jul 1, 2024
6ecd8b7
add new default cred kind
am0o0 Jul 1, 2024
5a18775
update test cases of __tests__/ dir
am0o0 Jul 1, 2024
b360c8a
Update hardcodedCredentials query file to only exclude 'jwt key' kind…
am0o0 Jul 1, 2024
354fcbe
apply changes from @erik-krogh
am0o0 Aug 1, 2024
fce183c
apply autoformat to `HardcodedCredentialsCustomizations.qll`
am0o0 Aug 5, 2024
e4deb7d
apply autoformating for HardcodedCredentials.ql
am0o0 Aug 5, 2024
b64cb4d
remove a part of code related to debugging :)
am0o0 Aug 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import javascript
abstract class CredentialsNode extends DataFlow::Node {
/**
* Gets a description of the kind of credential this expression is used as,
* such as `"user name"`, `"password"`, `"key"`.
* such as `"user name"`, `"password"`, `"key"`, `"jwt key"`.
*/
abstract string getCredentialsKind();
}
Expand Down
106 changes: 103 additions & 3 deletions javascript/ql/lib/semmle/javascript/frameworks/JWT.qll
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,111 @@ private module JsonWebToken {
}

/**
* The private key for a JWT as a `CredentialsNode`.
* The secret or PrivateKey for a JWT as a `CredentialsNode`.
*/
private class JwtKey extends CredentialsNode {
JwtKey() { this = DataFlow::moduleMember("jsonwebtoken", "sign").getACall().getArgument(1) }
JwtKey() {
this =
API::moduleImport("jsonwebtoken").getMember(["sign", "verify"]).getParameter(1).asSink()
}

override string getCredentialsKind() { result = "jwt key" }
}
}

/**
* Provides classes and predicates modeling the `jose` library.
*/
private module Jose {
/**
* The asymmetric key or symmetric secret for verifying a JWT as a `CredentialsNode`.
*/
private class JwtVerifyKey extends CredentialsNode {
JwtVerifyKey() {
this = API::moduleImport("jose").getMember("jwtVerify").getParameter(1).asSink()
}

override string getCredentialsKind() { result = "jwt key" }
}
}

/**
* Provides classes and predicates modeling the `jwt-simple` library.
*/
private module JwtSimple {
/**
* The asymmetric key or symmetric secret for a JWT as a `CredentialsNode`.
*/
private class JwtKey extends CredentialsNode {
JwtKey() { this = API::moduleImport("jwt-simple").getMember("decode").getParameter(1).asSink() }

override string getCredentialsKind() { result = "jwt key" }
}
}

/**
* Provides classes and predicates modeling the `koa-jwt` library.
*/
private module KoaJwt {
/**
* The shared secret for a JWT as a `CredentialsNode`.
*/
private class SharedSecret extends CredentialsNode {
SharedSecret() {
this = API::moduleImport("koa-jwt").getParameter(0).getMember("secret").asSink()
}

override string getCredentialsKind() { result = "jwt key" }
}
}

/**
* Provides classes and predicates modeling the `express-jwt` library.
*/
private module ExpressJwt {
/**
* The shared secret for a JWT as a `CredentialsNode`.
*/
private class SharedSecret extends CredentialsNode {
SharedSecret() {
this =
API::moduleImport("express-jwt")
.getMember("expressjwt")
.getParameter(0)
.getMember("secret")
.asSink()
}

override string getCredentialsKind() { result = "jwt key" }
}
}

/**
* Provides classes and predicates modeling the `passport-jwt` library.
*/
private module PassportJwt {
/**
* The secret (symmetric) or PEM-encoded public key (asymmetric) for a JWT as a `CredentialsNode`.
*/
private class JwtKey extends CredentialsNode {
JwtKey() {
this =
API::moduleImport("passport-jwt")
.getMember("Strategy")
.getParameter(0)
.getMember("secretOrKey")
.asSink()
or
this =
API::moduleImport("passport-jwt")
.getMember("Strategy")
.getParameter(0)
.getMember("secretOrKeyProvider")
.getParameter(2)
.getParameter(1)
.asSink()
}

override string getCredentialsKind() { result = "key" }
override string getCredentialsKind() { result = "jwt key" }
}
}
16 changes: 16 additions & 0 deletions javascript/ql/lib/semmle/javascript/frameworks/Next.qll
Original file line number Diff line number Diff line change
Expand Up @@ -255,4 +255,20 @@ module NextJS {
.getMember("router")
.asSource()
}

/**
* Provides classes and predicates modeling the `next-auth` library.
*/
private module NextAuth {
/**
* A random string used to hash tokens, sign cookies and generate cryptographic keys as a `CredentialsNode`.
*/
private class SecretKey extends CredentialsNode {
SecretKey() {
this = API::moduleImport("next-auth").getParameter(0).getMember("secret").asSink()
}

override string getCredentialsKind() { result = "jwt key" }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* own.
*/

import semmle.javascript.filters.ClassifyFiles
import javascript
private import semmle.javascript.security.SensitiveActions

Expand Down Expand Up @@ -38,5 +39,9 @@ module HardcodedCredentials {
*/
class DefaultCredentialsSink extends Sink instanceof CredentialsNode {
override string getKind() { result = super.getCredentialsKind() }

DefaultCredentialsSink() {
not (super.getCredentialsKind() = "jwt key" and isTestFile(this.getFile()))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,43 @@ class Configuration extends DataFlow::Configuration {
trg = bufferFrom and
src = bufferFrom.getArgument(0)
)
or
exists(API::Node n |
n = API::moduleImport("jose").getMember(["importSPKI", "importPKCS8", "importX509"])
|
src = n.getACall().getArgument(0) and
trg = n.getReturn().getPromised().asSource()
)
or
exists(API::Node n |
n = API::moduleImport("jose").getMember(["importSPKI", "importPKCS8", "importX509"])
|
src = n.getACall().getArgument(0) and
trg = n.getReturn().getPromised().asSource()
)
or
exists(API::Node n | n = API::moduleImport("jose").getMember("importJWK") |
src = n.getParameter(0).getMember(["x", "y", "n"]).asSink() and
trg = n.getReturn().getPromised().asSource()
)
or
exists(DataFlow::CallNode n |
n = DataFlow::globalVarRef("TextEncoder").getAnInstantiation().getAMemberCall("encode")
|
src = n.getArgument(0) and
trg = n
)
or
exists(DataFlow::CallNode n | n = DataFlow::globalVarRef("Buffer").getAMemberCall("from") |
src = n.getArgument(0) and
trg = [n, n.getAChainedMethodCall(["toString", "toJSON"])]
)
or
exists(API::Node n |
n = API::moduleImport("jose").getMember("base64url").getMember(["decode", "encode"])
|
src = n.getACall().getArgument(0) and
trg = n.getACall()
)
}
}
Loading