Jun 6, 2026·6 min read·29 visits
NocoDB fails to revoke OAuth tokens when a user changes or resets their password, allowing pre-existing OAuth grants to retain active API access.
NocoDB is subject to an insufficient session expiration vulnerability where OAuth access and refresh tokens are not invalidated or revoked during security-sensitive actions such as password changes, forgot-password requests, or password resets. This allows an attacker possessing an active OAuth token to maintain unauthorized persistence.
NocoDB is an open-source, no-code database platform that allows teams to transform databases into smart spreadsheets. Because NocoDB acts as a central hub for organizational data, it supports complex authentication structures, including standard web sessions and third-party integrations via OAuth. These interfaces expose various attack surfaces, especially when managing token lifetimes across security boundaries.
This security advisory details a critical session management vulnerability classified under CWE-613 (Insufficient Session Expiration). In NocoDB versions prior to 2026.05.1, OAuth access and refresh tokens are not invalidated or revoked when a user completes a password change, requests a forgot-password link, or executes a password reset. This defect allows previously issued OAuth grants to remain valid, establishing a persistent channel of unauthorized access.
While NocoDB correctly invalidated standard web sessions (via UserRefreshToken) during security-sensitive actions, the omission of OAuth token revocation represents a significant gap in the platform's security boundary. If an attacker possesses a valid OAuth token, they can maintain persistent, silent access to the database despite the victim actively changing their credentials.
The root cause of this vulnerability lies in the incomplete implementation of the token revocation logic within NocoDB's user management service. Session management in NocoDB operates on two distinct parallel paths: UserRefreshToken for browser-based user sessions, and OAuthToken for API and third-party integration authorization. This design separates standard user sessions from third-party application access to prevent user actions from unintentionally breaking valid external workflows.
Prior to the resolution in version 2026.05.1, when a user triggered security-sensitive events like password modification, forgot-password requests, or password resets, NocoDB invoked the UserRefreshToken.deleteAllUserToken(user.id) method. This successfully cleared active web-based sessions. However, the accompanying method responsible for purging OAuth-specific credentials, named revokeAllOAuthTokensByUser, was defined only as an empty stub inside the underlying UsersService layer.
As a consequence of this empty implementation, the metadata database holding OAuth mappings—including tables such as nc_api_tokens, nc_api_token_scopes, or related token schemas—remained unpurged. The application continued to accept these existing tokens because the validation middleware verified them against active database records that were never marked as revoked or deleted. Consequently, a compromised account could not be fully secured by changing its password alone.
The fix was introduced in Pull Request #13599 and split across two major commits to ensure correct integration without breaking compliant OAuth behavior. The primary modification implements a static revokeAllByUser helper in the OAuthToken model and integrates it within UsersService.
// packages/nocodb/src/models/OAuthToken.ts
static async revokeAllByUser(userId: string, ncMeta = Noco.ncMeta) {
const tokens = await this.listByUser(userId, ncMeta);
if (tokens?.length) {
// Concurrently revoke all retrieved tokens
await Promise.all(tokens.map((t) => this.revoke(t.id, ncMeta)));
}
}This method retrieves all active tokens and maps over them to invoke the revoke function. This model method is then integrated into the three main security-sensitive code paths in packages/nocodb/src/services/users/users.service.ts:
// In Password Change Flow
await UserRefreshToken.deleteAllUserToken(user.id);
await OAuthToken.revokeAllByUser(user.id); // Added to revoke OAuth grants
this.appHooksService.emit(AppEvents.USER_PASSWORD_CHANGE, { ... });
// In Forgot Password Flow
await OAuthToken.revokeAllByUser(user.id); // Added to clear grants immediately
this.appHooksService.emit(AppEvents.USER_PASSWORD_FORGOT, { ... });
// In Password Reset Flow
await UserRefreshToken.deleteAllUserToken(user.id);
await OAuthToken.revokeAllByUser(user.id); // Added to revoke OAuth grants
this.appHooksService.emit(AppEvents.USER_PASSWORD_RESET, { ... });Importantly, a secondary commit reverted the application of OAuthToken.revokeAllByUser(user.id) from the standard signout flow. This distinction is critical for standards compliance: a regular sign-out ends only the immediate user-agent session (such as a browser cookie session) and should not disrupt persistent third-party API or service integrations. In contrast, password changes, forgot requests, and resets assume credential compromise, necessitating full token revocation.
Exploiting this vulnerability requires that the attacker already possesses an active OAuth access or refresh token prior to the victim's password alteration event. This precursor state could occur if an attacker successfully compromises a user's password to generate an OAuth token, or exploits a brief physical/logical access vulnerability to authorize a rogue client application.
Once the OAuth token is generated, the victim may detect anomalous activity and attempt to remediate the breach by executing a password reset. While this action invalidates the session cookies, the empty stub in the original code allows the attacker's OAuth token to remain fully active. The attacker can then continue to query NocoDB endpoints without needing to re-authenticate, executing actions with the same privileges as the victim.
# Example of persistent API access using the unrevoked bearer token
curl -X GET "http://nocodb.local/api/v2/meta/bases" \
-H "Authorization: Bearer [unrevoked_oauth_token]" \
-H "Content-Type: application/json"This request will succeed and return administrative data, database metadata, or table contents, bypassing the user's explicit attempt to secure the account via credential rotation.
The security impact of this vulnerability is assessed at CVSS 6.3 (Medium). Because NocoDB handles business-critical databases, the persistence of unauthorized API access can lead to prolonged, undetected data exfiltration. Attackers can leverage active integrations or model context protocols (MCP) to read, modify, or delete sensitive records across all tables that the victim is authorized to access.
From an architectural perspective, the vulnerability facilitates a persistent foothold. Even if an enterprise deploys active monitoring for user logins, the usage of existing, valid OAuth bearer tokens bypasses standard login portals, multi-factor authentication (MFA) prompts, and single sign-on (SSO) reassessments. This directly violates the principle of least privilege and frustrates remediation efforts during incident response.
Furthermore, because the revocation relies on a concurrent Promise.all loop, security teams must evaluate the possibility of database performance degradation if a user with thousands of active OAuth tokens triggers a password reset. Although a minor concern, this concurrency design could be leveraged under specific circumstances to induce resource exhaustion on the metadata database.
The primary and recommended mitigation is upgrading the NocoDB deployment to version 2026.05.1 or later. This version incorporates the complete implementation of OAuthToken.revokeAllByUser across all password alteration events, ensuring complete session and token cleanup.
If upgrading is not immediately feasible, administrators can manually invalidate active OAuth tokens by running a targeted deletion query against the NocoDB metadata database (RootDB). The following SQL command targets the OAuth token table to remove all tokens associated with a compromised user ID:
-- Manually purge OAuth tokens for a specific compromised user
DELETE FROM nc_oauth_tokens
WHERE user_id = 'usr_xxxxxx';Additionally, security operations teams should implement logical event correlation. By auditing log events, detection systems can flag instances where an OAuth token is utilized shortly after a USER_PASSWORD_RESET or USER_PASSWORD_CHANGE hook is emitted for that specific user. Such patterns strongly suggest an active exploitation attempt or a dormant backdoor integration.
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
nocodb NocoDB | <= 2026.05.0 | 2026.05.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-613: Insufficient Session Expiration |
| Attack Vector | Network (AV:N) |
| CVSS Score | 6.3 (Medium) |
| Exploit Status | No public exploit available |
| Vulnerable Versions | <= 2026.05.0 |
| Patched Version | 2026.05.1 |
| CISA KEV Status | Not Listed |
The application does not invalidate the session or corresponding authorization tokens (OAuth access/refresh tokens) during events where the user's credentials change.
SiYuan is a privacy-first personal knowledge management system. In versions prior to v3.7.3, the application fails to apply publish-access filters to the getBacklinkDoc and getBackmentionDoc content endpoints (/api/ref/getBacklinkDoc and /api/ref/getBackmentionDoc). While the corresponding backlink list endpoints correctly filter out publish-forbidden documents, the content endpoints, which are only gated by high-level route authorization checks via CheckAuth, do not. Consequently, a user with low-privilege read access, or an anonymous reader when publish Basic Auth is disabled, can directly invoke these endpoints using a known publish-forbidden document's ID to retrieve its rendered DOM content or determine whether it references a specific target block.
A metadata disclosure vulnerability exists in SiYuan prior to version v3.7.3. The /api/block/getBlockInfo endpoint fails to validate authorization boundaries in publish mode, allowing anonymous readers to access private document metadata.
A critical authorization bypass vulnerability exists in SiYuan personal knowledge management system before v3.7.4. The /api/ref/refreshBacklink endpoint lacks administrative role verification, enabling unauthenticated users to initiate database transactions and disk operations. When combined with an unsafe SQL generation pattern in nested backlink queries, an attacker can exploit a secondary SQL injection vulnerability to compromise local databases or cause denial-of-service conditions.
A critical SQL Injection vulnerability exists in the SiYuan note-taking application (versions <= v3.7.2) due to improper neutralization of single quotes within the backlink and mention search queries. Because the application constructs SQLite Full Text Search (FTS) queries via direct string concatenation and uses a database driver that supports stacked query statements, remote unauthenticated attackers can execute arbitrary SQL commands on the master database, compromising all hosted notebooks. This issue has been fully remediated in version v3.7.4.
CVE-2026-72810 is a critical publish-boundary bypass vulnerability in the SiYuan personal knowledge management system before version 3.7.4. The flaw lies in the backend real-time WebSocket broadcast mechanism. When configured in public publish mode, the system fails to differentiate between unauthenticated public reader sessions and authorized administrative sessions within its global connection pool. This architectural oversight allows unauthenticated remote attackers connecting to the public WebSocket endpoint on port 6808 to passively receive real-time, raw workspace modification events, including keystroke logs, block updates, and content from protected or forbidden documents.
An authentication bypass vulnerability exists in the SiYuan personal knowledge management system (versions <= v3.7.2). The flaw occurs because the kernel's authorization validation handler trusts loopback connection origins blindly, allowing remote network attackers to gain administrative privileges via an exposed local reverse proxy.