{"record":{"id":"8e69f7c4143ae5a1","repo":"MagicMirrorOrg/MagicMirror","slug":"cors-proxy-is-disabled","errorCode":null,"errorMessage":"CORS proxy is disabled","messagePattern":"CORS proxy is disabled","errorType":"http","errorClass":null,"httpStatus":403,"severity":"error","filePath":"js/server_functions.js","lineNumber":60,"sourceCode":"\t\t// Load the real value from the environment. Fallback to placeholder if missing.\n\t\treturn process.env[secretName] || placeholder;\n\t});\n}\n\n/**\n * A method that forwards HTTP Get-methods to the internet to avoid CORS-errors.\n *\n * Example input request url: /cors?sendheaders=header1:value1,header2:value2&expectedheaders=header1,header2&url=http://www.test.com/path?param1=value1\n *\n * Only the url-param of the input request url is required. It must be the last parameter.\n * @param {Request} req - the request\n * @param {Response} res - the result\n * @returns {Promise<void>} A promise that resolves when the response is sent\n */\nasync function cors (req, res) {\n\tif (global.config.cors === \"disabled\") {\n\t\tLog.error(\"CORS is disabled, you need to enable it in `config.js` by setting `cors` to `allowAll` or `allowWhitelist`\");\n\t\treturn res.status(403).json({ error: \"CORS proxy is disabled\" });\n\t}\n\tlet url;\n\ttry {\n\t\tconst urlRegEx = \"url=(.+?)$\";\n\n\t\tconst match = new RegExp(urlRegEx, \"g\").exec(req.url);\n\t\tif (!match) {\n\t\t\turl = `invalid url: ${req.url}`;\n\t\t\tLog.error(url);\n\t\t\treturn res.status(400).send(url);\n\t\t} else {\n\t\t\turl = match[1];\n\t\t\tif (typeof global.config !== \"undefined\") {\n\t\t\t\tif (config.hideConfigSecrets) {\n\t\t\t\t\turl = replaceSecretPlaceholder(url);\n\t\t\t\t}\n\t\t\t}\n","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/MagicMirrorOrg/MagicMirror/blob/4b4a59534f7da01e4030e46029fe9dd649a7675e/js/server_functions.js#L42-L78","documentation":"The `/cors` proxy handler in js/server_functions.js:60 refuses to proxy when `global.config.cors` is set to the literal string `\"disabled\"`. It returns HTTP 403 with a JSON body `{ error: \"CORS proxy is disabled\" }` and logs that you must set `cors` to `allowAll` or `allowWhitelist`. The proxy exists so modules can fetch cross-origin resources (RSS, calendars, weather APIs) that lack CORS headers.","triggerScenarios":"A module or client issues a request like `/cors?url=https://...` while `config.cors === 'disabled'` in config.js (or `global.config` was initialized with that value); the request never reaches the URL parsing/SSRF checks because the feature check runs first.","commonSituations":"A user upgrades MagicMirror and the newer default `cors: 'disabled'` breaks a module that relied on the proxy; a config template copies `cors: 'disabled'` from a hardened/security-focused setup; deploying behind nginx where someone disabled the proxy thinking the webserver handles CORS, while modules still call `/cors?...`.","solutions":["Set `cors: 'allowAll'` in config.js if you accept unrestricted proxying, or `cors: 'allowWhitelist'` to restrict proxied hosts, then restart the mirror.","If you intentionally keep the proxy disabled, reconfigure the failing module to fetch its resource without the `/cors` endpoint (enable CORS on the upstream server, or use a module option that calls the backend directly).","Verify `global.config` is actually loaded from your config.js — check that config.js parses (no syntax errors) so your `cors` setting takes effect.","Check the server log for the companion message 'CORS is disabled, you need to enable it in `config.js` ...' to confirm which config file was loaded."],"exampleFix":"// before (config.js)\ncors: 'disabled',\n// after\ncors: 'allowWhitelist', // or 'allowAll'","handlingStrategy":"validation","validationCode":"// Before calling the proxy, confirm it is enabled on the server config:\nasync function proxyEnabled(baseUrl) {\n  const probe = await fetch(`${baseUrl}/cors?url=https://example.com`, { method: 'GET' });\n  const body = await probe.json().catch(() => ({}));\n  return !(probe.status === 403 && body.error === 'CORS proxy is disabled');\n}","typeGuard":"function isProxyDisabledResponse(body) {\n  return typeof body === 'object' && body !== null && body.error === 'CORS proxy is disabled';\n}","tryCatchPattern":"const res = await fetch(`/cors?url=${encodeURIComponent(target)}`);\nif (res.status === 403) {\n  const body = await res.json().catch(() => ({}));\n  if (body.error === 'CORS proxy is disabled') {\n    // fall back to direct fetch or instruct user to set cors: 'allowAll'|'allowWhitelist'\n  }\n  throw new Error(body.error ?? 'CORS proxy rejected the request');\n}","preventionTips":["Set `cors: 'allowAll'` or `cors: 'allowWhitelist'` in config.js whenever any module uses the /cors endpoint","Prefer 'allowWhitelist' so the proxy stays enabled but restricted","After MagicMirror upgrades, re-check config.js defaults — the cors setting may have changed","Document in module READMEs whether the /cors proxy is required","Surface the 403 JSON error in module UIs so users see the config fix instead of silent failure"],"tags":["cors","http-403","proxy","configuration"],"backgroundTag":"cors-proxy-disabled","analyzedSha":"4b4a59534f7da01e4030e46029fe9dd649a7675e","analyzedAt":"2026-08-31T21:49:42.591Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}