← Blog
5 min read

How RCE Works - and How I Found One in IriusRisk's Drools Engine

A technical walkthrough of remote code execution, why rule engines are dangerous attack surfaces, and how a custom Drools rules menu became a Java code injection vector.

securityrcevulnerability-researchdrools

This post explains how remote code execution (RCE) works as a vulnerability class, and how I discovered an RCE issue in the IriusRisk platform through a feature that let users insert custom Drools rules manually - effectively allowing Java code injection on the server.

I'll keep exploit specifics responsible. The failure mode matters more than copy-paste payloads.

Disclosure context: The issue was reported internally through proper channels and remediated.

What RCE actually means

Remote Code Execution means an attacker can cause a system to run arbitrary code - not just crash a parser with bad input, but execute logic that wasn't intended to be part of the application's trusted path.

On most application servers, that's game-over for practical threat modeling. The service account running your app becomes the execution context. Data access, lateral movement, and persistence all become questions of "how hard" rather than "if."

Where Drools fits in

Drools is a business rule management system. You write rules - typically in DRL (Drools Rule Language) - and the engine evaluates them against facts in working memory.

Rule engines are attractive in enterprise products because policy can change without redeploying core code. Security-wise, they're latent compilers: they accept logic, parse logic, and execute logic.

If users can influence what gets parsed, they're not configuring - they're programming. The JVM doesn't care that the UI called it a "rule."

The vulnerable feature

The issue lived in a menu that allowed users to insert custom Drools rules manually.

On paper, that's a power-user feature: let customers tailor automation, scoring, or workflow behavior without waiting for a vendor release.

In practice, it was an open door.

Drools rules aren't inert configuration strings. DRL supports Java semantics - imports, types, method calls, access to objects placed in the engine context. When the platform accepted user-supplied rule content and fed it to Drools for evaluation on the server, the trust boundary collapsed:

User text → parsed as executable logic → runs as the application.

That's not a logic bug. That's code injection through a rules engine.

How I found it

I wasn't running a scheduled pentest. I was doing the kind of security engineering work that connects product surface to architectural assumptions.

The thread was straightforward:

  1. There's a UI path where users paste or author custom Drools rules.
  2. Those rules are evaluated server-side.
  3. Drools DRL is expressive enough to reference Java classes available on the classpath.
  4. The permission model assumed "this is configuration" rather than "this is remote code."

I started with a simple question: what happens if I put Java in the rule field?

Not metaphorical Java. Actual imports and calls - the kind Drools allows when the language features are fully enabled and the runtime isn't sandboxed.

The answer was RCE.

Why this class of bug is so dangerous

A SQLi might leak records. An XSS might steal sessions. An RCE in the rule engine means the product's automation layer becomes the weapon.

Specifically painful in a threat modeling platform:

  • Confused deputy. Users think they're customizing policy. The server executes attacker-controlled bytecode paths.
  • High privilege context. Rule engines typically run with application-level access, not a stripped sandbox.
  • Irony factor. A security governance tool with a code execution primitive undermines customer trust in a very direct way.
  • Hard to detect. WAFs don't understand DRL. Logs look like normal authenticated traffic until something very bad happens inside the engine.

The fix isn't one line

Remediation for this category is architectural:

1. Remove or strictly gate the feature. If arbitrary DRL isn't essential, delete it. Most users don't need a compiler in the settings menu.

2. Treat rules as code. Code review, signing, deployment gates - only trusted operators publish executable policy.

3. Never evaluate untrusted DRL server-side. If customization is required, use constrained decision models - not a general-purpose language with Java imports.

4. Sandbox if you must evaluate. Isolated classloaders, restricted imports, separate microservice with minimal privileges. "Hope admins are careful" is not a control.

5. Audit existing content. If the feature shipped, assume someone already tried interesting things.

The lesson I keep repeating

Power-user features are attacker features when the permission model is fuzzy.

Every "flexibility" point in a security product is a contract: this input stays data. Drools DRL breaks that contract the moment users can type freely.

When I threat model now, I ask:

  • Where does user input become computation?
  • What language is it, really?
  • Who can trigger it?
  • What identity executes it?

If the answer includes "Java on the server," you don't have a settings page. You have a shell wearing a form label.

Closing

RCE is simple to define: untrusted computation in a trusted process.

The IriusRisk case was simpler to describe: a menu that let users write Drools rules was a menu that let users write Java.

Rule engines feel like configuration. The JVM disagrees.

If you're building enterprise software with dynamic rules, ask the uncomfortable question before shipping:

What happens if someone treats my configuration language like a programming language?

In our case, they could. That was the bug.

Plan accordingly.