Injection Attacks: RCE, Command Injection & XXE
How command injection and XXE actually lead to remote code execution — and what genuinely prevents each one.
Remote Code Execution: The Outcome, Not a Single Technique
Remote Code Execution (RCE) isn't itself a specific vulnerability — it's the outcome that several different vulnerability types (command injection, XXE, insecure deserialization, certain file inclusion chains) can all lead to when successfully exploited. RCE is treated as close to the maximum-severity finding in almost any vulnerability scoring system because it typically gives an attacker the same level of control over the server that the running application process itself has — reading and modifying files, accessing databases, pivoting to other systems on the same network, or using the compromised server as a launch point for further attacks.
Understanding RCE as an outcome rather than a technique matters practically: defending against it means addressing each of the specific mechanisms that can lead to it, rather than looking for a single unified fix. Command injection and XXE, covered below, are two of the most common paths to RCE in modern web applications.
Command Injection: When User Input Reaches a System Shell
Command injection happens when an application passes user-supplied input into a function that executes operating system commands, without properly separating the intended command from attacker-controlled data. Many programming languages provide convenience functions that hand a string directly to the system shell for execution — useful for legitimate tasks like running an image-conversion utility or checking network connectivity — but if any part of that string comes from user input without proper handling, an attacker can append additional shell operators (like a semicolon or pipe) to chain in entirely separate commands of their own choosing.
The canonical illustration: an application that runs a network diagnostic tool against a user-supplied hostname, building a command string like ping [hostname]. If the hostname parameter isn't properly isolated from the rest of the command, an attacker supplying a value like example.com; cat /etc/passwd causes the shell to interpret the semicolon as a command separator, running the attacker's second command immediately after the intended one. This exact pattern — a "ping" or "traceroute" style diagnostic feature — remains one of the most common real-world sources of command injection precisely because it feels like such an innocuous feature to build.
Why Command Injection Is So Persistently Common
Despite being one of the longest-known vulnerability classes in web security, command injection continues to appear in current applications for a specific, structural reason: many languages make shelling out to run a system command genuinely easy, while making it correctly and safely just as easy to get subtly wrong. Escaping shell metacharacters correctly varies by operating system and shell, is easy to overlook for edge cases, and a single missed character in an escaping function can reopen the entire vulnerability — which is why security guidance consistently recommends avoiding shell invocation entirely rather than trying to sanitize input into it safely.
The safer alternative most modern language standard libraries provide: functions that execute a specific program directly with an argument array, rather than constructing a single string interpreted by a shell. This approach means shell metacharacters in user input are never interpreted as command syntax at all, since there's no shell parsing the combined string in the first place — the input is passed as inert data to a specific program, not as part of an executable command line.
XXE: Exploiting How XML Parsers Handle External Entities
XML External Entity (XXE) injection exploits a legacy feature of the XML specification that lets a document define custom "entities" — reusable placeholders that get substituted with other content when the document is parsed, including content loaded from an external source like a local file or a URL. When an application parses XML from an untrusted source (a file upload, an API request body, a webhook payload) using a parser configured with external entity processing still enabled, an attacker can define an entity that points at a sensitive local file, and the parser will read and substitute that file's contents into the parsed output.
Beyond reading local files, a maliciously crafted XML document can define an entity that references a URL rather than a local file, causing the server to make an outbound request to an attacker-specified destination — a capability that overlaps directly with SSRF, covered in our companion guide on server-side request forgery. In more severe cases, certain parser configurations combined with specific entity structures can lead to denial of service through resource exhaustion, or in some environments, further escalation toward code execution.
Why XXE Became So Common, and Why It's Now Preventable by Default
XXE became a widespread issue specifically because external entity processing was enabled by default in most XML parser libraries for years, meaning any application parsing XML without explicitly disabling that feature was vulnerable by default rather than by mistake. Most major XML parsing libraries have since changed their default configuration to disable external entity processing, meaning applications built on current library versions with default settings are no longer automatically vulnerable — but applications built on older library versions, or ones that explicitly re-enabled the feature for some other reason, remain exposed.
This shift — from "vulnerable unless you remember to disable a feature" to "safe unless you explicitly re-enable it" — is widely regarded as one of the more successful examples of fixing a vulnerability class at the library level rather than relying on every individual application developer to remember a specific defensive step.
Command Injection vs XXE: Different Entry Points, Same Outcome Category
| Aspect | Command Injection | XXE |
|---|---|---|
| Entry point | Input passed into an OS shell command | Untrusted XML parsed with external entities enabled |
| Primary risk | Direct command execution | File disclosure, SSRF, sometimes RCE depending on configuration |
| Root cause | Unescaped input reaching a shell interpreter | Parser configuration allowing external entity resolution |
| Modern default risk level | Still high — shell invocation remains easy to misuse | Lower — most current parser libraries disable it by default |
| Primary fix | Avoid shell invocation; use argument-array execution instead | Explicitly disable external entity processing in parser config |
Insecure Deserialization: A Related Path to RCE Worth Knowing
Beyond command injection and XXE, insecure deserialization is a third common path to remote code execution worth understanding alongside them, since it shares the same underlying pattern of trusting structured data from an untrusted source more than is safe. Many programming languages support serializing objects (converting an in-memory data structure into a storable or transmittable format) and deserializing them back into live objects later. If an application deserializes data from an untrusted source without restriction, and the language's deserialization process can be made to construct objects that execute code as a side effect of being reconstructed, an attacker can craft serialized data that triggers code execution the moment it's deserialized.
This vulnerability class became widely known following several major, publicly disclosed incidents in enterprise Java and .NET applications specifically, though the underlying pattern applies to any language with a similarly flexible deserialization mechanism. The core defense mirrors XXE's: avoid deserializing data from untrusted sources at all where possible, and where unavoidable, use serialization formats and library configurations specifically designed to prevent arbitrary object construction during deserialization.
Real Scenarios Involving These Vulnerability Classes
A backup utility feature runs a system command to compress a user-specified folder name into an archive, building the command as a single string that includes the folder name directly. A security review catches that the folder-name parameter isn't isolated from the rest of the command, flagging it for conversion to argument-array execution before deployment.
An enterprise application accepts XML file uploads for a bulk-import feature, built years ago on an older parsing library version with external entity processing still enabled by default. A routine dependency audit flags the outdated library version specifically because of its default XXE exposure, prompting an upgrade that closes the gap without requiring any application code changes at all.
A penetration test against a network diagnostics dashboard finds that a "check domain availability" feature passes user input directly into a system ping command, discovered through the classic technique of testing whether shell metacharacters in the input produce any unexpected behavior — exactly the kind of finding that routine security testing is specifically designed to catch before real attackers do.
A developer troubleshoots unexpected server behavior after adding a webhook feature that parses incoming XML payloads from a third-party service, discovering the parser's default configuration in their specific library version still had external entities enabled, unlike the safer defaults in more recently updated libraries — a reminder that library defaults vary and shouldn't be assumed without checking.
Preventing Command Injection and XXE
For command injection, the single most reliable fix is avoiding shell string construction entirely: use language-standard functions that execute a program directly with a separate argument array, rather than building and passing a combined command string to a shell interpreter. Where shelling out genuinely can't be avoided, strict allowlist validation of the input (permitting only a specific, known-safe set of characters or values) provides meaningfully more protection than attempting to escape or blocklist dangerous characters.
For XXE, the fix is explicit and simple once known: disable external entity processing (and external DTD processing) in whatever XML parsing library your application uses, regardless of whether the current default already does this — explicit configuration removes any dependency on assumptions about library defaults that could change or be misremembered. Where possible, consider whether your application genuinely needs to accept raw XML from untrusted sources at all, since formats like JSON that don't carry this legacy entity-processing baggage eliminate the entire vulnerability class by design rather than requiring ongoing configuration vigilance.
FAQ
ToolsNovaHub guides are researched against primary sources (RFCs, vendor docs) and kept up to date as standards change. Spotted an error? Let us know.
📋 Related Tools & Guides Comparison
| Resource | Type | Link |
|---|---|---|
| Website Security Scanner | Tool | Open Tool → |
| File Inclusion & Path Traversal Vulnerabilities | Guide | Read Guide → |
| SSRF: Server-Side Request Forgery Explained | Guide | Read Guide → |
| Common Website Vulnerabilities Checklist | Guide | Read Guide → |