Impact
A SQL injection vulnerability exists in the conversation and contact filter APIs. When filtering by a custom attribute of type date or number using the is_greater_than or is_less_than operators, user-supplied values in the values field of the filter payload are interpolated directly into the SQL query without parameterization.
Any authenticated user with access to an account can exploit this to execute arbitrary SQL via time-based blind injection. Because the global users and account-scoped tables are reachable from subqueries, an attacker can:
- Read data across tenant boundaries (cross-account data breach)
- Exfiltrate user emails, bcrypt password hashes, and API access tokens
- Read conversation contents, contact PII, and integration credentials stored in the database
If the account has no date/number custom attribute, the attacker can create one via the public custom attribute definitions endpoint, so the precondition is trivially satisfied.
A second, related sink existed in the same code path: the attribute_key of a custom attribute was interpolated unparameterized into the JSON path expression in build_custom_attr_query (and not_in_custom_attr_query). An attacker could create a custom attribute with a crafted attribute_key and then trigger the injection on any filter call that referenced it, regardless of the attribute's data type. The same patch closes this vector by enforcing a strict format on attribute_key (/\A[\p{L}\p{N}_.\-]+\z/) and switching to bind parameters via sanitize_sql_array. Operators auditing for prior exploitation should inspect custom_attribute_definitions.attribute_key for values containing quotes, parentheses, whitespace, or other SQL metacharacters in addition to reviewing filter request payloads.
Affected endpoints:
POST /api/v1/accounts/{account_id}/conversations/filter
POST /api/v1/accounts/{account_id}/contacts/filter
POST /api/v1/accounts/{account_id}/custom_attribute_definitions (stores the malicious attribute_key for the second vector)
All Chatwoot installations on affected versions are impacted. Stacked queries are not possible via ActiveRecord/PostgreSQL, so direct UPDATE/DELETE injection is not feasible, but full read access via blind SQLi is.
Patches
The issue has been patched. Users should upgrade to 4.11.2
Workarounds
There is no reliable workaround short of upgrading. Operators who cannot upgrade immediately can mitigate exposure by:
- Restricting access to the
/conversations/filter and /contacts/filter endpoints at the reverse-proxy / WAF layer
- Removing all
date and number custom attribute definitions and blocking creation of new ones
- Auditing and rotating credentials (API access tokens, user passwords) if exploitation is suspected
Impact
A SQL injection vulnerability exists in the conversation and contact filter APIs. When filtering by a custom attribute of type
dateornumberusing theis_greater_thanoris_less_thanoperators, user-supplied values in thevaluesfield of the filter payload are interpolated directly into the SQL query without parameterization.Any authenticated user with access to an account can exploit this to execute arbitrary SQL via time-based blind injection. Because the global
usersand account-scoped tables are reachable from subqueries, an attacker can:If the account has no
date/numbercustom attribute, the attacker can create one via the public custom attribute definitions endpoint, so the precondition is trivially satisfied.A second, related sink existed in the same code path: the
attribute_keyof a custom attribute was interpolated unparameterized into the JSON path expression inbuild_custom_attr_query(andnot_in_custom_attr_query). An attacker could create a custom attribute with a craftedattribute_keyand then trigger the injection on any filter call that referenced it, regardless of the attribute's data type. The same patch closes this vector by enforcing a strict format onattribute_key(/\A[\p{L}\p{N}_.\-]+\z/) and switching to bind parameters viasanitize_sql_array. Operators auditing for prior exploitation should inspectcustom_attribute_definitions.attribute_keyfor values containing quotes, parentheses, whitespace, or other SQL metacharacters in addition to reviewing filter request payloads.Affected endpoints:
POST /api/v1/accounts/{account_id}/conversations/filterPOST /api/v1/accounts/{account_id}/contacts/filterPOST /api/v1/accounts/{account_id}/custom_attribute_definitions(stores the maliciousattribute_keyfor the second vector)All Chatwoot installations on affected versions are impacted. Stacked queries are not possible via ActiveRecord/PostgreSQL, so direct
UPDATE/DELETEinjection is not feasible, but full read access via blind SQLi is.Patches
The issue has been patched. Users should upgrade to 4.11.2
Workarounds
There is no reliable workaround short of upgrading. Operators who cannot upgrade immediately can mitigate exposure by:
/conversations/filterand/contacts/filterendpoints at the reverse-proxy / WAF layerdateandnumbercustom attribute definitions and blocking creation of new ones