CVE-2020-15094
Executive Summary
CVE-2020-15094 is a remote code execution (RCE) vulnerability affecting the Symfony PHP framework's CachingHttpClient class, which is part of the HttpClient component. Versions of Symfony before 4.4.13 and 5.1.5 are vulnerable. The flaw arises from an unsafe interaction between the CachingHttpClient and the underlying HttpCache class: the latter processes attacker-influenced internal headers (X-Body-Eval, X-Body-File) that control how cached response bodies are restored. If an attacker can manipulate the response content received by CachingHttpClient from the target endpoint, they can trigger arbitrary code execution on the server. The CVSS v3 base score is 8.0 (High), reflecting a network-based attack vector with no authentication requirements, though successful exploitation requires the ability to control an HTTP response returned to the application.
Affected party: All enterprises running Symfony applications (4.4.x < 4.4.13, 5.1.x < 5.1.5) that use CachingHttpClient as an HTTP client wrapper or act as a reverse proxy/cache service consuming external or untrusted responses.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Technical Analysis
The vulnerability resides in the CachingHttpClient class, which implements response caching for HTTP requests made through the Symfony HttpClient component. Internally, CachingHttpClient relies on the HttpCache class—a heavier-weight component originally designed for gateway caching with ESI (Edge Side Includes) support. The HttpCache class interprets two legacy, non-standard HTTP headers—X-Body-Eval and X-Body-File—when reconstructing cached response bodies.
Under the intended design (surrogate caching in a trusted backend environment), those headers would be set by a trusted origin server. However, when CachingHttpClient is used as a general-purpose HTTP client, these headers may be echoed back from an external (untrusted) server that the application is querying. The X-Body-Eval header causes the PHP engine to evaluate the response body as PHP code (code injection), while X-Body-File causes the server to read and inject the contents of an arbitrary local file (local file inclusion) into the response stream. An attacker controlling the response from a poisoned or malicious third-party service, or via a man-in-the-middle position over cleartext HTTP, can therefore deliver a payload that the vulnerable Symfony server will evaluate with server-side privileges.
The attack surface is wider than a standalone service attack: any application that utilizes CachingHttpClient to consume data from a remote API, RSS feed, federated platform, or even a network endpoint controlled by a lower-privileged user (e.g., a webhook) is exposed. The root cause is a privilege mismatch: a client-side cache mechanism is reusing a server-side cache kernel designed to trust headers from a reverse proxy, with no sanitization layer between them.
Specific technical details: The vulnerability class is CWE-94 (Code Injection), enabled via the X-Body-Eval header path. The X-Body-File variant provides a secondary vector for arbitrary file read that can be chained into RCE if the file contains user-influenced content.
Exploitation Scenarios
Because no public exploit code is available (POC_STATUS: Private), this attack chain is inferred from the CWE-94 code injection class and the behavior described in the NVD entry.
Step 1 — Reconnaissance/Target Identification:
An attacker identifies a target running Symfony 4.4.x (< 4.4.13) or 5.1.x (< 5.1.5) that exposes functionality making outbound HTTP requests through CachingHttpClient. This is typically determined via unauth responses (e.g., X-Powered-By: PHP/7.x, Symfony debug headers) or via framework-specific fingerprints in assets and cookies. Alternatively, the attacker administers a server endpoint that the target application is configured to poll (e.g., a webhook receiver, RSS aggregator, CDN origin) and controls its response headers.
Step 2 — Triggering the Flaw:
The attacker causes the Symfony application to make a request to a server they control and obtains a response containing the X-Body-Eval: 1 header, along with a response body containing PHP code. Since the application fetches remote content without filtering response headers, the HttpCache component treats the incoming response as a candidate for cache restoration. No authentication is required—the attacker only needs unidirectional control of an outbound HTTP response (the AC:H factor in the CVSS vector reflects this dependency).
Step 3 — Payload/Execution Method:
The response body is interpreted as PHP source code and evaluated in the context of the application's process via the X-Body-Eval header. The attacker's PHP payload executes with the privileges of the web server user. Alternatively, with X-Body-File, the attacker can read arbitrary readable files on the target system (e.g., /etc/passwd), and if they can cause the target to include a cache file that they previously seeded (e.g., via a log injection), they can achieve the same RCE outcome. The payload delivery is a single HTTP response, making the exploitation window minimal and evasive.
Step 4 — Post-Exploitation Impact:
Once the injected code executes, the attacker typically achieves:
- Full read/write access to the application filesystem under the web server user
- Database credential harvesting through
config/or.envfile reads - Lateral movement if the compromised server holds network trust to internal services
- Persistence via a web shell or scheduled task that mimics the legitimate framework routing
No public exploit exists; the attack chain is inferred from the vulnerability class. High skill is required to operationalize, but a single HTTP response is sufficient for payload delivery.
Impact Assessment
Business Impact:
RCE on a Symfony application commonly yields complete compromise of the web server process and everything it can reach. Confidentiality is fully compromised (database exfiltration, credential theft), integrity can be subverted (data falsification, file modification), and availability can be destroyed (web shell, destructive file operations). The CVSS base score of 8.0 (High) aligns with these catastrophic consequences, capped only by the network connectivity requirement.
Affected Systems:
- All Symfony 4.4.x applications before 4.4.13 that use the
HttpClientcomponent'sCachingHttpClientclass. - All Symfony 5.1.x applications before 5.1.5 with the same usage.
- Note: Even if the application does not use
CachingHttpClient, the presence ofHttpCachemiddleware can expose this vector on proxy/gateway endpoints that mirror untrusted upstream responses.
Blast Radius:
- Server-side: Complete takeover of the application server process.
- Data side: Full database access and internal configuration files.
- Network side: Pivot point for lateral movement into internal networks (SSH credentials in
.env, internal service tokens). - Supply chain: If the server is a caching reverse proxy for downstream consumers, the injected payload can also poison cached responses delivered to other clients, extending the blast radius beyond the initial victim.
The EPSS score of 0.03043 (86.3 percentile) suggests the vulnerability is moderately likely to be exploited in the wild, warranting urgent patching.
Detection Guidance
The following detection scenarios target servers running Symfony that may be subject to exploitation attempts via X-Body-Eval/X-Body-File headers in inbound traffic. All rules assume network visibility into HTTP response headers.
Sigma Rule
title: Suspicious X-Body-* Headers in HTTP Response
id: e3d8c0d9-1c7a-4a9b-9f32-fb04a1bb68a4
status: experimental
description: Detects responses containing internal Symfony HttpCache headers indicative of CVE-2020-15094 exploitation
logsource:
category: webserver
product: generic
detection:
selection:
http.response.headers|contains:
- 'X-Body-Eval'
- 'X-Body-File'
condition: selection
falsepositives:
- Legitimate Symfony backend communications between trusted internal servers
- Proxy responses that intentionally pass through these headers
level: high
tags:
- attack.t1190
- attack.t1505.003
- cve.2020.15094
YARA Rule
rule Symfony_CachingHttpClient_Header_Indicator
{
meta:
author = "ValtersIT SOC"
description = "Detects strings commonly associated with CVE-2020-15094 exploitation payloads"
date = "2024-01-29"
reference = "CVE-2020-15094"
severity = "high"
strings:
$header_eval = "X-Body-Eval" ascii wide nocase
$header_file = "X-Body-File" ascii wide nocase
$php_tag = "<?php" ascii wide
$system_call = "system(" ascii wide
$payload_common = "eval(" ascii wide
condition:
(#header_eval > 0 or #header_file > 0) and any of them
and ($php_tag or $system_call or $payload_common)
}
Suricata IDS Rule
alert http any any -> any any (msg:"CVE-2020-15094 Symfony HttpCache X-Body-Eval RCE"; flow:to_server,established; content:"X-Body-Eval"; http.header; content:"X-Body-File"; http.header; pcre:"/eval|system|shell_exec|passthru/i"; http.response_body; classtype:attempted-user; sid:2000007; rev:1; metadata:created_at 2024_01_29, updated_at 2024_01_29;)
Elastic Detection
sequence by host.ip
[http where response.status_code == 200 and
http.response.headers contains "X-Body-Eval" and
http.response.headers contains "X-Body-File"]
Splunk SPL Query
index=proxy OR index=web*
http_response_headers_key IN ("X-Body-Eval", "X-Body-File")
| eval exploit_attempt=if(match(http_response_body, "(?i)(eval|system|shell_exec|passthru)"), "RCE", "possible")
| stats count by src_ip, dest_ip, uri_path, exploit_attempt
| where exploit_attempt="RCE"
Wazuh OSSEC Rule
<group name="symfony,">
<rule id="100200" level="12">
<decoded>HTTP_RESPONSE_HEADER</decoded>
<field name="header_name">X-Body-Eval</field>
<description>Symfony HttpCache RCE - X-Body-Eval header in response (CVE-2020-15094)</description>
<group>cve-2020-15094,</group>
</rule>
<rule id="100201" level="12">
<decoded>HTTP_RESPONSE_HEADER</decoded>
<field name="header_name">X-Body-File</field>
<description>Symfony HttpCache file read - X-Body-File header in response (CVE-2020-15094)</description>
<group>cve-2020-15094,</group>
</rule>
</group>
Mitigation & Patch Guidance
Patch Confidence: 2/4 (CLAIMED — single source claims patch (not independently confirmed))
Deployment of patches is recommended despite moderate patch-confidence scoring.
1) Immediate Mitigations
- Restrict outbound HTTP: If
CachingHttpClientis used solely for internal services, limit remote connections via firewalled IP allow-lists to block untrusted external endpoints. - Disable
X-Body-Eval/X-Body-Fileprocessing: If code cannot be patched immediately, place a reverse proxy in front of the Symfony app that stripsX-Body-*headers from all inbound responses. - Network-level separation: Segment Symfony servers from arbitrary internet access until patching is complete.
- Upgrade via composer:
# Minimal safe versions to upgrade to
composer update symfony/http-client --with-dependencies
# For Symfony 4.4.x users:
composer require symfony/http-client:^4.4.13
# For Symfony 5.1.x users:
composer require symfony/http-client:^5.1.5
2) Patch/Upgrade Steps
- Symfony 4.4.x: upgrade to 4.4.13 or later (or any 4.4.x LTS after 4.4.13).
- Symfony 5.1.x: upgrade to 5.1.5 or later.
- Full framework upgrade recommended (e.g., 5.4 LTS) to ensure related security fixes are included.
- Verify patch by checking framework version:
bin/console about(if CLI available) or checkingvendor/symfony/http-client/CHANGELOG.mdfor the CVE entry.
3) Long-Term Hardening
- Header sanitization: Audit the entire HTTP stack (proxies, load balancers, application clients) to strip non-standard headers that are not intentionally used.
- Trust boundary review: All components that process HTTP responses must either validate or strip
X-Body-*headers; ensure thatHttpCacheis never used directly with untrusted upstream content. - Dependency monitoring: Enforce automated dependency scanning (e.g., composer audit in CI/CD, tools like Snyk or Trivy) to catch future CVEs.
- Network hygiene: Use TLS (HTTPS) for all outbound communication to prevent man-in-the-middle injection of malicious headers—though note this CVE is equally exploitable over HTTPS if the attacker controls the endpoint.
References
- NVD Entry – https://nvd.nist.gov/vuln/detail/CVE-2020-15094
- Debian Security Tracker – https://security-tracker.debian.org/tracker/CVE-2020-15094 (Patch source, additional package information)
- Symfony Release Announcement (Official) – Symfony 4.4.13 & 5.1.5 release notes confirming fix (via Symfony Blog / GitHub Releases)
- EPSS Database – https://www.first.org/epss/ (EPSS Score 0.03043)
- CISA KEV – No entry for CVE-2020-15094; no known exploited vulnerabilities catalog listing; no confirmed in-the-wild exploitation campaigns have been publicly documented.
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.