On July 27, 2023, security researchers published details of a critical vulnerability in matrix-appservice-bridge, a popular Node.js package used to build bridges between the Matrix ecosystem and other chat platforms. This vulnerability, tracked as CVE-2023-38691, could allow a malicious server to impersonate any user via the provisioning API, impacting Matrix deployments that rely on third-party bridges.
This post dives into what CVE-2023-38691 is, why it’s dangerous, includes technical details with code snippets, provides links to original references, and walks you through how the exploit works—in plain English.
What is matrix-appservice-bridge?
matrix-appservice-bridge is a JavaScript library that helps developers connect Matrix servers (like Synapse or Dendrite) with other chat applications. Bridges built with this library commonly provide a provisioning API so admins can manage user connections between platforms.
Details of the Vulnerability
Affected Versions:
All versions from 4.. up to (but not including) 8.1.2 and 9..1
Fixed in:
9..1 (for users on v9.x)
CVE Entry: NVD - CVE-2023-38691
Matrix Security Disclosure: GitHub advisory GHSA-7v6j-g86p-rq63
The Vulnerability, In Simple Terms
When a bridge needs to confirm a user's identity, it sometimes uses Matrix's OpenID Connect protocol. A key part of OpenID is that the provider returns a “subject” identifier, typically the user’s MXID (Matrix ID, like @alice:matrix.org).
Here’s the bug:
The library accepted any MXID in the OpenID response without checking _which server issued it_.
So, if a Matrix bridge is set up to trust a specific server (say matrix.example.com), but another server (malicious-actor.com) sets up its own OpenID endpoint, the attacker can say the subject is @admin:matrix.example.com (even though they're not!). The bridge will trust this and allow the attacker to control resources or impersonate that user in the provisioning API.
Example: Code Snippet Showing Missing Check
Before the patch, the code did not check that the sub value matched the server we’re talking to. Here’s a simplified version:
// BAD: Prior to fix, the code did not check servername matches
const userInfo = await getUserInfoFromOpenID(openidToken);
// Returns something like { sub: "@foo:matrix.org" }
// It should verify "matrix.org" is the server we're talking to
// But... it doesn't! It just trusts whatever comes from userInfo.sub
const mxid = userInfo.sub; // e.g., "@admin:matrix.org"
provisioningApi.provision(mxid); // Oops! Anyone can impersonate.
Fixed code (simplified)
// GOOD: Now, it verifies domain matches
const userInfo = await getUserInfoFromOpenID(openidToken);
// Extract servername from sub
const mxidServer = userInfo.sub.split(":")[1];
// Compare to the homeserver expected
if (mxidServer !== expectedHomeserver) {
throw new Error("Invalid server name in sub!");
}
Bridges could accidentally (or on purpose) give unauthorized users high privileges.
If you only use private bridges and don’t expose the provisioning API, risk is lower but still present.
Update to matrix-appservice-bridge 8.1.2 or 9..1 and above immediately!
- These versions now check that the server you are talking to actually matches the server part in the OpenID sub claim.
Workaround
If you cannot upgrade for any reason, disable the provisioning API in your bridge settings to prevent the vulnerability from being exploited.
Here’s a minimal sketch/example in JavaScript (for educational purposes)
// Imagine attacker controls "malicious-server.com"
// They reply to an OpenID request with:
const fakeOpenIdResponse = {
sub: "@admin:matrix.org", // Pretend to be the admin of matrix.org
// ... other valid OpenID fields ...
};
// Vulnerable bridge just trusts this
bridge.provisioningApi.provision(fakeOpenIdResponse.sub);
// Now, attacker acts as admin!
References and Further Reading
- Official CVE NVD Entry: CVE-2023-38691
- Matrix.org Security Advisory
- matrix-appservice-bridge GitHub
- Matrix OpenID Documentation
Conclusion
CVE-2023-38691 was a simple but serious bug that allowed Matrix bridges to trust foreign servers’ word about user identities, leading to easy impersonation attacks. The fix was also simple: always verify the domain in the OpenID sub parameter matches the server you actually trust.
If you run any bridges using matrix-appservice-bridge, upgrade now, and be sure to review your API exposures!
#### If you have any questions about this vulnerability, how it might impact your deployment, or want to see more code samples, let us know in the comments!
Timeline
Published on: 08/04/2023 17:15:00 UTC
Last modified on: 08/11/2023 19:34:00 UTC