// Apache Struts2 Jakarta multipart parser — pre-CVE-2017-5638 (S2-045). // The error-message branch evaluates user-controlled Content-Type as an // OGNL expression for "helpful" exception formatting. Attacker controls // the Content-Type header → controls the OGNL string → RCE. package org.apache.struts2.dispatcher.multipart; import com.opensymphony.xwork2.util.LocalizedTextUtil; import org.apache.commons.fileupload.FileUploadException; import javax.servlet.http.HttpServletRequest; import java.util.Locale; public final class JakartaMultiPartRequest { public void parse(HttpServletRequest req, String saveDir) throws FileUploadException { try { parseUploadInternal(req, saveDir); } catch (FileUploadException e) { // BUG: attacker-controlled Content-Type flows into LocalizedTextUtil // which evaluates ${...} / %{...} as OGNL — bypassing all // type/security restrictions, running arbitrary Java. String contentType = req.getContentType(); String errorMessage = LocalizedTextUtil.findText( getClass(), "struts.messages.upload.error.InvalidContentTypeException", Locale.ENGLISH, "Unable to parse Content-Type " + contentType, new Object[] { contentType } ); throw new FileUploadException(errorMessage, e); } } private void parseUploadInternal(HttpServletRequest req, String saveDir) throws FileUploadException { // ...real parsing happens here, but invalid Content-Types throw the // FileUploadException caught above. throw new FileUploadException("invalid boundary"); } }