← Back to Attack Research

Unauthenticated file upload to RCE on SAP NetWeaver: inside CVE-2025-31324

One HTTP POST with no credentials drops a JSP web shell onto an SAP NetWeaver application server, and the next request runs commands on the ERP host as the SAP service account. The Visual Composer Metadata Uploader was missing an authorization check. Here is the mechanism, the zero-day timeline, and what closes it.

The endpoint that broke was supposed to check who you were before it accepted a file. It did not. SAP NetWeaver Visual Composer exposes a Metadata Uploader at /developmentserver/metadatauploader, and in vulnerable builds that endpoint was reachable with no authentication at all. An attacker who could reach it over the network could upload an arbitrary file, including an executable JSP, into a web-reachable directory on the SAP Java application server, then request that file to run code on the host. This is CWE-434 (Unrestricted Upload of File with Dangerous Type), tracked as CVE-2025-31324, scored 10.0 by SAP and 9.8 by NVD, and it has been on CISA's Known Exploited Vulnerabilities catalog since it was disclosed. This is not deserialization and it is not a memory bug. It is a missing gate on an upload endpoint, and it turns an ERP server into an attacker-controlled host.

SAP NetWeaver is the application platform underneath a large share of the world's ERP estates, and the Visual Composer component ships as part of the AS Java stack in the affected VCFRAMEWORK 7.50 line. Visual Composer is a low-code modeling tool that many organizations never actively use, yet it is present and running by default on plenty of NetWeaver installs. That combination, a rarely-used but always-present component exposing an unauthenticated write primitive on a business-critical host, is what makes this one of the more consequential SAP bugs in recent memory. We do not republish weaponized exploit code here. We explain the mechanism, the timeline, and how to determine whether your own perimeter carries the risk. Verifiable security.

The bug in one paragraph

The Metadata Uploader endpoint accepts uploaded content as part of its normal Visual Composer function. In the vulnerable code path, that endpoint did not enforce an authorization check, so a request arriving without any session or credential was still processed and its payload still written to disk. Because the upload accepted arbitrary file types rather than restricting to a safe allow-list, an attacker could send a file the server would happily execute, a JSP being the natural choice on a Java application server. The uploaded file landed in a directory served by the same web container that runs the application, which meant it was directly reachable by URL. At that point the attacker simply requested the file they had just uploaded, the container compiled and executed the JSP, and the attacker had command execution. Two facts stacked on top of each other produce the outcome: no authorization on the write, and no restriction on what could be written. Either one alone is a serious finding. Together they are a pre-authentication path from the open internet to arbitrary code execution.

Be precise about the class, because it is frequently misdescribed. CVE-2025-31324 is an unrestricted file upload, CWE-434. It is not an insecure deserialization bug. SAP later shipped a separate note for CVE-2025-42999, an insecure deserialization issue in the same broad area that was observed in some follow-on exploitation chains, but that is a different weakness with its own identifier, and the details of that second issue should be verified on their own rather than conflated with this one. The upload bug does not need deserialization to reach code execution. The upload itself is the whole exploit.

From one POST to a web shell

The attack is short because the primitive is powerful. An operator sends a single HTTP POST to the uploader endpoint carrying a JSP payload, receives a success response, and then makes an ordinary GET request to the path where the file was written. Publicly reported intrusions have used generic, innocuous-looking filenames for the dropped shell, names like helper.jsp and cache.jsp, precisely so the artifact blends into a busy servlet directory. Once the shell answers, the attacker has an interactive command channel that requires no credentials on every subsequent visit, because the shell itself is the authentication bypass. From there the typical progression is reconnaissance of the SAP host, credential and configuration harvesting, and lateral movement, all running with the privileges of the SAP Java process.

UNAUTHENTICATED UPLOAD --> WEB SHELL --> RCE [1] POST /developmentserver/metadatauploader body: helper.jsp (no auth header, no session) | v [2] server writes helper.jsp into a web-reachable servlet path ( missing authz check + no file-type restriction ) | v [3] GET //helper.jsp?cmd=... container compiles and runs the JSP | v [4] command execution as the SAP Java service account ( frequently <sid>adm ) --> full ERP host control weakness: CWE-434 unrestricted file upload | auth: PR:N (none)

The full chain is two requests: one to write the shell, one to run it. Illustrative, not from any specific host.

Why an ERP RCE is close to worst case

