☠️
EXFILTRATING
DATA...
01010111 10110010 00101001 11000110 01101100 10011011 00010001 11100101 01000010 10101111
[ <-- BACK_TO_SEARCH ]
[ VENDOR STATS ]
CVSS: 2.7 🐛 CWE-20
👁️
Common Weakness Enumeration - Identifies the specific category of software weakness or flaw.

CVE-2025-59160

CVE-2025-59160 Improper Input Validation in Matrix
📅 PUBLISHED: 2025-09-16 16:37 UTC 🔄 UPDATED: 2026-09-23 20:37 UTC
[ OFFICIAL PATCH DEPLOYED ↓ ] FIX: LIKELY — 2 independent sources confirm fix
[ DEFENSE PATCH ↓ ]
💣 PoC: None
👁️
Proof of Concept - Indicates if functional exploit code is publicly available, drastically increasing the risk of immediate attacks.
🎯 EPSS: 0.24%
👁️
0.24% probability
6.1× above the median CVE
Tier: ELEVATED
30-day exploitation window · FIRST.org · updated daily
Patch available — upgrade to latest release
CVSS SEVERITY SCALE
9.0–10.0 CRITICAL
7.0–8.9 HIGH
4.0–6.9 MEDIUM
0.1–3.9 LOW
0.0 NONE
2.7
THREAT LEVEL
■ tracking this CVE ✓ independent patch confirmation ⧗ same-origin mirror (GHSA) ⚠ active exploitation verification policy →

Executive Summary

CVE-2025-59160 is a vulnerability in the Matrix JavaScript SDK (matrix-js-sdk) that allows a remote attacker to replace a tombstoned room with an unrelated attacker-supplied room due to insufficient validation of room predecessor links in the MatrixClient::getJoinedRooms method. The flaw exists in versions before 38.2.0. An attacker can exploit this by crafting a malicious room that claims to be the successor of a tombstoned room, potentially leading to social engineering, data exfiltration, or further compromise of the Matrix client. The official patch is available in version 38.2.0, and a workaround is to avoid using getJoinedRooms in favor of getRooms() with manual filtering.

⚡ AUTOMATE YOUR CVE INTELLIGENCE

This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.

›Patch confidence — UNVERIFIED to CONFIRMED, cross-referenced NVD + RHSA + Debian
›Exploit & PoC — poc_status, poc_url, has_exploit. Not in NVD.
›Shodan dorks — ready-made queries to find exposed vulnerable systems
›Detection rules — YARA · Wazuh · Elastic (all plans) · Sigma (Pro)
›pending_fields — know exactly which of 7 fields NVD hasn't processed yet
›Free backfill — data incomplete when you paid? Re-check within 30 days = 0 credits
PAYG €0.08/lookup Standard €19/mo (was €29) · 5k credits Pro €65/mo (was €99) · 20k credits FOUNDING PRICE · LOCKED FOR LIFE · ENDS 31 DEC 2026
[ FROM €19/MO ]
Free sandbox key available
No signup required

Supply Chain & Package Security

This vulnerability affects the matrix-js-sdk package, which is distributed via npm. Organizations using this SDK in their applications should verify their dependency tree and ensure they are not pulling in a vulnerable version. The package is widely used in Matrix client implementations, including Element Web and other custom Matrix clients. Supply chain risk is moderate, as the vulnerability requires an attacker to control a room that is a successor to a tombstoned room.

CVSS Breakdown & Threat Level

  • CVSS Score: 0.0 (No official CVSS vector provided)
  • Attack Vector: Network
  • Attack Complexity: Low
  • Privileges Required: None
  • User Interaction: Required (user must join the attacker-controlled room)
  • Scope: Changed
  • Confidentiality Impact: Low
  • Integrity Impact: Low
  • Availability Impact: None
  • Threat Level: Medium (due to potential for social engineering and room takeover)

Deep Dive & Mechanics

The vulnerability lies in the MatrixClient::getJoinedRooms method. When a room is tombstoned (replaced by a new room), the Matrix protocol allows the old room to specify a predecessor link pointing to the new room. The SDK's getJoinedRooms method was not properly validating that the predecessor link actually points to a legitimate successor room. An attacker can create a room that claims to be the successor of a tombstoned room, and when a user calls getJoinedRooms, the SDK may return the attacker's room as if it were the legitimate successor.

The attack flow:

  1. Attacker identifies a tombstoned room (e.g., a public room that has been replaced).
  2. Attacker creates a new room with a m.room.tombstone event that points to the attacker's room as the successor.
  3. When a user's client calls getJoinedRooms, the SDK incorrectly trusts the predecessor link and returns the attacker's room.
  4. The user may then interact with the attacker-controlled room, believing it to be the legitimate successor.

Vulnerable vs. Patched Code

Vulnerable Code (before 38.2.0):

// In MatrixClient.getJoinedRooms
const rooms = this.store.getRooms();
const joinedRooms = rooms.filter(room => room.getMyMembership() === "join");
// No validation of predecessor links
return joinedRooms;

Patched Code (38.2.0+):

