Web · Methodology

Hunting RCE in Modern Stacks

Aug 2026 · 9 min read · Imperonlabs Research

Direct OS command injection still exists, but the modern remote-code-execution surface has moved. The bugs that land today come from the abstractions we added on top of the language — template engines, serializers, parsers, and package managers. This is where we hunt.

Server-side template injection (SSTI)

Any place user input is concatenated into a server-side template is a candidate. The tell is a mathematical payload rendering: submit {{7*7}} (Jinja/Twig), ${7*7} (FreeMarker/Spring EL), #{7*7} (Ruby), <%= 7*7 %> (ERB). A reflected 49 means you're inside the engine, not just the HTML.

  • Find the injection in anything that gets rendered back: display names, email templates, PDF/report generators, error pages, "custom message" fields, admin-configurable copy.
  • Fingerprint the engine (each has distinct syntax and error strings), then walk the documented sandbox-escape chain for that engine to reach Runtime.exec / os.system / subprocess.
  • The highest-value SSTI is in template features exposed to low-privilege users — a "customize your notification" box that turns out to be a live template.

Insecure deserialization

When a server rebuilds an object from attacker-controlled bytes, a gadget chain can turn "load this object" into "run this code." Look for:

  • Serialized blobs in cookies, hidden fields, caches, and message queues — Java (rO0 base64, AC ED 00 05 magic), .NET (ViewState, BinaryFormatter), Python (pickle), Ruby (Marshal), PHP (O: in unserialize), and Node (node-serialize).
  • The move: identify the framework, then reach for the known gadget chains present in its dependency tree. The vulnerability is deserializing untrusted input at all; the gadget is just the delivery.

Dependency and build-chain RCE

Increasingly, the code you run is code you didn't write:

  • Dependency confusion — an internal package name that isn't claimed on the public registry lets an attacker publish a malicious public version the build pulls instead.
  • Lockfile and CI injection — a postinstall script, a poisoned dependency, or an injectable build variable that runs in the pipeline. CI runs with credentials; RCE in the build is RCE in production's supply chain.
  • Known-vuln dependencies — an outdated parser/serializer/image library with a public RCE. Fingerprint versions from behavior and error strings, then match to advisories.

File-processing pipelines

Anywhere an upload is parsed rather than merely stored:

  • Image/media libraries (ImageMagick-style delegate abuse, ffmpeg, PDF renderers) that shell out or resolve remote resources.
  • Document parsers — Office/XML with external entity and macro-adjacent processing; SVG that reaches template or script contexts.
  • Archive handling — path traversal on extraction (../../) that writes a file into a code path that later executes (a webshell into the web root, a cron/config file, an overwritten binary).

The methodology, compressed

  1. Inventory every parser and renderer the input touches — templates, serializers, media/doc processors, archive extractors, the dependency graph.
  2. Fingerprint the exact engine/library and version.
  3. Prove execution with the most benign primitive — a DNS callback from the target, a sleep that measures, a id/whoami echoed once. Never a shell, never persistence, never lateral movement on someone else's box.
  4. Stop at proof. One out-of-band ping that only your infrastructure sees is a complete, undeniable demonstration of RCE. Everything past it is risk with no added value.

Modern RCE is rarely a ; in a parameter. It's trusting attacker bytes at a layer that was powerful enough to run them. Find the powerful layer, and the input that reaches it.