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

CVE-2026-88003: InvoicePlane Privilege Escalation Vulnerability

CVE-2026-88003 is a privilege escalation flaw in InvoicePlane that lets downgraded admin accounts retain elevated access through session reuse. This post covers technical details, affected versions, and mitigation.

Published:

CVE-2026-88003 Overview

CVE-2026-88003 is an authorization vulnerability in InvoicePlane, a self-hosted open source application for managing invoices, clients, and payments. Versions prior to 1.7.2 fail to revoke administrative privileges after a role downgrade. The Admin_Controller trusts the user_type snapshot stored in an existing session instead of revalidating ip_users.user_type on each request. A downgraded administrator retains an active session that continues to authorize administrative actions. The attacker can then invoke Users::form() to reset their own user_type back to 1, restoring the admin role and making the escalation persistent. This weakness maps to CWE-863: Incorrect Authorization.

Critical Impact

An authenticated user whose administrative role was revoked can continue issuing privileged requests and permanently restore their own admin privileges in the database.

Affected Products

  • InvoicePlane versions prior to 1.7.2
  • InvoicePlane Admin_Controller authorization layer
  • InvoicePlane Users module privilege handling

Discovery Timeline

Technical Details for CVE-2026-88003

Vulnerability Analysis

InvoicePlane stores the authenticated user's user_type in the PHP session at login. The Admin_Controller consults this cached value to decide whether a request is authorized. The controller never cross-checks the live ip_users.user_type column during subsequent requests. When an administrator downgrades another account, the target's active session still carries the original admin snapshot. The downgraded user can therefore keep calling administrative endpoints until the session expires.

The second half of the flaw lives in Users::form(). The handler accepts a user_type POST field and writes it back to the database for the user being edited. Because the stale session still passes the admin check, the downgraded user can submit a form targeting their own account and set user_type back to 1. The role change persists in the database, producing durable privilege escalation that survives logout.

Root Cause

The root cause is session-based authorization that trusts a login-time snapshot instead of revalidating the authoritative role on each request. Combined with mass-assignable user_type in Users::form(), this allows an attacker holding a stale session to re-promote their own account.

Attack Vector

Exploitation requires an authenticated session that previously held administrative rights. No user interaction is needed from the current administrator. The attacker submits a crafted POST to the users form endpoint with user_type=1, writing the elevated role directly to ip_users.

php
            session_destroy();
            redirect('sessions/login');
        }
+
+        // The session-based check above trusts the snapshot taken at login and
+        // does not notice a role change (e.g. an administrator downgraded to a
+        // guest) or a deactivated account applied by another administrator. To
+        // enforce privilege revocation at the point it is expected to take
+        // effect, re-validate the required role against the authoritative
+        // ip_users record on every request.
+        if ($required_key === 'user_type') {
+            $this->revalidate_user_type((string) $required_val);
+        }
+    }
+
+    private function revalidate_user_type(string $required_val): void
+    {
+        $user_id = $this->session->userdata('user_id');
+
+        $current = null;
+        if ($user_id) {
+            $current = $this->db
+                ->select('user_type, user_active')
+                ->where('user_id', $user_id)
+                ->get('ip_users')
+                ->row();

Source: InvoicePlane commit 904847f. The patch forces Admin_Controller to re-read the role from ip_users on every request and destroy the session when the live record no longer satisfies the required role.

Detection Methods for CVE-2026-88003

Indicators of Compromise

  • POST requests to /users/form/<user_id> where user_id matches the submitting session's own user and user_type=1 is set.
  • Rows in ip_users where user_type was downgraded and later restored to 1 without a corresponding administrator action in audit logs.
  • Administrative endpoints accessed by a user whose current ip_users.user_type is not 1.

Detection Strategies

  • Compare the user_type embedded in active PHP session files against the live ip_users.user_type for the same user_id and alert on mismatches.
  • Review web server access logs for Users::form submissions where the acting account edits itself and submits a user_type field.
  • Audit the InvoicePlane database for recent role transitions from non-admin to admin that lack a matching administrative actor in application logs.

Monitoring Recommendations

  • Enable verbose logging on application/modules/users/controllers/Users.php for all form() invocations, including POST body and acting user ID.
  • Monitor session storage directory activity so that stale session files for downgraded users can be identified and purged.
  • Alert on any write to ip_users.user_type that does not originate from an authenticated administrator session.

How to Mitigate CVE-2026-88003

Immediate Actions Required

  • Upgrade InvoicePlane to version 1.7.2 or later as published in the InvoicePlane 1.7.2 release.
  • Invalidate all active InvoicePlane sessions after upgrade by clearing the session save path on the server.
  • Audit the ip_users table and revert any unauthorized user_type promotions to admin.

Patch Information

The fix ships in InvoicePlane 1.7.2. Two commits implement the remediation: commit 904847f adds per-request role revalidation in User_Controller, and commit daa49ce adds defense-in-depth by invalidating sessions on role or active-status change and by blocking self-escalation in Users::form().

php
        if ($this->mdl_users->run_validation(($id) ? 'validation_rules_existing' : 'validation_rules')) {
-            $db_array              = $this->mdl_users->db_array();
-            $db_array['user_type'] = (int) $this->input->post('user_type');
-            $id                    = $this->mdl_users->save($id, $db_array);
+            $db_array      = $this->mdl_users->db_array();
+            $requested_type = (int) $this->input->post('user_type');
+            $current_user_id = (string) $this->session->userdata('user_id');
+            $is_self_edit = $id && (string) $id === $current_user_id;
+
+            // User editing themselves: do not allow type changes (prevents self-escalation)
+            $old_user = $id ? $this->mdl_users->get_by_id($id) : null;
+            $role_changed = false;
+
+            if ( ! $is_self_edit) {
+                if ( ! $old_user || (int) $old_user->user_type !== $requested_type) {
+                    $db_array['user_type'] = $requested_type;
+                    $role_changed = true;
+                }
+            }

Source: InvoicePlane commit daa49ce. The patch blocks any user_type change when a user edits their own record and invalidates sessions when another administrator changes a user's role or active status.

Workarounds

  • If upgrading immediately is not possible, force all users to re-authenticate after any role change by deleting PHP session files from the configured sess_save_path.
  • Restrict network access to the InvoicePlane /users/ routes so that only trusted administrator workstations can submit updates.
  • Remove any accounts that previously held admin privileges and have since been downgraded, then recreate them with the intended role.
bash
# Force session invalidation on the InvoicePlane host after a role downgrade
rm -f /var/lib/php/sessions/sess_*
systemctl reload php-fpm

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

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.