mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge pull request #20324 from michaelnebel/actions/ql4ql
Actions: Fix some Ql4Ql violations.
This commit is contained in:
@@ -70,8 +70,8 @@ class Location extends TLocation, TBaseLocation {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this element is at the specified location.
|
* Holds if this element is at the specified location.
|
||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `sc` of line `sl` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `ec` of line `el` in file `p`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Providing locations in CodeQL queries](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
* [Providing locations in CodeQL queries](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ class If extends AstNode instanceof IfImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An Environemnt node representing a deployment environment.
|
* An Environment node representing a deployment environment.
|
||||||
*/
|
*/
|
||||||
class Environment extends AstNode instanceof EnvironmentImpl {
|
class Environment extends AstNode instanceof EnvironmentImpl {
|
||||||
string getName() { result = super.getName() }
|
string getName() { result = super.getName() }
|
||||||
|
|||||||
@@ -125,12 +125,11 @@ abstract class AstNodeImpl extends TAstNode {
|
|||||||
* Gets the enclosing Step.
|
* Gets the enclosing Step.
|
||||||
*/
|
*/
|
||||||
StepImpl getEnclosingStep() {
|
StepImpl getEnclosingStep() {
|
||||||
if this instanceof StepImpl
|
this instanceof StepImpl and
|
||||||
then result = this
|
result = this
|
||||||
else
|
or
|
||||||
if this instanceof ScalarValueImpl
|
this instanceof ScalarValueImpl and
|
||||||
then result.getAChildNode*() = this.getParentNode()
|
result.getAChildNode*() = this.getParentNode()
|
||||||
else none()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1416,9 +1415,8 @@ class ExternalJobImpl extends JobImpl, UsesImpl {
|
|||||||
override string getVersion() {
|
override string getVersion() {
|
||||||
exists(YamlString name |
|
exists(YamlString name |
|
||||||
n.lookup("uses") = name and
|
n.lookup("uses") = name and
|
||||||
if not name.getValue().matches("\\.%")
|
not name.getValue().matches("\\.%") and
|
||||||
then result = name.getValue().regexpCapture(repoUsesParser(), 4)
|
result = name.getValue().regexpCapture(repoUsesParser(), 4)
|
||||||
else none()
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -286,7 +286,7 @@ private module Cached {
|
|||||||
/**
|
/**
|
||||||
* Holds if `cfn` is the `i`th node in basic block `bb`.
|
* Holds if `cfn` is the `i`th node in basic block `bb`.
|
||||||
*
|
*
|
||||||
* In other words, `i` is the shortest distance from a node `bb`
|
* In other words, `i` is the shortest distance from a node `bbStart`
|
||||||
* that starts a basic block to `cfn` along the `intraBBSucc` relation.
|
* that starts a basic block to `cfn` along the `intraBBSucc` relation.
|
||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
|
|||||||
@@ -63,10 +63,10 @@ predicate madSource(DataFlow::Node source, string kind, string fieldName) {
|
|||||||
(
|
(
|
||||||
if fieldName.trim().matches("env.%")
|
if fieldName.trim().matches("env.%")
|
||||||
then source.asExpr() = uses.getInScopeEnvVarExpr(fieldName.trim().replaceAll("env.", ""))
|
then source.asExpr() = uses.getInScopeEnvVarExpr(fieldName.trim().replaceAll("env.", ""))
|
||||||
else
|
else (
|
||||||
if fieldName.trim().matches("output.%")
|
fieldName.trim().matches("output.%") and
|
||||||
then source.asExpr() = uses
|
source.asExpr() = uses
|
||||||
else none()
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,14 +31,14 @@ abstract class RemoteFlowSource extends SourceNode {
|
|||||||
class GitHubCtxSource extends RemoteFlowSource {
|
class GitHubCtxSource extends RemoteFlowSource {
|
||||||
string flag;
|
string flag;
|
||||||
string event;
|
string event;
|
||||||
GitHubExpression e;
|
|
||||||
|
|
||||||
GitHubCtxSource() {
|
GitHubCtxSource() {
|
||||||
this.asExpr() = e and
|
exists(GitHubExpression e |
|
||||||
// github.head_ref
|
this.asExpr() = e and
|
||||||
e.getFieldName() = "head_ref" and
|
// github.head_ref
|
||||||
flag = "branch" and
|
e.getFieldName() = "head_ref" and
|
||||||
(
|
flag = "branch"
|
||||||
|
|
|
||||||
event = e.getATriggerEvent().getName() and
|
event = e.getATriggerEvent().getName() and
|
||||||
event = "pull_request_target"
|
event = "pull_request_target"
|
||||||
or
|
or
|
||||||
@@ -148,7 +148,6 @@ class GhCLICommandSource extends RemoteFlowSource, CommandSource {
|
|||||||
class GitHubEventPathSource extends RemoteFlowSource, CommandSource {
|
class GitHubEventPathSource extends RemoteFlowSource, CommandSource {
|
||||||
string cmd;
|
string cmd;
|
||||||
string flag;
|
string flag;
|
||||||
string access_path;
|
|
||||||
Run run;
|
Run run;
|
||||||
|
|
||||||
// Examples
|
// Examples
|
||||||
@@ -163,7 +162,7 @@ class GitHubEventPathSource extends RemoteFlowSource, CommandSource {
|
|||||||
run.getScript().getACommand() = cmd and
|
run.getScript().getACommand() = cmd and
|
||||||
cmd.matches("jq%") and
|
cmd.matches("jq%") and
|
||||||
cmd.matches("%GITHUB_EVENT_PATH%") and
|
cmd.matches("%GITHUB_EVENT_PATH%") and
|
||||||
exists(string regexp |
|
exists(string regexp, string access_path |
|
||||||
untrustedEventPropertiesDataModel(regexp, flag) and
|
untrustedEventPropertiesDataModel(regexp, flag) and
|
||||||
not flag = "json" and
|
not flag = "json" and
|
||||||
access_path = "github.event" + cmd.regexpCapture(".*\\s+([^\\s]+)\\s+.*", 1) and
|
access_path = "github.event" + cmd.regexpCapture(".*\\s+([^\\s]+)\\s+.*", 1) and
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ abstract class ArgumentInjectionSink extends DataFlow::Node {
|
|||||||
*/
|
*/
|
||||||
class ArgumentInjectionFromEnvVarSink extends ArgumentInjectionSink {
|
class ArgumentInjectionFromEnvVarSink extends ArgumentInjectionSink {
|
||||||
string command;
|
string command;
|
||||||
string argument;
|
|
||||||
|
|
||||||
ArgumentInjectionFromEnvVarSink() {
|
ArgumentInjectionFromEnvVarSink() {
|
||||||
exists(Run run, string var |
|
exists(Run run, string var |
|
||||||
@@ -28,7 +27,7 @@ class ArgumentInjectionFromEnvVarSink extends ArgumentInjectionSink {
|
|||||||
exists(run.getInScopeEnvVarExpr(var)) or
|
exists(run.getInScopeEnvVarExpr(var)) or
|
||||||
var = "GITHUB_HEAD_REF"
|
var = "GITHUB_HEAD_REF"
|
||||||
) and
|
) and
|
||||||
run.getScript().getAnEnvReachingArgumentInjectionSink(var, command, argument)
|
run.getScript().getAnEnvReachingArgumentInjectionSink(var, command, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,13 +43,12 @@ class ArgumentInjectionFromEnvVarSink extends ArgumentInjectionSink {
|
|||||||
*/
|
*/
|
||||||
class ArgumentInjectionFromCommandSink extends ArgumentInjectionSink {
|
class ArgumentInjectionFromCommandSink extends ArgumentInjectionSink {
|
||||||
string command;
|
string command;
|
||||||
string argument;
|
|
||||||
|
|
||||||
ArgumentInjectionFromCommandSink() {
|
ArgumentInjectionFromCommandSink() {
|
||||||
exists(CommandSource source, Run run |
|
exists(CommandSource source, Run run |
|
||||||
run = source.getEnclosingRun() and
|
run = source.getEnclosingRun() and
|
||||||
this.asExpr() = run.getScript() and
|
this.asExpr() = run.getScript() and
|
||||||
run.getScript().getACmdReachingArgumentInjectionSink(source.getCommand(), command, argument)
|
run.getScript().getACmdReachingArgumentInjectionSink(source.getCommand(), command, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,8 +125,6 @@ class LegitLabsDownloadArtifactActionStep extends UntrustedArtifactDownloadStep,
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ActionsGitHubScriptDownloadStep extends UntrustedArtifactDownloadStep, UsesStep {
|
class ActionsGitHubScriptDownloadStep extends UntrustedArtifactDownloadStep, UsesStep {
|
||||||
string script;
|
|
||||||
|
|
||||||
ActionsGitHubScriptDownloadStep() {
|
ActionsGitHubScriptDownloadStep() {
|
||||||
// eg:
|
// eg:
|
||||||
// - uses: actions/github-script@v6
|
// - uses: actions/github-script@v6
|
||||||
@@ -149,12 +147,14 @@ class ActionsGitHubScriptDownloadStep extends UntrustedArtifactDownloadStep, Use
|
|||||||
// var fs = require('fs');
|
// var fs = require('fs');
|
||||||
// fs.writeFileSync('${{github.workspace}}/test-results.zip', Buffer.from(download.data));
|
// fs.writeFileSync('${{github.workspace}}/test-results.zip', Buffer.from(download.data));
|
||||||
this.getCallee() = "actions/github-script" and
|
this.getCallee() = "actions/github-script" and
|
||||||
this.getArgument("script") = script and
|
exists(string script |
|
||||||
script.matches("%listWorkflowRunArtifacts(%") and
|
this.getArgument("script") = script and
|
||||||
script.matches("%downloadArtifact(%") and
|
script.matches("%listWorkflowRunArtifacts(%") and
|
||||||
script.matches("%writeFileSync(%") and
|
script.matches("%downloadArtifact(%") and
|
||||||
// Filter out artifacts that were created by pull-request.
|
script.matches("%writeFileSync(%") and
|
||||||
not script.matches("%exclude_pull_requests: true%")
|
// Filter out artifacts that were created by pull-request.
|
||||||
|
not script.matches("%exclude_pull_requests: true%")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override string getPath() {
|
override string getPath() {
|
||||||
@@ -171,10 +171,10 @@ class ActionsGitHubScriptDownloadStep extends UntrustedArtifactDownloadStep, Use
|
|||||||
.getScript()
|
.getScript()
|
||||||
.getACommand()
|
.getACommand()
|
||||||
.regexpCapture(unzipRegexp() + unzipDirArgRegexp(), 3)))
|
.regexpCapture(unzipRegexp() + unzipDirArgRegexp(), 3)))
|
||||||
else
|
else (
|
||||||
if this.getAFollowingStep().(Run).getScript().getACommand().regexpMatch(unzipRegexp())
|
this.getAFollowingStep().(Run).getScript().getACommand().regexpMatch(unzipRegexp()) and
|
||||||
then result = "GITHUB_WORKSPACE/"
|
result = "GITHUB_WORKSPACE/"
|
||||||
else none()
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,12 +207,13 @@ class GHRunArtifactDownloadStep extends UntrustedArtifactDownloadStep, Run {
|
|||||||
.getScript()
|
.getScript()
|
||||||
.getACommand()
|
.getACommand()
|
||||||
.regexpCapture(unzipRegexp() + unzipDirArgRegexp(), 3)))
|
.regexpCapture(unzipRegexp() + unzipDirArgRegexp(), 3)))
|
||||||
else
|
else (
|
||||||
if
|
(
|
||||||
this.getAFollowingStep().(Run).getScript().getACommand().regexpMatch(unzipRegexp()) or
|
this.getAFollowingStep().(Run).getScript().getACommand().regexpMatch(unzipRegexp()) or
|
||||||
this.getScript().getACommand().regexpMatch(unzipRegexp())
|
this.getScript().getACommand().regexpMatch(unzipRegexp())
|
||||||
then result = "GITHUB_WORKSPACE/"
|
) and
|
||||||
else none()
|
result = "GITHUB_WORKSPACE/"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,15 +260,15 @@ class DirectArtifactDownloadStep extends UntrustedArtifactDownloadStep, Run {
|
|||||||
|
|
||||||
class ArtifactPoisoningSink extends DataFlow::Node {
|
class ArtifactPoisoningSink extends DataFlow::Node {
|
||||||
UntrustedArtifactDownloadStep download;
|
UntrustedArtifactDownloadStep download;
|
||||||
PoisonableStep poisonable;
|
|
||||||
|
|
||||||
ArtifactPoisoningSink() {
|
ArtifactPoisoningSink() {
|
||||||
download.getAFollowingStep() = poisonable and
|
exists(PoisonableStep poisonable |
|
||||||
// excluding artifacts downloaded to the temporary directory
|
download.getAFollowingStep() = poisonable and
|
||||||
not download.getPath().regexpMatch("^/tmp.*") and
|
// excluding artifacts downloaded to the temporary directory
|
||||||
not download.getPath().regexpMatch("^\\$\\{\\{\\s*runner\\.temp\\s*}}.*") and
|
not download.getPath().regexpMatch("^/tmp.*") and
|
||||||
not download.getPath().regexpMatch("^\\$RUNNER_TEMP.*") and
|
not download.getPath().regexpMatch("^\\$\\{\\{\\s*runner\\.temp\\s*}}.*") and
|
||||||
(
|
not download.getPath().regexpMatch("^\\$RUNNER_TEMP.*")
|
||||||
|
|
|
||||||
poisonable.(Run).getScript() = this.asExpr() and
|
poisonable.(Run).getScript() = this.asExpr() and
|
||||||
(
|
(
|
||||||
// Check if the poisonable step is a local script execution step
|
// Check if the poisonable step is a local script execution step
|
||||||
|
|||||||
@@ -159,11 +159,8 @@ abstract class CommentVsHeadDateCheck extends ControlCheck {
|
|||||||
|
|
||||||
/* Specific implementations of control checks */
|
/* Specific implementations of control checks */
|
||||||
class LabelIfCheck extends LabelCheck instanceof If {
|
class LabelIfCheck extends LabelCheck instanceof If {
|
||||||
string condition;
|
|
||||||
|
|
||||||
LabelIfCheck() {
|
LabelIfCheck() {
|
||||||
condition = normalizeExpr(this.getCondition()) and
|
exists(string condition | condition = normalizeExpr(this.getCondition()) |
|
||||||
(
|
|
||||||
// eg: contains(github.event.pull_request.labels.*.name, 'safe to test')
|
// eg: contains(github.event.pull_request.labels.*.name, 'safe to test')
|
||||||
condition.regexpMatch(".*(^|[^!])contains\\(\\s*github\\.event\\.pull_request\\.labels\\b.*")
|
condition.regexpMatch(".*(^|[^!])contains\\(\\s*github\\.event\\.pull_request\\.labels\\b.*")
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -55,12 +55,8 @@ class EnvVarInjectionFromFileReadSink extends EnvVarInjectionSink {
|
|||||||
* echo "COMMIT_MESSAGE=${COMMIT_MESSAGE}" >> $GITHUB_ENV
|
* echo "COMMIT_MESSAGE=${COMMIT_MESSAGE}" >> $GITHUB_ENV
|
||||||
*/
|
*/
|
||||||
class EnvVarInjectionFromCommandSink extends EnvVarInjectionSink {
|
class EnvVarInjectionFromCommandSink extends EnvVarInjectionSink {
|
||||||
CommandSource inCommand;
|
|
||||||
string injectedVar;
|
|
||||||
string command;
|
|
||||||
|
|
||||||
EnvVarInjectionFromCommandSink() {
|
EnvVarInjectionFromCommandSink() {
|
||||||
exists(Run run |
|
exists(Run run, CommandSource inCommand, string injectedVar, string command |
|
||||||
this.asExpr() = inCommand.getEnclosingRun().getScript() and
|
this.asExpr() = inCommand.getEnclosingRun().getScript() and
|
||||||
run = inCommand.getEnclosingRun() and
|
run = inCommand.getEnclosingRun() and
|
||||||
run.getScript().getACmdReachingGitHubEnvWrite(inCommand.getCommand(), injectedVar) and
|
run.getScript().getACmdReachingGitHubEnvWrite(inCommand.getCommand(), injectedVar) and
|
||||||
@@ -86,12 +82,8 @@ class EnvVarInjectionFromCommandSink extends EnvVarInjectionSink {
|
|||||||
* echo "FOO=$BODY" >> $GITHUB_ENV
|
* echo "FOO=$BODY" >> $GITHUB_ENV
|
||||||
*/
|
*/
|
||||||
class EnvVarInjectionFromEnvVarSink extends EnvVarInjectionSink {
|
class EnvVarInjectionFromEnvVarSink extends EnvVarInjectionSink {
|
||||||
string inVar;
|
|
||||||
string injectedVar;
|
|
||||||
string command;
|
|
||||||
|
|
||||||
EnvVarInjectionFromEnvVarSink() {
|
EnvVarInjectionFromEnvVarSink() {
|
||||||
exists(Run run |
|
exists(Run run, string inVar, string injectedVar, string command |
|
||||||
run.getScript() = this.asExpr() and
|
run.getScript() = this.asExpr() and
|
||||||
exists(run.getInScopeEnvVarExpr(inVar)) and
|
exists(run.getInScopeEnvVarExpr(inVar)) and
|
||||||
run.getScript().getAnEnvReachingGitHubEnvWrite(inVar, injectedVar) and
|
run.getScript().getAnEnvReachingGitHubEnvWrite(inVar, injectedVar) and
|
||||||
|
|||||||
@@ -99,18 +99,14 @@ class OutputClobberingFromEnvVarSink extends OutputClobberingSink {
|
|||||||
* echo $BODY
|
* echo $BODY
|
||||||
*/
|
*/
|
||||||
class WorkflowCommandClobberingFromEnvVarSink extends OutputClobberingSink {
|
class WorkflowCommandClobberingFromEnvVarSink extends OutputClobberingSink {
|
||||||
string clobbering_var;
|
|
||||||
string clobbered_value;
|
|
||||||
|
|
||||||
WorkflowCommandClobberingFromEnvVarSink() {
|
WorkflowCommandClobberingFromEnvVarSink() {
|
||||||
exists(Run run, string workflow_cmd_stmt, string clobbering_stmt |
|
exists(Run run, string workflow_cmd_stmt, string clobbering_stmt, string clobbering_var |
|
||||||
run.getScript() = this.asExpr() and
|
run.getScript() = this.asExpr() and
|
||||||
run.getScript().getAStmt() = clobbering_stmt and
|
run.getScript().getAStmt() = clobbering_stmt and
|
||||||
clobbering_stmt.regexpMatch("echo\\s+(-e\\s+)?(\"|')?\\$(\\{)?" + clobbering_var + ".*") and
|
clobbering_stmt.regexpMatch("echo\\s+(-e\\s+)?(\"|')?\\$(\\{)?" + clobbering_var + ".*") and
|
||||||
exists(run.getInScopeEnvVarExpr(clobbering_var)) and
|
exists(run.getInScopeEnvVarExpr(clobbering_var)) and
|
||||||
run.getScript().getAStmt() = workflow_cmd_stmt and
|
run.getScript().getAStmt() = workflow_cmd_stmt and
|
||||||
clobbered_value =
|
exists(trimQuotes(workflow_cmd_stmt.regexpCapture(".*::set-output\\s+name=.*::(.*)", 1)))
|
||||||
trimQuotes(workflow_cmd_stmt.regexpCapture(".*::set-output\\s+name=.*::(.*)", 1))
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import actions
|
import actions
|
||||||
|
|
||||||
class UnversionedImmutableAction extends UsesStep {
|
class UnversionedImmutableAction extends UsesStep {
|
||||||
string immutable_action;
|
|
||||||
|
|
||||||
UnversionedImmutableAction() {
|
UnversionedImmutableAction() {
|
||||||
isImmutableAction(this, immutable_action) and
|
isImmutableAction(this, _) and
|
||||||
not isSemVer(this.getVersion())
|
not isSemVer(this.getVersion())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ where
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// upload artifact is not used in the same workflow
|
// upload artifact is not used in the same workflow
|
||||||
not exists(UsesStep upload |
|
not download.getEnclosingWorkflow().getAJob().(LocalJob).getAStep() instanceof UsesStep
|
||||||
download.getEnclosingWorkflow().getAJob().(LocalJob).getAStep() = upload
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
select download, "Potential artifact poisoning"
|
select download, "Potential artifact poisoning"
|
||||||
|
|||||||
Reference in New Issue
Block a user