@@ -92,6 +92,69 @@ class OutputClobberingFromEnvVarSink extends OutputClobberingSink {
9292 }
9393}
9494
95+ /**
96+ * - id: clob1
97+ * env:
98+ * BODY: ${{ github.event.comment.body }}
99+ * run: |
100+ * # VULNERABLE
101+ * echo $BODY
102+ * echo "::set-output name=OUTPUT::SAFE"
103+ * - id: clob2
104+ * env:
105+ * BODY: ${{ github.event.comment.body }}
106+ * run: |
107+ * # VULNERABLE
108+ * echo "::set-output name=OUTPUT::SAFE"
109+ * echo $BODY
110+ */
111+ class WorkflowCommandClobberingFromEnvVarSink extends OutputClobberingSink {
112+ WorkflowCommandClobberingFromEnvVarSink ( ) {
113+ exists ( Run run , string output_line , string clobbering_line , string var_name |
114+ run .getScript ( ) .splitAt ( "\n" ) = output_line and
115+ singleLineWorkflowCmd ( output_line , "set-output" , _, _) and
116+ run .getScript ( ) .splitAt ( "\n" ) = clobbering_line and
117+ clobbering_line .regexpMatch ( ".*echo\\s+(-e\\s+)?(\"|')?\\$(\\{)?" + var_name + ".*" ) and
118+ exists ( run .getInScopeEnvVarExpr ( var_name ) ) and
119+ run .getScriptScalar ( ) = this .asExpr ( )
120+ )
121+ }
122+ }
123+
124+ class WorkflowCommandClobberingFromFileReadSink extends OutputClobberingSink {
125+ WorkflowCommandClobberingFromFileReadSink ( ) {
126+ exists ( Run run , string output_line , string clobbering_line |
127+ run .getScriptScalar ( ) = this .asExpr ( ) and
128+ run .getScript ( ) .splitAt ( "\n" ) = output_line and
129+ singleLineWorkflowCmd ( output_line , "set-output" , _, _) and
130+ run .getScript ( ) .splitAt ( "\n" ) = clobbering_line and
131+ (
132+ // A file is read and its content is assigned to an env var that gets printed to stdout
133+ // - run: |
134+ // foo=$(<pr-id.txt)"
135+ // echo "${foo}"
136+ exists ( string var_name , string value , string assign_line , string assignment_regexp |
137+ run .getScript ( ) .splitAt ( "\n" ) = assign_line and
138+ assignment_regexp = "([a-zA-Z0-9\\-_]+)=(.*)" and
139+ var_name = assign_line .regexpCapture ( assignment_regexp , 1 ) and
140+ value = assign_line .regexpCapture ( assignment_regexp , 2 ) and
141+ outputsPartialFileContent ( trimQuotes ( value ) ) and
142+ clobbering_line .regexpMatch ( ".*echo\\s+(-e\\s+)?(\"|')?\\$(\\{)?" + var_name + ".*" )
143+ )
144+ or
145+ // A file is read and its content is printed to stdout
146+ // - run: echo "foo=$(<pr-id.txt)"
147+ clobbering_line .regexpMatch ( ".*echo\\s+(-e)?\\s*(\"|')?" ) and
148+ clobbering_line .regexpMatch ( partialFileContentRegexp ( ) + ".*" )
149+ or
150+ // A file content is printed to stdout
151+ // - run: cat pr-id.txt
152+ clobbering_line .regexpMatch ( partialFileContentRegexp ( ) + ".*" )
153+ )
154+ )
155+ }
156+ }
157+
95158class OutputClobberingFromMaDSink extends OutputClobberingSink {
96159 OutputClobberingFromMaDSink ( ) { madSink ( this , "output-clobbering" ) }
97160}
0 commit comments