Skip to content
CVE IDCVE-2026-77615GitHub advisory IDGHSA-m6c8-jcw2-5r25

Opencast: Stored XSS in Paella player via WebVTT/DFXP caption cue text

CVE-2026-77615 (GitHub advisory GHSA-m6c8-jcw2-5r25) is a high-severity vulnerability with a CVSS 3.1 base score of 8.7, classed as Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79), in org.opencastproject:opencast-engage-paella-player-7 (Maven) and paella-core (npm). Fixed versions: org.opencastproject:opencast-engage-paella-player-7 19.7 or 20.2; paella-core 1.50.6.

High8.7Fix availableGitHub reviewed

Published 17 Sept 2026Updated 18 Sept 2026

8.7HighCVSS 3.1
EPSS
0.39%higher than 33% of CVEs
Weakness (CWE)
  • CWE-79Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
KEV status
Not in KEV
Published
17 Sept 2026
Updated
18 Sept 2026
Ecosystems
  • Maven
  • npm
Assigned by (CNA)
GitHub_M

Summary

Source: OSV (GitHub advisory)

The Opencast Paella player renders caption cue text into innerHTML without escaping. The captions canvas clears _captionsContainer.innerHTML and then appends each active cue with _captionsContainer.innerHTML += cue, so HTML inside a WebVTT or DFXP cue becomes live DOM and executes in the Opencast origin.

