Twenty: Cleartext IMAP, SMTP and CalDAV Passwords Through the `/metadata` GraphQL API
Any member of a workspace reads the cleartext password, host, port and username of every other member's mail accounts with a single GraphQL query.
Advisory ID: TP-2026-080
Product: Twenty (open-source CRM)
Vulnerability type: Insufficiently protected credentials (CWE-522)
CVE: CVE-2026-105763
CVSS 3.1: 9.6 (Critical) · CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N
Affected versions: >= 1.20.10, < 2.7.0
Vendor advisory: GHSA-mq5c-qp77-2cv3
Fixed in: 2.7.0
Reported: 16 May 2026
Summary
Twenty is an open-source CRM in which users connect their mail accounts over IMAP, SMTP and CalDAV so that messages and appointments appear inside the CRM. The connectedAccounts query of the /metadata GraphQL API returned the connection parameters of every connected account in the workspace, and for IMAP, SMTP and CalDAV connections that object carried the password, which at the time was stored in plaintext. Because the field did not carry the protective annotation its neighbours carry, the query was not narrowed to the calling account, and account visibility was not enforced, any member read the password, host, port and username of every other member's mail accounts in the same workspace. The default Member role was enough and no user interaction was required. Workspaces using only Google or Microsoft OAuth were not affected.
Root cause
The connectedAccounts query returned the connection parameters of every connected account in the workspace, because the backing lookup filters on workspaceId alone (packages/twenty-server/src/engine/metadata-modules/connected-account/connected-account-metadata.service.ts:40-42, resolver in packages/twenty-server/src/engine/metadata-modules/connected-account/resolvers/connected-account.resolver.ts:51-57). The connectionParameters field was a regular GraphQL output value, while the neighbouring secrets accessToken, refreshToken and oidcTokenClaims in the same DTO are removed from the schema with @HideField() (packages/twenty-server/src/engine/metadata-modules/connected-account/dtos/connected-account.dto.ts:58-60, neighbours at :32, :35, :67). The referenced output type carries password as an ordinary field, and a comment in the same file records the plaintext storage as a deliberate decision (packages/twenty-server/src/engine/core-modules/imap-smtp-caldav-connection/dtos/imap-smtp-caldav-connection.dto.ts:55-56 and :20-26). The resolver's guard checks only the connected-account permission flag, which the default Member role holds, and the visibility attribute of an account (connected-account.dto.ts:93-95) was never evaluated. Version 2.7.0 puts @HideField() on connectionParameters, routes myConnectedAccounts through buildPublicConnectedAccount, scopes the lookups to the caller's userWorkspaceId and encrypts the credentials at rest.
Proof of Concept
POST /metadata
Authorization: Bearer <token of a workspace member, default Member role>
query {
connectedAccounts {
handle
connectionParameters {
IMAP { host port username password }
SMTP { host port username password }
CALDAV { host port username password }
}
}
}
-> the response carries the cleartext password of every member of the workspace
The password field is part of the schema and therefore selectable, and the lookup narrows to the workspace only. A single query is enough, with no decryption, no chained primitive and no user interaction.
Impact
- Disclosure of the cleartext password, host, port and username of every IMAP, SMTP and CalDAV account in the same workspace.
- Full access to the victim's mailbox at the external provider: reading, sending and deleting mail.
- Takeover of third-party accounts through password resets sent to the controlled mail address.
- Access to the connected calendars through the CalDAV credentials.
References
Is Something Like This in Your Software?
Our team found this vulnerability in the course of its work. Have your applications tested by the same specialists, with a penetration test from turingpoint.
