Untrusted expression evaluation can turn a routine request into server-side code execution, file access, or data exfiltration. Once an attacker reaches that point, they can often pivot to environment discovery, command execution, and outbound callbacks that prove compromise. The practical consequence is that a convenience feature becomes a full application takeover path.
Why Untrusted Expression Evaluation Becomes a Security Boundary
When an application accepts expressions from users, templates, rules, filters, or workflow builders, it is no longer handling plain data. It is asking the parser or runtime to interpret attacker-controlled input as logic, which can change what the application reads, writes, or executes. That is why this issue sits closer to code execution risk than to ordinary validation failure, especially when the expression language can reach files, environment variables, network calls, or host functions.
Strict input sanitisation matters here because the dangerous part is often not a single character, but the evaluator’s ability to resolve names, call functions, traverse object graphs, or chain subexpressions. A weak filter may block obvious shell metacharacters and still leave expression syntax intact. In practice, many security teams encounter this only after a benign-looking feature has already been used to probe internals, rather than through intentional design review.
How Safe Evaluation Fails in Practice
The usual failure mode is treating an expression engine like a safe calculator when it actually has access to application context. If the evaluator can reference variables, call methods, or invoke helpers, then attacker-supplied input may cross from computation into privilege-bearing actions. That can expose secrets, mutate records, trigger outbound requests, or reach server-side primitives that the developer never meant to publish.
Good design starts by reducing what the expression engine can see and do. The safest pattern is to avoid general-purpose evaluation entirely when a fixed schema or explicit allowlist can express the same business rule. If evaluation is unavoidable, the expression grammar should be tightly bounded, with no access to reflection, object construction, filesystem functions, or arbitrary imports. Sanitisation alone is rarely enough if the evaluator remains expressive.
- Restrict the language to the minimum syntax needed for the business use case.
- Separate data inputs from executable expressions so user content is never reinterpreted as code.
- Run evaluation in a constrained context with no ambient access to secrets, OS commands, or internal network paths.
- Log rejected patterns and unexpected evaluator behaviour so abuse attempts are visible.
Where teams get into trouble is assuming that escaping or pattern filtering can compensate for an overly powerful evaluator. That breaks down as soon as an attacker finds an alternate syntax, a nested function, or a reachable helper that the filter did not anticipate.
Edge Cases Where “Sanitised” Still Is Not Safe Enough
Tighter filtering often increases implementation complexity, requiring organisations to balance developer convenience against the risk of hidden evaluation features. The hardest cases are not the obvious injection sinks but the business features that intentionally support formulas, condition builders, rich search syntax, or plugin-style expressions.
There is no universal consensus that every expression language is inherently unsafe; the practical question is whether the language is sufficiently constrained for the trust level of its input. A narrowly scoped rule engine may be acceptable, while a feature that exposes runtime objects, imports, or custom functions usually is not. Even when input is encoded or escaped correctly, the design can still be vulnerable if the evaluator can resolve symbols beyond the intended scope.
Watch especially for “safe mode” claims that only remove a few obvious built-ins. If the underlying runtime still allows indirect access through attribute traversal, helper objects, or deserialised context, the attacker may recover dangerous capabilities by composition rather than by direct calls. The answer stops being reliable whenever the application delegates trust decisions to a general evaluator whose effective power is broader than the developer intended.
Standards & Framework Alignment
This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.
MITRE ATT&CK address the attack and risk surface, while CIS Controls v8 and NIST CSF 2.0 set the governance and control requirements practitioners need to meet.
| Framework | Control / Reference | Relevance |
|---|---|---|
| CIS Controls v8 | 16.1 — Application Software Security | Expression evaluation is an application security weakness that needs safe design and testing. |
| 3.4 — Data Recovery | If evaluation leads to data exfiltration or destructive actions, recovery readiness becomes relevant. | |
| Recommendation — Assess expression features for unsafe execution paths and remove or constrain them before release. Protect recovery paths so compromise through unsafe evaluation does not permanently destroy data. | ||
| NIST CSF 2.0 | PR.DS — Data Security | Untrusted evaluation can expose secrets and data, making data protection controls directly relevant. |
| Recommendation — Limit evaluator access to sensitive data and verify that secret-bearing context is never exposed. | ||
| MITRE ATT&CK | T1059 — Command and Scripting Interpreter | Unsafe expression evaluation can become code execution through interpreter abuse. |
| T1210 — Exploitation of Remote Services | Reachable evaluators and exposed helpers can provide a path to abuse application services remotely. | |
| Recommendation — Hunt for interpreter abuse and block attempts to turn expression input into executable commands. Monitor remotely reachable evaluation endpoints for abuse and restrict exposed helper functions. | ||
Practitioner Guidance
What to prioritise: Classify every expression feature by trust level before deciding how it will be parsed. If untrusted users can influence the expression text, treat the feature as an attack surface and not as a simple validation problem.
Decision rule: If a business rule can be expressed with an allowlist, fixed conditions, or prebuilt operators, prefer that over runtime evaluation. Reserve expression engines for cases where user-defined logic is genuinely required and cannot be safely simplified.
What to verify: Confirm whether the evaluator can reach filesystem, process, reflection, network, or secret-bearing objects through direct calls or indirect object navigation. Also verify that rejected input is actually blocked at the parser level, not merely transformed into a different syntax that still executes.
What practitioners underestimate: The main risk is often not obvious injection syntax but the breadth of the evaluator’s context. A restricted expression language can still become dangerous if it inherits powerful objects from the host application.
Practitioner takeaway: The security question is not whether input was “cleaned,” but whether untrusted text can still influence executable logic with access to anything sensitive.
Related resources from NHI Mgmt Group
- What happens when path traversal is attempted without strict input validation and path restrictions?
- What happens when remote code execution is attempted without strong input validation and patch management?
- What happens when AI agents share context without strict scoping and validation?
- What happens when application security is left to security teams without developer and operations collaboration?