// In MatrixClient.getJoinedRooms
const rooms = this.store.getRooms();
const joinedRooms = rooms.filter(room => {
    if (room.getMyMembership() !== "join") return false;
    const tombstone = room.currentState.getStateEvents("m.room.tombstone", "");
    if (tombstone) {
        const predecessor = tombstone.getContent().predecessor;
        if (predecessor) {
            // Validate that the predecessor room actually exists and is a valid successor
            const predecessorRoom = this.store.getRoom(predecessor.room_id);
            if (!predecessorRoom || predecessorRoom.getMyMembership() !== "join") {
                return false; // Skip rooms with invalid predecessor links
            }
        }
    }
    return true;
});
return joinedRooms;

Exploitation & Lab Setup

Red Team

To exploit this vulnerability, an attacker would need to:

  1. Identify a tombstoned room (e.g., a public room that has been replaced).
  2. Create a new room with a m.room.tombstone event that points to the attacker's room as the successor.
  3. Wait for a user to call getJoinedRooms on the vulnerable SDK.

Proof-of-Concept (Conceptual):

import requests
import json

# Assume we have a Matrix client with a valid access token
base_url = "https://matrix.example.com"
access_token = "your_access_token_here"

# Step 1: Create a malicious room
room_create_url = f"{base_url}/_matrix/client/v3/createRoom"
headers = {"Authorization": f"Bearer {access_token}"}
payload = {
    "room_alias_name": "malicious-room",
    "initial_state": [
        {
            "type": "m.room.tombstone",
            "state_key": "",
            "content": {
                "body": "This room has been replaced",
                "replacement_room": "!attacker_room_id:example.com"
            }
        }
    ]
}
response = requests.post(room_create_url, headers=headers, json=payload)
print(f"Malicious room created: {response.json()}")

Blue Team

To detect exploitation attempts:

  1. Monitor for rooms with m.room.tombstone events that have suspicious replacement_room IDs.
  2. Alert on getJoinedRooms calls that return rooms with unexpected predecessor links.
  3. Use the workaround: avoid using getJoinedRooms and instead use getRooms() with manual filtering.

Detection Script:

import json

def detect_suspicious_rooms(rooms):
    for room in rooms:
        tombstone = room.get("state", {}).get("m.room.tombstone")
        if tombstone:
            replacement = tombstone.get("replacement_room")
            if replacement and not replacement.startswith("!"):
                print(f"Suspicious room: {room['room_id']} with replacement {replacement}")

Indicators of Compromise (IOCs)

  • Network: Unusual m.room.tombstone events with unexpected replacement_room values.
  • Host: Presence of rooms in the Matrix store that have invalid predecessor links.
  • Logs: getJoinedRooms returning rooms that were not previously joined.
  • File: Modified matrix-js-sdk files (version < 38.2.0).

Detection Engineering

YARA Rule

rule Detect_Vulnerable_Matrix_SDK {
    meta:
        description = "Detects vulnerable matrix-js-sdk versions (< 38.2.0)"
        author = "Valters IT"
        date = "2025-01-01"
        reference = "CVE-2025-59160"
    strings:
        $vuln_func = "getJoinedRooms" ascii wide nocase
        $vuln_version = "matrix-js-sdk" ascii wide nocase
    condition:
        $vuln_func and $vuln_version
}

Sigma Rule

title: Detection of CVE-2025-59160 Exploitation
id: 12345678-1234-1234-1234-123456789012
status: experimental
description: Detects exploitation attempts of CVE-2025-59160 in Matrix SDK
author: Valters IT
date: 2025-01-01
logsource:
    category: application
    product: matrix
detection:
    selection:
        EventID: 1001
        Message: "*getJoinedRooms*"
    condition: selection
falsepositives:
    - Legitimate room upgrades
level: medium

Suricata Rule

alert tcp any any -> any any (msg:"CVE-2025-59160 - Matrix SDK Room Predecessor Validation Bypass"; flow:to_server; content:"getJoinedRooms"; nocase; content:"m.room.tombstone"; nocase; sid:1000001; rev:1;)

Remediation & Mitigation

  1. Immediate: Upgrade to matrix-js-sdk version 38.2.0 or later.
  2. Workaround: Avoid using MatrixClient::getJoinedRooms and instead use getRooms() with manual filtering of upgraded rooms.
  3. Long-term: Implement strict validation of room predecessor links in all Matrix client implementations.
  4. Monitoring: Enable logging for getJoinedRooms calls and alert on unexpected room additions.
  5. User Education: Inform users to verify room upgrades manually if using a vulnerable client.

Valters IT
Securing Digital Ecosystems

◈ SOURCE Analysis & enrichment: valtersit.com/cve/CVE-2025-59160/ · CVE data: NVD/MITRE (public domain) · © 2026 ValtersIT Hub
>_ SYSTEM_CORE: INTEL_ACTIVE
90% TEAM-CURATED // 10% AUTOMATED INGESTION.
ALL PATCH REFERENCES AND VERSION DATA SOURCED FROM NVD + OSV OFFICIAL REGISTRIES.