Summary
The main_matrix.yml workflow is triggered by pull_request_target (line 19) and multiple jobs check out the attacker's fork code and execute it with access to repository secrets and elevated GITHUB_TOKEN permissions.
No approval gate exists - I verified that PRs from external users with author_association: "NONE" triggered the CI workflow automatically.
This is not a command injection vulnerability - the workflow directly executes attacker-controlled files from the fork checkout.
Note: I reproduced the vulnerability in a replica environment. I did not attempt to exploit this on the meshtastic/firmware repository. POC video available here.
Vulnerable Flows
Flow 1 - build-debian-src job (via build_debian_src.yml lines 27-42) - Supply Chain (GPG Key)
Called with secrets: inherit, which passes all repository secrets. Checks out the fork and runs mk-build-deps against attacker-controlled debian/control, with PPA_GPG_PRIVATE_KEY available in the environment.
Impact: An attacker can exfiltrate PPA_GPG_PRIVATE_KEY - the GPG key used to sign Debian packages for the Meshtastic PPA - and sign and distribute malicious firmware packages to all users who install via apt.
Flow 2 - check job (main_matrix.yml lines 87-98) - Self-Hosted Runner
Checks out the fork and runs meshtastic/gh-action-firmware@main, a Docker action that executes /workspace/bin/check-all.sh from the checked-out code. Runs on self-hosted arctastic runners.
Impact: Attacker code executes on persistent self-hosted runners. Unlike ephemeral GitHub-hosted runners, backdoors can survive between workflow runs, access cached credentials, or pivot to internal network resources.
Flow 3 - build job (via build_firmware.yml lines 26-34) - Self-Hosted Runner
Same fork checkout pattern, also on self-hosted arctastic runners. Executes meshtastic/gh-action-firmware@main which runs attacker-controlled build scripts.
Flow 4 - gather-artifacts job (main_matrix.yml lines 174-178)
Checks out the fork with explicit permissions: contents: write, pull-requests: write. This grants the attacker a GITHUB_TOKEN that can push commits directly to any branch (including master) and modify releases, enabling repository takeover.
PoC
- Attacker forks meshtastic/firmware
- Replaces bin/check-all.sh (or any build script) with a malicious payload
- Opens a pull request to meshtastic/firmware
- The pull_request_target workflow triggers automatically - no approval required
- The workflow checks out the attacker's fork and executes the malicious code with access to all repository secrets
Impact
Supply Chain Compromise: PPA_GPG_PRIVATE_KEY - the GPG key used to sign Debian packages for the Meshtastic PPA. An attacker could sign and distribute malicious firmware packages to all users who install Meshtastic via apt. DIST_PAGES_DEPLOY_KEY - deploy key for meshtastic/meshtastic.github.io, used to publish firmware binaries (see publish-firmware job, line 482). An attacker could replace legitimate firmware downloads with backdoored versions.
Self-Hosted Runner Compromise: The check and build jobs run on self-hosted arctastic runners. These are persistent machines - an attacker could install backdoors that survive between workflow runs, access cached credentials, or pivot to internal network resources. GitHub explicitly warns against using self-hosted runners with public repositories for this reason.
Repository Takeover: The gather-artifacts job grants a GITHUB_TOKEN with contents: write permissions, allowing an attacker to push commits to any branch (including master), create or modify releases, and take full control of the repository.
Note that a previous advisory addressed a command injection via github.head_ref in the setup job of the same workflow. That fix correctly moved to environment variables. However, the more critical fork checkout vulnerability across the check, build, and build-debian-src jobs was not addressed.
Summary
The main_matrix.yml workflow is triggered by pull_request_target (line 19) and multiple jobs check out the attacker's fork code and execute it with access to repository secrets and elevated GITHUB_TOKEN permissions.
No approval gate exists - I verified that PRs from external users with author_association: "NONE" triggered the CI workflow automatically.
This is not a command injection vulnerability - the workflow directly executes attacker-controlled files from the fork checkout.
Note: I reproduced the vulnerability in a replica environment. I did not attempt to exploit this on the meshtastic/firmware repository. POC video available here.
Vulnerable Flows
Flow 1 - build-debian-src job (via build_debian_src.yml lines 27-42) - Supply Chain (GPG Key)
Called with secrets: inherit, which passes all repository secrets. Checks out the fork and runs mk-build-deps against attacker-controlled debian/control, with PPA_GPG_PRIVATE_KEY available in the environment.
Impact: An attacker can exfiltrate PPA_GPG_PRIVATE_KEY - the GPG key used to sign Debian packages for the Meshtastic PPA - and sign and distribute malicious firmware packages to all users who install via apt.
Flow 2 - check job (main_matrix.yml lines 87-98) - Self-Hosted Runner
Checks out the fork and runs meshtastic/gh-action-firmware@main, a Docker action that executes /workspace/bin/check-all.sh from the checked-out code. Runs on self-hosted arctastic runners.
Impact: Attacker code executes on persistent self-hosted runners. Unlike ephemeral GitHub-hosted runners, backdoors can survive between workflow runs, access cached credentials, or pivot to internal network resources.
Flow 3 - build job (via build_firmware.yml lines 26-34) - Self-Hosted Runner
Same fork checkout pattern, also on self-hosted arctastic runners. Executes meshtastic/gh-action-firmware@main which runs attacker-controlled build scripts.
Flow 4 - gather-artifacts job (main_matrix.yml lines 174-178)
Checks out the fork with explicit permissions: contents: write, pull-requests: write. This grants the attacker a GITHUB_TOKEN that can push commits directly to any branch (including master) and modify releases, enabling repository takeover.
PoC
Impact
Supply Chain Compromise: PPA_GPG_PRIVATE_KEY - the GPG key used to sign Debian packages for the Meshtastic PPA. An attacker could sign and distribute malicious firmware packages to all users who install Meshtastic via apt. DIST_PAGES_DEPLOY_KEY - deploy key for meshtastic/meshtastic.github.io, used to publish firmware binaries (see publish-firmware job, line 482). An attacker could replace legitimate firmware downloads with backdoored versions.
Self-Hosted Runner Compromise: The check and build jobs run on self-hosted arctastic runners. These are persistent machines - an attacker could install backdoors that survive between workflow runs, access cached credentials, or pivot to internal network resources. GitHub explicitly warns against using self-hosted runners with public repositories for this reason.
Repository Takeover: The gather-artifacts job grants a GITHUB_TOKEN with contents: write permissions, allowing an attacker to push commits to any branch (including master), create or modify releases, and take full control of the repository.
Note that a previous advisory addressed a command injection via github.head_ref in the setup job of the same workflow. That fix correctly moved to environment variables. However, the more critical fork checkout vulnerability across the check, build, and build-debian-src jobs was not addressed.