mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
56 lines
1.7 KiB
Plaintext
56 lines
1.7 KiB
Plaintext
/**
|
|
* @name Information disclosure through postMessage
|
|
* @description Tracks values from an 'authKey' property into a postMessage call with unrestricted origin,
|
|
indicating a leak of sensitive information.
|
|
* @kind path-problem
|
|
* @tags security
|
|
* @id js/cookbook/information-disclosure
|
|
*/
|
|
|
|
import javascript::DataFlow
|
|
import DataFlow::PathGraph
|
|
|
|
/**
|
|
* Tracks authentication tokens ("authKey") to a postMessage call with unrestricted target origin.
|
|
*
|
|
* For example:
|
|
* ```
|
|
* win.postMessage(JSON.stringify({
|
|
* action: 'pause',
|
|
* auth: {
|
|
* key: window.state.authKey
|
|
* }
|
|
* }), '*');
|
|
* ```
|
|
*/
|
|
class AuthKeyTracking extends DataFlow::Configuration {
|
|
AuthKeyTracking() { this = "AuthKeyTracking" }
|
|
|
|
override predicate isSource(Node node) { node.(PropRead).getPropertyName() = "authKey" }
|
|
|
|
override predicate isSink(Node node) {
|
|
exists(MethodCallNode call |
|
|
call.getMethodName() = "postMessage" and
|
|
call.getArgument(1).getStringValue() = "*" and // no restriction on target origin
|
|
call.getArgument(0) = node
|
|
)
|
|
}
|
|
|
|
override predicate isAdditionalFlowStep(Node pred, Node succ) {
|
|
// Step into objects: x -> { f: x }
|
|
succ.(SourceNode).getAPropertyWrite().getRhs() = pred
|
|
or
|
|
// Step through JSON serialization: x -> JSON.stringify(x)
|
|
// Note: TaintTracking::Configuration includes this step by default, but not DataFlow::Configuration
|
|
exists(CallNode call |
|
|
call = globalVarRef("JSON").getAMethodCall("stringify") and
|
|
pred = call.getArgument(0) and
|
|
succ = call
|
|
)
|
|
}
|
|
}
|
|
|
|
from AuthKeyTracking cfg, PathNode source, PathNode sink
|
|
where cfg.hasFlowPath(source, sink)
|
|
select sink.getNode(), source, sink, "Message leaks the authKey from $@.", source.getNode(), "here"
|