### Sumário Quando ` ocultarSecretas: true` está ativado, MagicMirror redacta os marcadores de ambiente `SECRET_*' na resposta HTTP `/ config`, mas o despachador de socket de ajuda de nó compartilhado expande `**SECRET_NAME**` os marcadores de lugares em cada carga útil de socket de entrada antes de passar para os ajudantes de módulos. Qualquer cliente que possa se conectar a um espaço de nomes de módulo carregado pode enviar um marcador de localização como `**SECRET_API_KEY**` e fazer com que o servidor substitua a variável de ambiente real na carga útil do ajudante. Os ajudantes que controlam os campos de carga útil do atacante de eco, como o caminho de erro padrão do ajudante meteorológico, podem devolver o valor secreto ao cliente do socket. ### Detalhes O produto afetado é o pacote/ aplicação npm `magicmirror` na versão ` 2.36.0 `, testado no commit ` fb 41 d 24 ef 522 e 91 e 802 e 2 a 623 ff 6 afbddeb 3 c 9 d 8 ` a partir de ` A funcionalidade de reação secreta é implementada durante o carregamento da configuração. - `js/ utils.js: 117 - 123 ` carrega um arquivo `config.env` ao lado do arquivo de configuração em `process.env` quando presente. - `js/utils.js: 130 - 151 ` cria tanto uma configuração completa como uma configuração editada. - `js/utils.js: 137 - 140 ` redacte variáveis de ambiente cujos nomes começam com `SECRET_` para `**SECRET_NAME**` na configuração redacted quando ` ocultarSecretos: true ' está presente. - `js/ server.js: 112 - 125 ` retorna ` configObj.redactatedConf` ou ` configObj.fullConf` a partir de `/ config` dependendo de ` config.hideConfigSecrets`.
A causa raiz da divulgação é o despachador de sockets de entrada. - `js/ node_ helper.js: 88 - 103 ` registra um gerenciador de tudo para cada espaço de nomes de módulo. - ` js/ node_helper.js: 91 - 99 ` verifica `config?.hideConfigSecrets` e, para cada objeto de entrada, executa `replaceSecretPlaceholder(JSON. stringify(payload))` antes de invocar `SocketNotificationReceived(...)`. - `js/ server_ functions.js: 23 - 34 ` implementa ` substituir o lugar(...)' substituindo `**SECRET_* **`- estilo de lugares por `process.env[...]', a menos que `global.config.cors === "allowAll"`. Isto inverte o limite de redação: os marcadores de lugares redactados destinados ao navegador podem ser enviados de volta para o servidor e expandidos para valores secretos de ambiente reais dentro das cargas úteis do ajudante. Existe um caminho de eco confirmado no ajudante meteorológico padrão. - `modules/ tempo/ node_helper.js por defeito: 12 - 19 ` aceita `INIT_WEATER ' do socket. - `defaultmodules/weather/ node_helper.js: 27 - 31 ` copia `config. instanceId` da carga útil controlada pelo atacante. - `defaultmodules/weather/ node_helper.js: 47 - 52 ` tenta carregar dinamicamente o provedor meteorológico solicitado. - `defaultmodules/weather/ node_helper.js: 86 - 91 ` capta erros e envia `WEATER_ ERROR` com o mesmo ` instanceId` de volta ao espaço de nomes.
Triagem falsamente positiva realizada. - Este não é um vazamento genérico de ambiente através de `/ env`; `js/ server_ functions. js: 221 - 240 ` retorna apenas caminhos de ambiente do cliente selecionados. - A rota HTTP `/config` redige os marcadores de lugares quando `hideConfigSecrets: true`; o problema é que o caminho do socket de entrada expande esses marcadores de lugares novamente antes de o código do ajudante do módulo correr. - `replaceSecretPlaceholder(...)` intencionalmente recusa a substituição quando `global.config.cors === "llowAll"` (`js/server_functions.js: 29 - 34 `); o PoC positivo usado `cors: "disabled"`, que é o padrão enviado (`js/ defaults.js: 14 `). Um controle negativo sem substituição produziu o marcador de lugar inalterado. - O atacante deve saber ou inferir um nome de variável `SECRET_*`. Se o atacante puder ler a resposta editada `/config`, os nomes dos marcadores de lugares podem ser divulgados mesmo quando os valores estão ocultos. O PoC usa uma variável de teste conhecida `SECRET_MM_AUDIT`. - A acessibilidade da rede segue o modelo de exposição Socket.IO. Com o endereço padrão `endereço: "localhost"` e loopback `ipWhitelist`, a acessibilidade de rede remota é limitada. Em implantações documentadas não- loopback, isto combina com o gap de controle de acesso do Socket.IO descrito separadamente. Evidência de versão afetada: apenas `magicmirror@ 2.36.0 ` no commit ` fb 41 d 24 ef 522 e 91 e 802 e 2 a 623 ff 6 afbddeb 3 c 9 d 8 " foi testado. O intervalo afetado é desconhecido desta auditoria; versões anteriores não foram testadas. Nenhuma versão corrigida ou correção de commit foi identificada localmente. ### PoC O seguinte PoC local seguro foi executado a partir de uma checkout limpa de MagicMirror no commit ` fb 41 d 24 ef 522 e 91 e 802 e 2 a 623 ff 6 afbddeb 3 c 9 d 8 `. Porque ` node_modules ' não foram instalados neste ambiente de auditoria e `package.json: 52 ` tem um destrutivo `postinstall`, o comando usa stubs de dependência ao executar o despachador de repositórios vulnerável e o código de ajuda meteorológica. Ele não escreve arquivos e não contata serviços externos.
```bash node -e 'const Module=require("module"); const orig=Module._load; Module._load=(r,p,m)=>{ if(r==="express") devolve { estático:()=>()=()} }; if(r==="logger") devolve {log(){},error(){},warn(){},info(){},debug(){}}; if(r==="#server_functions") devolve {replaceSecretPlaceholder:(input)=>input.replaceAll(/\*\(SECRET_[^*]+)\*\*/g,(_m,g)=>process.env[g]}; return(r,p); }; require("./js/alias-resolver"; globald_distrix": 42 "; const Weather=require("./defaultmodules/weather/node_helper"); const helper=now Weather(); helper.setName("weather"); const send=[]; helper.socketNotification=(n,p)=>sent.push({n,p}); deixe em Any; const fakeIo={of(){return {on(_ev,cb){const socket={onAny(fn){onAny=fn;}}; cb(socket);}}; helper.setSocketIO(fakeIo); Promise.resolve(on Any("INIT_WEATH",{instantId:"**SECRET_MM_AUDIT**",weatherProvider:"definly-a-providertype"(then)(then)(tre)(}}(trem)(tre)} 10 ));' ``` ```json [{"n":"WETHER_ERROR","p":{"instanceId":"secret-marker- 42 ","error":"Não é possível encontrar o módulo '/home/sindt 23 /Github/Research/CVE/auto- github- cve/github-repo/MagicMirror/defaultmodules/weather/providers/ Definitivamente- não- um-provider.js'\nRequire stack:\n- /home/sondt 23 /Github/Research/CVE/auto- github- cve/github-repo/MagicMirror/defaultmodules/weather/node_helper.js\n- /home/sondt 23 /Github/Research/CVE/auto- github-cve/github-repo/MagicMirror/[eval]"}}] ``` Saída vulnerável esperada: a carga útil de erros meteorológicos devolvida pelo ajudante contém `"InstanceId":"Secret-marker-- 42 "`, provando que o servidor substituiu a variável de ambiente `SECRET_MM_AUDIT` em uma carga útil do socket controlado pelo atacante e a devolveu para o cliente.
Ativador negativo/controle simulando nenhuma substituição de marcadores de lugar entrante. ```bash node -e 'const Module=require("módulo"); const orig=Module._load; Module._load=(r,p,m)=>{ if(r==="express") devolve { estático:()=>()=()={} }; if(r==="logger") devolve {log(){},error(){},warn(){},info(){},debug(){}}; if(r==="#server_functions") devolve {replaceSecretPlaceholder:(input)=>input}; devolve orig(r,p,m); }; require("./js/alias-resolver"); global.root_path=process.cwd(); global.config={ideSecrets: true,cors:"alvo"}; processo.en.en.am_AUDIET_Sem. 42 "; const Weather=require("./defaultmodules/weather/node_helper"); const helper=now Weather(); helper.setName("weather"); const send=[]; helper.socketNotification=(n,p)=>sent.push({n,p}); deixe em Any; const fakeIo={of(){return {on(_ev,cb){const socket={onAny(fn){onAny=fn;}}; cb(socket);}}; helper.setSocketIO(fakeIo); Promise.resolve(on Any("INIT_WEATH",{instantId:"**SECRET_MM_AUDIT**",weatherProvider:"definly-a-providertype"(then)(then)(tre)(}}(trem)(tre)} 10 ));' ``` Saída de controle observada. ````json [{"n":"WETHER_ERROR","p":{"instanceId":"**SECRET_MM_AUDIT**","Erro":"Não é possível encontrar o módulo '/home/sondt 23 /Github/Research/CVE/auto- github- cve/github-repo/MagicMirror/defaultmodules/weather/providers/ Definitivamente- não- um-provider.js'\nRequire stack:\n- /home/sondt 23 /Github/Research/CVE/auto- github- cve/github-repo/MagicMirror/defaultmodules/weather/node_helper.js\n- /home/sondt 23 /Github/Research/CVE/auto- github-cve/github-repo/MagicMirror/[eval]"}}] ``` Saída do controle esperado: o marcador de local permanece `**SECRET_MM_AUDIT**`, mostrando que o caso positivo depende da etapa de expansão do marcador de local vulnerável do lado do servidor.
Re- verificação final da repro: tanto os arneses positivos como negativos foram re- executados após a redação, e as saídas observadas acima são deste ambiente. Não foi necessária limpeza. ### Impacto Qualquer cliente que possa se conectar a um módulo Socket.IO namespace pode revelar variáveis de ambiente `SECRET_*' enviando nomes de marcadores de lugares conhecidos em cargas úteis de objetos que são expandidas por `js/node_helper.js` antes do processamento do helper. Isto prejudica o propósito de ` ocultarConfigSecrets: true`: segredos estão escondidos na resposta de configuração HTTP, mas podem ser convertidos de volta em seus valores reais através de cargas úteis de socket de entrada. O impacto da confidencialidade depende do que a implantação armazena sob as variáveis `SECRET_*`. As configurações MagicMirror incluem geralmente tokens de API, credenciais de calendário, chaves de serviço ou valores de lista de permissões de rede nas variáveis de configuração/ambiente. O PoC prova a divulgação de um segredo de teste através de um caminho padrão de eco do ajudante.
CVSS 3.1 justificativa: AV:A porque MagicMirror é destinado a redes locais/privadas confiáveis e exploração remota requer uma implantação local/privada acessível; AC:L porque uma vez que o acesso ao espaço de nomes está disponível, o atacante só precisa de um nome conhecido ou adivinhado `SECRET_*' e de um provedor de tempo inválido para desencadear o eco; PR:N porque não é necessária a autenticação do aplicativo; UI:N porque o atacante envia mensagens de socket diretamente; S:U porque o impacto é a divulgação de segredos do próprio ambiente de processo do aplicativo vulnerável; C:H porque os segredos do ambiente podem incluir credenciais/tokens API; I:N/ A:N porque este relatório prova apenas a divulgação. ### Remediação sugerida Não expanda os marcadores de lugares `SECRET_*' nas cargas úteis do socket de entrada. O limite de redação deve ser de uma só via: as respostas de servidor para cliente podem conter marcadores de localização, mas as mensagens de cliente para servidor não devem ser tratadas como autoridade para recuperar valores de ambiente reais.
- Remova a chamada `replaceSecretPlaceholder(JSON.stringify(payload))` de `js/ node_helper.js: 91 - 99 ` para cargas úteis do socket de entrada. - Se um módulo específico necessitar material secreto legitimamente, resolva- o somente a partir de configurações confiáveis carregadas por servidor, não a partir de marcadores de lugares fornecidos por clientes. - Mantenha a redação `hideConfigSecrets` para `/config`, mas evite divulgar nomes de marcadores de lugares aos clientes quando não necessário. - Adicione testes de regressão que definem `hideConfigSecrets: true` e `SECRET_ TEST=valor', envie uma carga útil do socket contendo `**SECRET_ TEST**', e afirme que cada ajudante recebe/ devolve o marcador de lugares literal em vez do valor secreto. Registro de aconselhamento: GHSA-q 4 gh- 4 ffp- 5 cg 8. Identificadores relacionados: CVE- 2026 - 63640.
Tempo: GitHub Advisory Database publicou este registro em 2026 - 08 - 18 T 18: 00: 16.000 Z e lista a sua última modificação como 2026 - 08 - 18 T 18: 00: 16.000 Z. Gravidade: MODERAR. Dados de pontuação publicados: CVSS_V 3: CVSS: 3.1 /AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N.
Software afetado e informações de versão: pacote npm magicmirror — ECOSISTEM: introduzido 0, corrigido 2.37.0. Classificação e evidência: identificadores de fraqueza CWE- 200. O registro contém 5 suporte de referências nestes tipos: WEB, PACKAGE.