CVE-2026-33318 Overview
CVE-2026-33318 is a privilege escalation vulnerability in Actual, a local-first personal finance tool developed by ActualBudget. This vulnerability affects servers that have migrated from password authentication to OpenID Connect, allowing any authenticated user—including those with only BASIC role permissions—to escalate their privileges to ADMIN level.
The vulnerability results from a chain of three distinct weaknesses that, when combined, enable complete privilege escalation. While no single weakness provides escalation independently, their sequential exploitation allows attackers to gain administrative control over affected Actual installations.
Critical Impact
Any authenticated user can escalate to ADMIN privileges on migrated servers, potentially gaining complete control over financial data and server configuration.
Affected Products
- ActualBudget Actual versions prior to 26.4.0
- Actual installations migrated from password authentication to OpenID Connect
- Node.js deployments of ActualBudget Actual
Discovery Timeline
- 2026-04-24 - CVE-2026-33318 published to NVD
- 2026-04-27 - Last updated in NVD database
Technical Details for CVE-2026-33318
Vulnerability Analysis
This vulnerability is classified under CWE-284 (Improper Access Control) and represents a complex authorization bypass through a chained exploit. The attack requires network access and low-privilege authentication, but requires no user interaction to execute successfully.
The vulnerability enables attackers to compromise the confidentiality, integrity, and availability of the affected system by gaining unauthorized administrative access. In the context of a personal finance application, this could result in exposure or manipulation of sensitive financial data.
Root Cause
The single root cause is a missing authorization check on the POST /account/change-password endpoint. This endpoint lacks proper access control verification, allowing any authenticated session to overwrite the password hash for any account. Two preconditions make this weakness exploitable:
Orphaned Password Row: When servers migrate from password authentication to OpenID Connect, the inactive password authentication row is never removed from the database, leaving a target for attackers.
Client-Controlled Login Method: The login endpoint accepts a client-supplied loginMethod parameter that can bypass the server's active authentication configuration, allowing forced password-based authentication.
Attack Vector
The attack is executed over the network and follows a specific sequential chain:
Step 1 - Password Hash Overwrite: An attacker with basic authentication sends a request to POST /change-password to overwrite the password hash of the orphaned admin account. Due to the missing authorization check, this request succeeds regardless of the attacker's privilege level.
Step 2 - Target the Orphaned Row: The orphaned password authentication row, persisting from the pre-migration period, becomes the target. This row is associated with the anonymous admin account created during the multiuser migration process.
Step 3 - Force Password Authentication: The attacker authenticates using the login endpoint with a client-supplied loginMethod: "password" parameter, bypassing the server's OpenID Connect configuration and using the newly set password to gain admin access.
Each step depends on the previous, and all three must be executed in sequence. The missing authorization on /change-password provides the entry point, the orphaned row provides the target, and the client-controlled login method enables exploitation of the compromised credentials.
Detection Methods for CVE-2026-33318
Indicators of Compromise
- Unexpected password change requests to POST /account/change-password from low-privilege users
- Authentication attempts using loginMethod: "password" on servers configured for OpenID Connect
- Sudden privilege changes from BASIC to ADMIN role without authorized administrative action
- Suspicious API calls targeting authentication endpoints from authenticated sessions
Detection Strategies
- Monitor authentication logs for login attempts using password method on OIDC-configured servers
- Implement alerting for any calls to /account/change-password endpoint by non-admin users
- Track privilege escalation events and correlate with recent authentication endpoint activity
- Review access logs for sequential patterns matching the exploit chain (change-password followed by password-based login)
Monitoring Recommendations
- Enable detailed logging on all authentication-related endpoints
- Implement real-time alerting for authentication method mismatches
- Monitor for privilege elevation events in the application user database
- Establish baseline authentication patterns to detect anomalous login method usage
How to Mitigate CVE-2026-33318
Immediate Actions Required
- Upgrade to Actual version 26.4.0 or later immediately
- Audit authentication logs for signs of exploitation prior to patching
- Review all user accounts for unauthorized privilege escalations
- Verify that orphaned password authentication rows have been properly cleaned up after migration
Patch Information
ActualBudget has released version 26.4.0 which contains a fix for this vulnerability. The patch addresses the missing authorization check on the /change-password endpoint. Organizations should upgrade to this version immediately.
For detailed patch information, see the ActualBudget Release Blog Post and the GitHub Security Advisory.
Workarounds
- Restrict network access to the Actual server to trusted users only until patching is complete
- Monitor and block suspicious requests to the /account/change-password endpoint at the network level
- Manually remove orphaned password authentication rows from the database if OpenID Connect migration was performed
- Implement additional authorization controls at the reverse proxy or API gateway level to validate change-password requests
# Verify current Actual version and upgrade if needed
npm show actualbudget/actual version
npm update @actual-app/api
# After upgrading, verify the new version is installed
npm list | grep actual
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

