CVE-2025-53890
Description
pyload is an open-source Download Manager written in pure Python. An unsafe JavaScript evaluation vulnerability in pyLoad’s CAPTCHA processing code allows unauthenticated remote attackers to execute arbitrary code in the client browser and potentially the backend server. Exploitation requires no user interaction or authentication and can result in session hijacking, credential theft, and full system remote code execution. Commit 909e5c97885237530d1264cfceb5555870eb9546, the patch for the issue, is included in version 0.5.0b3.dev89.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
pyload-ngPyPI | < 0.20 | 0.20 |
Patches
1909e5c978852Fix Improper Neutralization of Input code injection interactive.user (#4586)
1 file changed · +94 −92
src/pyload/webui/app/static/js/captcha-interactive.user.js+94 −92 modified@@ -1,7 +1,7 @@ // ==UserScript== // @name pyLoad Script for Interactive Captcha // @namespace https://pyload.net/ -// @version 0.19 +// @version 0.20 // @author Michi-F, GammaC0de // @description pyLoad Script for Interactive Captcha // @homepage https://github.com/pyload/pyload @@ -35,97 +35,99 @@ */ (function() { - 'use strict'; + 'use strict'; - // this function listens to messages from the pyload main page - window.addEventListener('message', function(e) { - try { - var request = JSON.parse(e.data); - } catch(e) { - return - } - if(request.constructor === {}.constructor && request.actionCode === "pyloadActivateInteractive") { - if (request.params.script) { - var sig = new KJUR.crypto.Signature({"alg": "SHA384withRSA", "prov": 'cryptojs/jsrsa'}); - sig.init("-----BEGIN PUBLIC KEY-----\n" + - "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuEHE4uAeTeEQjIwB//YH\n" + - "Gl5e058aJRCRyOvApv1iC1ZQgXGHopgEd528+AtkAZKdCRkoNCWda7L/hROpZNjq\n" + - "xgO5NjjlBnotntQiZ6xr7A4Kfdctmw1DPcv/dkp6SXRpAAw8BE9CctZ3H7cE/4UT\n" + - "FIJOYQQXF2dcBTWLnUAjesNoHBz0uHTdvBIwJdfdUIrNMI4IYXL4mq9bpKNvrwrb\n" + - "iNhSqN0yV8sanofZmDX4JUmVGpWIkpX0u+LA4bJlaylwPxjuWyIn5OBED0cdqpbO\n" + - "7t7Qtl5Yu639DF1eZDR054d9OB3iKZX1a6DTg4C5DWMIcU9TsLDm/JJKGLWRxcJJ\n" + - "fwIDAQAB\n" + - "-----END PUBLIC KEY----- "); - sig.updateString(request.params.script.code); - if (sig.verify(request.params.script.signature)) { - window.gpyload = { - isVisible : function(element) { - var style = window.getComputedStyle(element); - return !(style.width === 0 || - style.height === 0 || - style.opacity === 0 || - style.display ==='none' || - style.visibility === 'hidden' - ); - }, - debounce : function (fn, delay) { - var timer = null; - return function () { - var context = this, args = arguments; - clearTimeout(timer); - timer = setTimeout(function () { - fn.apply(context, args); - }, delay); - }; - }, - submitResponse: function(response) { - if (typeof gpyload.observer !== 'undefined') { - gpyload.observer.disconnect(); - } - var responseMessage = {actionCode: "pyloadSubmitResponse", params: {response: response}}; - parent.postMessage(JSON.stringify(responseMessage),"*"); - }, - activated: function() { - var responseMessage = {actionCode: "pyloadActivatedInteractive"}; - parent.postMessage(JSON.stringify(responseMessage),"*"); - }, - setSize : function(rect) { - if (gpyload.data.rectDoc.left !== rect.left || gpyload.data.rectDoc.right !== rect.right || gpyload.data.rectDoc.top !== rect.top || gpyload.data.rectDoc.bottom !== rect.bottom) { - gpyload.data.rectDoc = rect; - var responseMessage = {actionCode: "pyloadIframeSize", params: {rect: rect}}; - parent.postMessage(JSON.stringify(responseMessage), "*"); - } - }, - data : { - debounceInterval: 1500, - rectDoc: {top: 0, right: 0, bottom: 0, left: 0} - } - }; - - try { - eval(request.params.script.code); - } catch(err) { - console.error("pyLoad: Script aborted: " + err.name + ": " + err.message + " (" + err.stack +")"); - return; - } - if (typeof gpyload.getFrameSize === "function") { - var checkDocSize = gpyload.debounce(function() { - window.scrollTo(0,0); - var rect = gpyload.getFrameSize(); - gpyload.setSize(rect); - }, gpyload.data.debounceInterval); - gpyload.observer = new MutationObserver(function(mutationsList) { - checkDocSize(); - }); - var js_script = document.createElement("script"); - js_script.type = "text/javascript"; - js_script.innerHTML = "gpyload.observer.observe(document.querySelector('body'), {attributes:true, attributeOldValue:false, characterData:true, characterDataOldValue:false, childList:true, subtree:true});"; - document.getElementsByTagName('body')[0].appendChild(js_script); - } - } else { - console.error("pyLoad: Script signature verification failed") - } + // this function listens to messages from the pyload main page + window.addEventListener('message', function(e) { + let request; + try { + request = JSON.parse(e.data); + } catch(e) { + return + } + if(request.constructor === {}.constructor && request.actionCode === "pyloadActivateInteractive") { + if (request.params.script) { + const sig = new KJUR.crypto.Signature({"alg": "SHA384withRSA", "prov": 'cryptojs/jsrsa'}); + sig.init("-----BEGIN PUBLIC KEY-----\n" + + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuEHE4uAeTeEQjIwB//YH\n" + + "Gl5e058aJRCRyOvApv1iC1ZQgXGHopgEd528+AtkAZKdCRkoNCWda7L/hROpZNjq\n" + + "xgO5NjjlBnotntQiZ6xr7A4Kfdctmw1DPcv/dkp6SXRpAAw8BE9CctZ3H7cE/4UT\n" + + "FIJOYQQXF2dcBTWLnUAjesNoHBz0uHTdvBIwJdfdUIrNMI4IYXL4mq9bpKNvrwrb\n" + + "iNhSqN0yV8sanofZmDX4JUmVGpWIkpX0u+LA4bJlaylwPxjuWyIn5OBED0cdqpbO\n" + + "7t7Qtl5Yu639DF1eZDR054d9OB3iKZX1a6DTg4C5DWMIcU9TsLDm/JJKGLWRxcJJ\n" + + "fwIDAQAB\n" + + "-----END PUBLIC KEY----- "); + sig.updateString(request.params.script.code); + if (sig.verify(request.params.script.signature)) { + window.gpyload = { + isVisible : function(element) { + const style = window.getComputedStyle(element); + return !(style.width === 0 || + style.height === 0 || + style.opacity === 0 || + style.display ==='none' || + style.visibility === 'hidden' + ); + }, + debounce : function (fn, delay) { + let timer = null; + return function () { + const context = this, args = arguments; + clearTimeout(timer); + timer = setTimeout(function () { + fn.apply(context, args); + }, delay); + }; + }, + submitResponse: function(response) { + if (typeof gpyload.observer !== 'undefined') { + gpyload.observer.disconnect(); + } + const responseMessage = {actionCode: "pyloadSubmitResponse", params: {response: response}}; + parent.postMessage(JSON.stringify(responseMessage),"*"); + }, + activated: function() { + const responseMessage = {actionCode: "pyloadActivatedInteractive"}; + parent.postMessage(JSON.stringify(responseMessage),"*"); + }, + setSize : function(rect) { + if (gpyload.data.rectDoc.left !== rect.left || gpyload.data.rectDoc.right !== rect.right || gpyload.data.rectDoc.top !== rect.top || gpyload.data.rectDoc.bottom !== rect.bottom) { + gpyload.data.rectDoc = rect; + const responseMessage = {actionCode: "pyloadIframeSize", params: {rect: rect}}; + parent.postMessage(JSON.stringify(responseMessage), "*"); + } + }, + data : { + debounceInterval: 1500, + rectDoc: {top: 0, right: 0, bottom: 0, left: 0} } + }; + + try { + let scriptFunction = new Function('request', 'gpyload', '"use strict";' + request.params.script.code); + scriptFunction(request, gpyload); + } catch(err) { + console.error("pyLoad: Script aborted: " + err.name + ": " + err.message + " (" + err.stack +")"); + return; + } + if (typeof gpyload.getFrameSize === "function") { + const checkDocSize = gpyload.debounce(() => { + window.scrollTo(0,0); + var rect = gpyload.getFrameSize(); + gpyload.setSize(rect); + }, gpyload.data.debounceInterval); + gpyload.observer = new MutationObserver(function(mutationsList) { + checkDocSize(); + }); + const js_script = document.createElement("script"); + js_script.type = "text/javascript"; + js_script.innerHTML = "gpyload.observer.observe(document.querySelector('body'), {attributes:true, attributeOldValue:false, characterData:true, characterDataOldValue:false, childList:true, subtree:true});"; + document.getElementsByTagName('body')[0].appendChild(js_script); + } + } else { + console.error("pyLoad: Script signature verification failed") } - }); -})(); \ No newline at end of file + } + } + }); +})();
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5News mentions
0No linked articles in our index yet.