Add workflow to expand telemetry tags from PR command#9435
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7a8f9869-e5db-4403-8bc3-29200827dcf6
| - name: Checkout PR head | ||
| if: steps.context.outputs.authorized == 'True' | ||
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | ||
| with: | ||
| repository: ${{ steps.context.outputs.headRepo }} | ||
| ref: ${{ steps.context.outputs.headRef }} | ||
| path: pr | ||
|
|
||
| - name: Expand telemetry tags |
|
Could not find a linked ADO work item. Please link one by using the pattern 'AB#' followed by the relevant work item number. You may use the 'Fixes' keyword to automatically resolve the work item when the pull request is merged. E.g. 'Fixes AB#1234' |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7a8f9869-e5db-4403-8bc3-29200827dcf6
Copilot PR ReviewIteration 2 · Outcome: completed
Knowledge source: https://github.com/microsoft/BCQuality@809af9708e265f110ced6752fd8f2e40f1efc820 Findings by domainFindings split into Knowledge-backed (cite a BCQuality article) and Agent (the agent's own judgement, no matching BCQuality rule).
Totals: 0 knowledge-backed · 1 agent findings. Orchestrator pre-filter (2 file(s) excluded)
Findings produced by the Copilot CLI agent against BCQuality at |
| } | ||
| "updated" { | ||
| if ("${{ steps.push.outputs.pushed }}" -eq "true") { | ||
| $comment = "Telemetry tags were updated and pushed to `${{ steps.context.outputs.headRef }}` ✅" |
There was a problem hiding this comment.
Note on true severity: the underlying impact of this finding is a critical/blocker-grade CI supply-chain vulnerability; it is capped to 'minor' here only because no BCQuality knowledge file backs it (agent-finding rule), not because the real risk is low - it should be triaged as a blocker and a corresponding knowledge article should be authored.
Important scoping note: this review was asked to diff against origin/main, but the PR branch (HEAD) is 26 commits behind origin/main and only 2 commits ahead of the merge-base (f7f34ab). A raw 'git diff origin/main' therefore shows ~285 unrelated files (a Job->Project rename, several unrelated bugfix reverts, etc.) that are just divergence noise from the stale base, not part of this PR. The actual PR content, diffed against the merge-base, is a single new file: .github/workflows/ExpandTelemetryTagsFromPRComment.yaml (304 lines), which adds a maintainer-triggered '/telemetry-tags' comment workflow with 'contents: write' and 'issues: write' permissions. In the 'Comment result on PR' step, several GitHub Actions '${{ }}' expressions whose values are attacker-controlled are interpolated directly into the PowerShell run: script text instead of being passed through env: variables (the safe pattern the same workflow already uses elsewhere, e.g. HEAD_REF in the 'Commit and push updates' step). Specifically: '${{ steps.context.outputs.headRef }}' (the PR's head branch name, which is fully attacker-chosen by whoever opens the PR - git ref names permit backticks, double quotes, '$', and parentheses) is embedded inside a double-quoted PowerShell string, and '${{ steps.expand.outputs.errorMessage }}' (a raw exception .Message that can originate from processing attacker-supplied .al file content checked out from the PR) is embedded inside a PowerShell here-string. Because GitHub Actions performs textual substitution of these expressions before the script runs, a PR author can choose a branch name or craft file content that breaks out of the surrounding string/here-string and injects arbitrary PowerShell that executes in this job's context - which holds 'GH_TOKEN: ${{ github.token }}' with 'contents: write' and 'issues: write'. The exploit fires as soon as any maintainer (who is otherwise trusted and simply runs the intended '/telemetry-tags' command on the attacker's PR) triggers the workflow; the authorization check only gates who can invoke the command, it does not sanitize the untrusted headRef/errorMessage values that are later interpolated. This is the classic GitHub Actions 'script injection via untrusted input' / pwn-request pattern and would let an external contributor push arbitrary commits or exfiltrate the workflow token.
Recommendation:
- pass every value derived from PR-controlled data (head ref, exception messages, file paths/content, comment bodies, etc.) into the run: step exclusively via the env: block (as already done correctly for HEAD_REF in the push step) and reference it only as
$env:VarName inside the script; never interpolate '$ {{ ... }}' expressions carrying such data directly into run: script text.
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why
Summary
Validation