The caption track is read from any media package element with a captions/* flavor and is served, with the player manifest, to anonymous viewers through /search/episode.json. The caption plugins that consume it are enabled in the default player configuration, the "Subtitles" upload that produces a captions/source track is active by default, and no caption processing step escapes the cue text.

A user who can upload a subtitle to an event and publish it stores the payload in the published caption file. Any viewer who opens the event and turns captions on runs the script.

Result: a non-admin content author stores JavaScript in a subtitle cue that executes in the browser session of every viewer who enables captions on that event, including anonymous viewers and authenticated staff.

Affected

opencast/opencast, engage-paella-player module. Supported release lines 19.x and 20.x are affected (and 18.x). Live-confirmed on 18.8 (Paella 7, paella-core 1.50.2) and 20.0 (Paella 8, paella-core 1.50.4); 19.5 ships the code-identical caption path (paella-core 1.50.4, same EpisodeConversor and default plugin config as 20.0). The captions canvas uses the same innerHTML += cue sink across these versions. Default configuration: the WebVTT and DFXP caption plugins are enabled: true in etc/ui-config/mh_default_org/paella7/config.json, the "Subtitles" upload option (captions/source, .vtt) is active in etc/listproviders/event.upload.asset.options.properties, and the fast workflow publishes captions/* to the engage player. Condition: an event with a caption track published to the engage player. No non-default flag required.

Root cause

The captions canvas appends each cue to _captionsContainer.innerHTML in the bundled paella-core (served at /paellaN/ui/paella-player.js / the 20.x core chunk), so markup in a cue becomes live DOM. The caption entry is built from any media package element whose flavor matches captions/* at modules/engage-paella-player-7/src/js/EpisodeConversor.js:392, and /search/episode.json serves the manifest and the caption file to anonymous clients. The WebVTT and DFXP plugins that consume it are enabled by default at etc/ui-config/mh_default_org/paella7/config.json:571 and :574. The cue text is not HTML-escaped before assignment to innerHTML, and partial-process-uploaded-captions only cuts and tags the file, it never sanitizes it. Opencast sets neither a Content-Security-Policy nor an X-Content-Type-Options header, so the injected script runs without restriction.

Reproduction

Default config, default caption plugins enabled, a non-admin user with ROLE_API_EVENTS_CREATE, ROLE_API_EVENTS_TRACK_EDIT, and ROLE_UI_TASKS_CREATE (no ROLE_ADMIN).

  1. As the non-admin user, create an event, then upload a WebVTT subtitle as captions/source whose cue text is an XSS payload, and publish the event.
WEBVTT

00:00:00.000 --> 00:00:30.000
<img src=x onerror=document.title=window.__xss=document.domain>
  1. The anonymous search manifest then exposes the caption and serves the cue raw.
GET /search/episode.json?id=<event>
"type":"captions/source", "url":".../static/.../x.vtt"
GET .../static/.../x.vtt  ->  cue text returned verbatim
  1. Open the event in the player as an anonymous viewer, open the captions menu, and select the track; the cue is written to innerHTML and the onerror handler runs.

Live-verified: on Opencast 18.8 (build 8705223) in Chrome, a non-admin author published the subtitle and an anonymous viewer enabled captions, rendering the cue as a live <img> node and setting window.__xss and document.title to document.domain. On Opencast 20.0 (build d919405, Paella 8), the served core bundle contains the identical innerHTML += cue sink and the player loads the cue raw; the sink executes JavaScript in the engage origin when fed the player's own published caption file.

Impact

  • JavaScript execution in the Opencast origin in the session of any viewer who enables captions on the event.
  • Anonymous viewers and authenticated staff are equally affected; an instructor or admin viewer exposes that session context to the script.
  • Session and CSRF-token theft, actions performed as the victim against the Opencast REST API.
  • Stored by a non-admin content author, triggered by viewing with captions on, no attacker authentication at view time.

Credit

Jan Kahmen, turingpoint (jan@turingpoint.de)

Technical details

Source: GitHub Advisory Database

CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N

High8.7Base score from GitHub Advisory Database

Attack Vector AV
Network
Attack Complexity AC
Low
Privileges Required PR
Low
User Interaction UI
Required
Scope S
Changed
Confidentiality C
High
Integrity I
High
Availability A
None

Affected packages

Source: OSV (GitHub advisory)

  • org.opencastproject:opencast-engage-paella-player-7
    Maven
    pkg:maven/org.opencastproject/opencast-engage-paella-player-7
    Affected versions
    < 19.7
    >= 20.0, < 20.2
    Fixed in
    19.7
    20.2
    Show 61 listed versions
    • 12.0
    • 12.1
    • 12.11
    • 12.12
    • 12.13
    • 12.2
    • 12.3
    • 12.5
    • 12.6
    • 12.7
    • 12.8
    • 12.9
  • paella-core
    npm
    pkg:npm/paella-core
    Affected versions
    < 1.50.6
    Fixed in
    1.50.6

Fix

Source: OSV (GitHub advisory)

Fix available

  • org.opencastproject:opencast-engage-paella-player-7: upgrade to 19.7 or 20.2, depending on your release line
  • paella-core: upgrade to 1.50.6 or later

Patch commits

  • 701682cPatch commitgithub.com/opencast/opencast

    Upgrade paella 8

    +589 −4788 across 4 files

    • modules/engage-paella-player-8/package-lock.json+541 −4751
    • modules/engage-paella-player-8/package.json+10 −10
    • modules/engage-paella-player-8/src/applyQueryParams.ts+37 −26
    • modules/engage-paella-player-8/src/watch.ts+1 −1
  • 94a3649Patch commitgithub.com/polimediaupv/paella-core

    Fix XSS bug in captions and HTML DOM generation

    +34043 −26014 across 7 files

    • dist/paella-core.js+31642 −23950
    • dist/paella-core.js.map+1 −1
    • package-lock.json+2319 −2046
    • package.json+1 −1
    • src/js/captions/CaptionsCanvas.js+9 −6
    • src/js/captions/DFXPParser.js+1 −1
    • src/js/core/dom.js+70 −9
  • 9b2f14ePatch commitgithub.com/polimediaupv/paella-core

    Fix security issue in WevVTT captions

    +195 −264 across 5 files

    • package-lock.json+179 −227
    • package.json+2 −1
    • src/index.html+0 −2
    • src/js/Paella.js+0 −1
    • src/js/captions/WebVTTParser.js+14 −33
  • 6fe4af7Patch commitgithub.com/polimediaupv/paella-player
  • #7736Pull requestgithub.com/opencast/opencast

Vulnerability intelligence

References

Credits

Questions about CVE-2026-77615

What is the GHSA ID for CVE-2026-77615?
GitHub tracks CVE-2026-77615 as GHSA-m6c8-jcw2-5r25.
What is the CVSS score of CVE-2026-77615?
CVE-2026-77615 has a CVSS 3.1 base score of 8.7 (High), vector CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N.
Which versions are affected by CVE-2026-77615?
org.opencastproject:opencast-engage-paella-player-7 (Maven): < 19.7; >= 20.0, < 20.2. paella-core (npm): < 1.50.6.
How do I fix CVE-2026-77615?
Upgrade each package to its fixed version: org.opencastproject:opencast-engage-paella-player-7 19.7 or 20.2; paella-core 1.50.6. The fix is in commits 701682c, 94a3649 and 9b2f14e and pull request #7736.
What is the Package URL (PURL) for CVE-2026-77615?
The affected packages' PURLs are pkg:maven/org.opencastproject/opencast-engage-paella-player-7 and pkg:npm/paella-core.
Is CVE-2026-77615 exploited in the wild?
CISA's Known Exploited Vulnerabilities catalog doesn't list CVE-2026-77615. That means no confirmed exploitation has been catalogued, not that it is safe to leave unpatched. EPSS estimates a 0.39% chance of exploitation in the next 30 days, higher than 33% of CVEs.

Data sources

Upstream records

  • OSV (GitHub advisory)LoadedRaw JSON
  • GitHub Advisory DatabaseLoadedRaw JSON
  • OSV (CVE record)LoadedRaw JSON
  • CVE.orgLoaded
  • CISA KEV catalogLoaded

Fetched 5 days ago (9 Oct 2026, 02:42 UTC). Records refresh automatically after 24 hours.

Where each part of this page came from

Title and description
OSV (GitHub advisory)
Severity score
GitHub Advisory Database
Weakness (CWE)
GitHub Advisory Database
Affected packages
OSV (GitHub advisory)
Fix
OSV (GitHub advisory)
References
Computed by CVEminer
KEV status
CISA KEV catalog
EPSS
GitHub Advisory Database

OSV and GitHub Advisory Database content is licensed CC BY 4.0. Values marked as computed or derived were calculated by CVEminer from the upstream data.