Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-49229

CVE-2026-49229: Actual Finance App Auth Bypass Vulnerability

CVE-2026-49229 is an authentication bypass flaw in Actual personal finance app that allows disabled users to maintain active sessions. This post covers the technical details, affected versions, impact, and mitigation.

Published:

CVE-2026-49229 Overview

Actual Budget is a local-first personal finance application with an optional sync server supporting OpenID multi-user mode. CVE-2026-49229 is a session management flaw [CWE-613] in versions prior to 26.6.0. When an administrator disables a user account, only future OpenID logins are blocked. Existing session tokens tied to that disabled user remain valid and continue to authorize server API calls. A disabled user can invoke authenticated sync-server endpoints until their token naturally expires. The issue is patched in Actual 26.6.0.

Critical Impact

A disabled user retains authenticated access to the Actual sync server through their existing session token, undermining administrative account revocation in OpenID multi-user deployments.

Affected Products

  • Actual Budget sync server versions prior to 26.6.0
  • Deployments configured with OpenID multi-user mode
  • Self-hosted Actual instances relying on administrative user disable actions for access revocation

Discovery Timeline

  • 2026-07-07 - CVE-2026-49229 published to NVD
  • 2026-07-09 - Last updated in NVD database

Technical Details for CVE-2026-49229

Vulnerability Analysis

The flaw lives in the sync-server session validation path. The getSession(token) function in packages/sync-server/src/account-db.js queries the sessions table for a matching, unexpired token and returns the row. It never joins against the users table to confirm the associated account is still enabled. Any endpoint depending on this shared validation therefore trusts the token as long as it exists.

Administrative disable actions in user-service.ts updated the users.enabled column but did not invalidate outstanding sessions. Account deletion behaved the same way, orphaning session rows that continued to authenticate requests. This is a classic insufficient session expiration issue mapped to [CWE-613].

Root Cause

Session lifecycle state was decoupled from user account state. Enabling, disabling, and deleting users mutated user records without touching the sessions table. The token lookup treated presence and non-expiration as sufficient proof of authorization, so revocation semantics never propagated to active clients.

Attack Vector

An attacker must first hold a valid session token issued while their account was enabled. After an administrator disables or deletes that account, the attacker replays the token against authenticated sync-server endpoints. Because the network-reachable API accepts the token, the attacker continues to read or modify budget data until the token expires.

javascript
// Patch: packages/sync-server/src/account-db.js
export function getSession(token) {
  const accountDb = getAccountDb();
- return accountDb.first('SELECT * FROM sessions WHERE token = ?', [token]);
+ return accountDb.first(
+   `SELECT sessions.*
+    FROM sessions
+    JOIN users ON users.id = sessions.user_id
+    WHERE sessions.token = ? AND users.enabled = 1`,
+   [token],
+ );
}
// Source: https://github.com/actualbudget/actual/commit/c8cb8a223a4faf1c2e1dcb0795a79a93f7b19e80

Detection Methods for CVE-2026-49229

Indicators of Compromise

  • Authenticated sync-server requests originating from a user ID whose users.enabled column is 0.
  • Session rows in the sessions table whose user_id references a disabled or deleted user.
  • API activity from an account after an administrator recorded a disable or delete action in audit logs.

Detection Strategies

  • Query the sync-server database periodically for sessions joined to users WHERE enabled = 0 and alert on any matches.
  • Correlate application access logs against the administrative user-management audit trail to surface requests made after account disable events.
  • Baseline expected API callers per user and flag continued activity from identities marked inactive in the OpenID provider.

Monitoring Recommendations

  • Enable verbose request logging on the Actual sync server and forward logs to a central analytics platform.
  • Track HTTP request volume per user_id and alert on non-zero traffic from disabled accounts.
  • Monitor for unexpected budget mutations, especially write endpoints, following any account revocation event.

How to Mitigate CVE-2026-49229

Immediate Actions Required

  • Upgrade the Actual sync server to version 26.6.0 or later, which enforces the enabled-user check inside getSession.
  • Manually purge stale session rows for any user previously disabled or deleted while running an earlier version: DELETE FROM sessions WHERE user_id IN (SELECT id FROM users WHERE enabled = 0);
  • Rotate or invalidate all outstanding sessions after upgrading to guarantee that revocation actions taken during the vulnerable window take effect.

Patch Information

The fix is delivered in Actual Budget release v26.6.0. See the GitHub Security Advisory GHSA-cq9c-6w48-qmfg and the remediation commit for full technical details. The patch joins sessions to users during token lookup and deletes sessions when a user is disabled or removed.

Workarounds

  • If immediate patching is not possible, delete rows from the sessions table for any user administrators intend to revoke.
  • Restrict network exposure of the sync server to trusted networks or VPN clients until the upgrade is applied.
  • Shorten session token lifetimes in the sync-server configuration to reduce the replay window for tokens issued before disable actions.
bash
# Post-upgrade cleanup: invalidate sessions for disabled or removed users
sqlite3 /path/to/account.sqlite \
  "DELETE FROM sessions WHERE user_id NOT IN (SELECT id FROM users WHERE enabled = 1);"

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.