The severity here is not about the elegance of the bug, it is about where it lands. An SAP application server is a trust anchor for the business: it holds financial records, procurement and supply-chain data, HR and payroll information, and it is wired into identity, messaging, and downstream systems across the environment. Code execution on that host is not a foothold on the edge of the network, it is a foothold at the center of the organization's operations. The SAP Java service typically runs under a dedicated operating-system account, commonly the <sid>adm user, which owns the SAP installation and its data directories. Execution as that account means the attacker can read and alter SAP data, plant persistence, extract secrets used to reach connected systems, and pivot, all without ever having presented a credential.

That is why the scoring is what it is. SAP, as the CNA, rates CVE-2025-31324 a CVSS 10.0 with the vector AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H. NVD rates it 9.8. The single difference between the two scores is the Scope metric: SAP scores it Scope Changed (S:C), reflecting that the compromised web-tier component can affect the broader system beyond its own security authority, while NVD scores it Scope Unchanged (S:U), which caps the arithmetic at 9.8. Both agree on the parts that matter operationally: network reachable, low complexity, no privileges required, no user interaction, and full compromise of confidentiality, integrity, and availability. Quote both numbers when you brief this. Presenting only one invites an argument about the wrong thing.

The full exploit is two requests. Neither carries a credential. The second one runs your commands on the ERP server.

Exploited before the patch existed

This was a zero-day. SAP released the fixing Security Note on 2025-04-24, but exploitation had already been observed in the wild before that date. Rapid7 reported activity against the uploader endpoint from at least 2025-03-27, roughly four weeks before a patch was available, which means early victims had no vendor fix to apply while the endpoint was being actively hit. The targeting was not indiscriminate background noise either. Reporting from multiple responders described heavy focus on manufacturing organizations, the kind of operational environments where SAP sits at the core of production and supply-chain planning and where downtime is expensive enough that patching windows are conservative. That is a difficult combination: a pre-auth RCE, exploited before a fix shipped, aimed at a sector that is structurally slow to patch its most critical systems.

The practical lesson from the timeline is that patch status is necessary but not sufficient. An organization that applied the note promptly still needs to assume the window between late March and their patch date was exposed, and to hunt for artifacts left during it. A web shell dropped on 2025-03-30 does not remove itself when you install the April note. Patching closes the door; it does not evict anyone already inside.

How to recognize your exposure

You can assess this without sending a malicious payload, because the exposure is determined by a few readable facts.

  1. Is the uploader endpoint reachable? Determine whether /developmentserver/metadatauploader answers on any internet-facing or broadly-reachable SAP NetWeaver host. An endpoint that responds pre-authentication is the whole precondition for the attack.
  2. Is Visual Composer present and on an affected build? The component is VCFRAMEWORK 7.50. Confirm whether it is installed and whether the host predates SAP's 2025-04-24 note, since a public-facing, unpatched instance carries active, catalog-listed risk by definition.
  3. What account does the SAP Java service run as? The blast radius equals the privilege of the process that gets injected. Knowing the run-as account, commonly <sid>adm, tells you how bad a successful hit is before one happens.

What to do about it

Close CVE-2025-31324 and hunt for prior compromise

How Celvex catches this

Find. Prove. Fix. Verify.

Find

A read-only sweep maps internet-facing SAP NetWeaver hosts, checks whether the Metadata Uploader endpoint answers, and fingerprints the Visual Composer build against the known-exploited catalog, without sending a single upload.

Prove

A confirmed exposed, catalog-listed surface becomes an Ed25519-signed Proof Capsule carrying the host, the endpoint and version evidence, and the matching CVE-2025-31324 record, reproducible offline by you or your auditor.

Fix

The capsule's remediation block names the steps: apply the 2025-04-24 note, block or disable the uploader, reduce the service privilege, and hunt the servlet path for planted JSP files.

Verify

A fresh sweep confirms the endpoint is patched, blocked, or no longer exposed. The finding closes and the verified-fix event is recorded for the audit trail.

The reason this bug is so instructive is that it is not clever. There is no exotic gadget chain and no race to win. An endpoint that was meant to authenticate its callers simply did not, and an upload that should have been restricted to safe types was not. The discipline that catches it is the same one that catches its cousins: for every host that accepts input from outside, ask which endpoints answer before login, what they let a stranger write, and what privilege that write inherits. On an ERP server the answer to that question is the whole business, which is exactly why it warrants a faster patch window and a closer watch than almost anything else on the perimeter.

Verifiable security. Find it. Prove it. Fix it. Verify the fix held. That is what we ship.

Sources

Is your SAP NetWeaver uploader answering strangers?

Free Exposure Check, no signup required. We map your internet-facing SAP NetWeaver hosts, test whether the Metadata Uploader endpoint responds and on which Visual Composer build, and ship a signed Proof Capsule for the highest-confidence finding.

Run a Free Scan →