# How to hack Github Actions

Researcher injected shellcode into GitHub Actions' closed-source Virtual Environment Provisioner and used Harmony to disable its miner/malware detection hooks.

- Payout: $500
- Severity: medium
- Program: GitHub
- Credited: StackOverflowExcept1on
- Disclosed: 2022-09-19
- Write-up quality: 8/10
- Original: https://github.com/StackOverflowExcept1on/how-to-hack-github-actions
- Library page: https://bugbountylibrary.com/r/blog%3Agithub-com-stackoverflowexcept1on-how-to-hack-github-actions
- Tags: domain:cloud domain:infra impact:integrity kind:bounty platform:blog sev:medium tech:ci-cd tech:dotnet tech:windows technique:reverse-engineering technique:source-review vuln:misconfiguration vuln:privilege-escalation

**Target:** Virtual Environment Provisioner (provisioner.exe) on windows-latest runner VMs
**Root cause:** provisioner.exe runs as runneradmin in the same session as user scripts with no isolation, so a workflow can OpenProcess/VirtualAllocEx/WriteProcessMemory/CreateRemoteThread into it and hook .NET methods via Harmony.
**Steps:**
1. Workflow copies C:\actions\runner-provisioner-Windows to artifacts to obtain provisioner.exe and DLLs
2. Decompile with dnSpyEx to identify SuspiciousFilesMonitorJob, ProcessMonitorJob, ScriptTaskValidator, MachineManagementClient
3. Find provisioner.exe PID via CreateToolhelp32Snapshot/Process32NextW, OpenProcess, VirtualAllocEx, WriteProcessMemory, CreateRemoteThread
4. In injected code, resolve hostfxr_get_runtime_properties export, scan bytes for 2nd `0xE8` call opcode, compute fx_muxer_t::get_active_host_context address as `instructionAddress + *(DWORD*)buf + 5`
5. Call get_active_host_context, hostfxr_get_runtime_delegate, load_assembly_and_get_function_pointer_fn to load a C# assembly with [UnmanagedCallersOnly] entrypoint
6. Use Harmony [HarmonyPrefix]/[HarmonyPostfix] to patch SuspiciousSignatureExists to return false, HasBadParamOrArgument to return false, and ReportSuspiciousActivityAsync to no-op
7. Run miner/trojan in workflow; provisioner no longer flags or reports it
**How found:** Read a blog about crypto-mining via PRs, wondered how GitHub detects it, stole provisioner.exe via workflow artifacts, reverse-engineered with dnSpyEx, and noticed it runs unisolated as runneradmin — leading to the injection hypothesis.
**Exploitation:** Any workflow on windows-latest can inject into the co-resident provisioner process and neuter its monitoring, allowing crypto-mining or malware execution without triggering GitHub's abuse detection or VM termination.
**Escalation:** Chaining file-scan bypass + process-arg bypass + suspicious-activity reporting suppression yields full evasion of the provisioner security system.
**Insight:** On hosted CI runners, look for privileged monitoring agents running in the same user session as the job; if they're .NET, hostfxr_get_runtime_properties' second call opcode reveals the non-exported get_active_host_context needed to bootstrap a managed injector.
