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

CVE-2026-77240: WACRM Privilege Escalation Vulnerability

CVE-2026-77240 is a privilege escalation vulnerability in WACRM that allows authenticated users to modify their account roles and access other tenant resources. This article covers technical details, affected versions, and mitigation steps.

Published:

CVE-2026-77240 Overview

WACRM, a self-hostable Customer Relationship Management (CRM) template for WhatsApp, contains two database authorization flaws in versions 0.7.0 and earlier. The profiles_update row-level security (RLS) policy allows authenticated users to modify their own account_role and account_id columns, enabling privilege escalation and tenant relocation. Additionally, the match_ai_knowledge_fts and match_ai_knowledge_semantic functions run as SECURITY DEFINER without membership validation, exposing knowledge-base data across tenants. Both weaknesses map to [CWE-639] Authorization Bypass Through User-Controlled Key. The vendor patched the issues in commit e01f7ed37184f972ace8fb2da5c3e37e56a6050f.

Critical Impact

An authenticated viewer can self-promote to owner, move into a victim tenant, and read or modify arbitrary tenant resources including AI knowledge-base chunks.

Affected Products

  • WACRM version 0.7.0
  • WACRM versions prior to 0.7.0
  • Supabase migrations 017_account_sharing.sql and 030_ai_knowledge.sql

Discovery Timeline

  • 2026-09-18 - CVE-2026-77240 published to the National Vulnerability Database (NVD)
  • 2026-09-23 - CVE-2026-77240 last updated in NVD database

Technical Details for CVE-2026-77240

Vulnerability Analysis

WACRM relies on Supabase Row-Level Security (RLS) to isolate tenant data. Two distinct authorization defects break that isolation.

The first defect lives in the profiles_update RLS policy defined in supabase/migrations/017_account_sharing.sql. The policy gates updates on auth.uid() = user_id, which correctly restricts users to their own row but does not restrict which columns they may modify. Because account_role and account_id reside on the same profiles table and back the is_account_member() check, an authenticated browser client can update those columns directly through PostgREST.

The second defect lives in the AI knowledge-base functions match_ai_knowledge_fts and match_ai_knowledge_semantic in supabase/migrations/030_ai_knowledge.sql. Both are declared SECURITY DEFINER and granted to the authenticated role. They filter on a caller-supplied p_account_id parameter and never invoke is_account_member(), so any logged-in user can request another tenant's chunks.

Root Cause

The policy authors conflated row-scope authorization with column-scope authorization. RLS in PostgreSQL controls which rows a role can read or write, not which columns may change. Sensitive privilege columns were left on the same row as self-service fields without a column-level GRANT or trigger guard. The knowledge-base functions compounded the issue by bypassing RLS entirely under SECURITY DEFINER while trusting a client-controlled tenant identifier.

Attack Vector

An attacker only needs valid credentials for any tenant. From the browser client, the attacker issues an UPDATE against profiles to change account_role to owner or to swap account_id to a victim tenant. Alternatively, the attacker calls /rest/v1/rpc/match_ai_knowledge_fts with a foreign p_account_id to exfiltrate knowledge-base content without altering any state.

sql
-- Vulnerable behavior in profiles_update (migration 017)
-- Viewer self-promotes to owner of the shared account
UPDATE profiles SET account_role = 'owner' WHERE user_id = auth.uid();

-- Attacker relocates their profile into a victim tenant
UPDATE profiles SET account_id = '<victim>' WHERE user_id = auth.uid();

-- Cross-tenant knowledge-base read via PostgREST RPC (migration 030)
-- POST /rest/v1/rpc/match_ai_knowledge_fts
-- { "p_account_id": "<victim>", "p_query": "price", "p_match_count": 1000 }

Source: GitHub Commit e01f7ed

Detection Methods for CVE-2026-77240

Indicators of Compromise

  • UPDATE statements against the profiles table that modify account_role or account_id and originate from the authenticated role.
  • PostgREST RPC calls to match_ai_knowledge_fts or match_ai_knowledge_semantic where p_account_id differs from the caller's tenant.
  • Sudden appearance of a user in a tenant they were never invited to, visible in profiles audit history.

Detection Strategies

  • Enable PostgreSQL audit logging (pgaudit) on the profiles table to capture every column-level change to account_role and account_id.
  • Add a database-side trigger that logs any RPC invocation of the knowledge-base functions with the caller sub, p_account_id, and result row count.
  • Correlate authentication logs from Supabase Auth with unexpected tenant switches recorded in application telemetry.

Monitoring Recommendations

  • Alert when the same user identifier appears bound to multiple account_id values across a short time window.
  • Baseline the volume and diversity of p_account_id values requested per user against the knowledge-base RPC endpoints.
  • Forward Supabase and PostgREST logs to a centralized analytics pipeline for cross-tenant anomaly analysis.

How to Mitigate CVE-2026-77240

Immediate Actions Required

  • Upgrade WACRM to a version that includes commit e01f7ed37184f972ace8fb2da5c3e37e56a6050f or apply migrations 031_fix_profiles_update_rls.sql and 032_fix_ai_knowledge_membership.sql.
  • Audit the profiles table for unexpected account_role = 'owner' assignments or account_id reassignments performed by non-administrative users.
  • Rotate credentials and invalidate active sessions for any user identified as having pivoted between tenants.

Patch Information

The fix is delivered in two migrations. Migration 031_fix_profiles_update_rls.sql installs a BEFORE UPDATE trigger that rejects changes to account_role and account_id when the caller is the authenticated role, while allowing the legitimate handle_new_user flow and the member and invitation Remote Procedure Calls (RPCs) to continue. Migration 032_fix_ai_knowledge_membership.sql recreates match_ai_knowledge_fts and match_ai_knowledge_semantic as SECURITY INVOKER so the existing ai_knowledge_chunks_select policy governs authenticated callers and returns zero rows for foreign p_account_id values. Full details are in GitHub Security Advisory GHSA-fg5p-2qc3-jmxr and Pull Request #350.

Workarounds

  • Revoke UPDATE on profiles.account_role and profiles.account_id from the authenticated role using column-level REVOKE statements until the patch is applied.
  • Revoke EXECUTE on match_ai_knowledge_fts and match_ai_knowledge_semantic from the authenticated role and restrict invocation to the service_role.
  • Disable public exposure of the affected PostgREST RPC endpoints via API gateway or reverse-proxy rules.
bash
# Emergency mitigations before applying the official patch
psql "$DATABASE_URL" <<'SQL'
REVOKE UPDATE (account_role, account_id) ON public.profiles FROM authenticated;
REVOKE EXECUTE ON FUNCTION public.match_ai_knowledge_fts FROM authenticated;
REVOKE EXECUTE ON FUNCTION public.match_ai_knowledge_semantic FROM authenticated;
SQL

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.