Summary CVE-2020–24932 (published 27/10/2021, CVSS 9.8) is a critical SQL Injection in Complaint Management System v1.0 (Sourcecodester). The vulnerability in `complaint-details.php` via the `cid` GET parameter allowed remote attackers to enumerate and exfiltrate full database contents. This post summarizes the issue, technical root cause, responsible disclosure timeline, mitigation, and practical recommendations for developers.
Context Tutorial and sample applications are widely reused by students, hobbyists, and small projects. When those examples contain insecure code patterns, that insecurity propagates into real deployments. The Complaint Management System v1.0 is one such learning application that contained a trivially exploitable SQL injection.
Vulnerability Overview
- CVE: CVE-2020–24932 - Published: 27/10/2021 - Severity: Critical (CVSS 9.8) - Product: Complaint Management System v1.0 (Sourcecodester) - Vulnerable component: `complaint-details.php` — `cid` parameter - Type: SQL Injection (remote) - Impact: Full database disclosure (enumeration and exfiltration of data) - Discoverer: Mohamed Elobeid - Public references: CVE, NVD, Exploit-DB (ID 48758)
Technical Root Cause The `complaint-details.php` endpoint accepted a `cid` parameter and interpolated it directly into an SQL query without input validation or use of parameterized queries. Concretely, user-supplied input was embedded into the WHERE clause, allowing attackers to manipulate SQL logic (UNION, boolean, or error-based techniques) and extract arbitrary table data.
Typical insecure pattern:
```php $id = $_GET['cid']; $sql = "SELECT * FROM complaints WHERE id = $id"; ```
Why this is dangerous
- Direct interpolation of GET/POST parameters lets attackers inject SQL fragments. - Lack of input typing or whitelisting allows string or boolean payloads. - Verbose SQL errors can aid attackers in crafting payloads and mapping schema.
Proof of Concept (high level) A publicly available exploit (Exploit-DB 48758) demonstrates that supplying crafted payloads to the `cid` parameter allows enumeration of table names, column names, and row data. The exploit shows practical extraction of PII and credentials stored in the database. (Raw exploit strings are omitted here — use safe, authorized testing environments only.)
Responsible Disclosure Timeline (summary)
- Discovery and verification: vulnerability reproduced and reliable PoC created. - Vendor contact: issue reported to sourcecodester.com with PoC and remediation suggestions. - Vendor acknowledgement: vendor confirmed the issue. - CVE assignment and publication: CVE-2020–24932 published 27/10/2021. - Public exploit: Exploit-DB published a working exploit (ID 48758), emphasizing the need for patching.
Remediation — How to Fix It
1) Use parameterized queries / prepared statements - Use PDO or mysqli with bound parameters. - Example: `SELECT * FROM complaints WHERE id = ?` (bind the id as an integer).
2) Validate and sanitize input - Enforce types (cast to `int` where appropriate) and whitelist allowed values. - Reject unexpected input early.
3) Principle of least privilege - Use a database account with only the permissions necessary for the application. - Avoid using an account with `DROP`, `CREATE`, or admin privileges.
4) Reduce information leakage - Disable verbose SQL error messages in production. - Log errors server-side without returning stack traces to users.
5) Testing and CI - Add static analysis and automated dynamic scanning to CI. - Include unit tests and integration tests that cover input handling. - Consider automated SQLi checks or fuzzing for input endpoints.
Suggested secure code diffs
A. Using mysqli with prepared statements (procedural)
Secure replacement:
```php $id = isset($_GET['cid']) ? (int) $_GET['cid'] : 0; $stmt = mysqli_prepare($conn, "SELECT * FROM complaints WHERE id = ?"); mysqli_stmt_bind_param($stmt, "i", $id); mysqli_stmt_execute($stmt); $res = mysqli_stmt_get_result($stmt); ```
B. Using PDO (recommended)
Secure replacement:
```php $id = isset($_GET['cid']) ? (int) $_GET['cid'] : 0; $stmt = $pdo->prepare("SELECT * FROM complaints WHERE id = :id"); $stmt->bindValue(':id', $id, PDO::PARAM_INT); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); ```
Notes on the diffs
- Casting to `int` enforces numeric type and prevents many injection vectors when IDs are numeric. - Prepared statements protect when inputs are strings or more complex. - For non-numeric parameters, validate and whitelist allowed values or use strict regex checks.
Hardening checklist for tutorial/sample apps
- Always show secure examples in tutorials (prepared statements + input validation). - Include comments explaining why prepared statements are used. - Ship a minimal CI pipeline that runs SAST checks and common SQLi tests. - Add an automated test that sends invalid inputs and asserts no DB leakage or stack traces are returned.
Impact Any deployment that reused this tutorial code without fixing the SQL injection risked full database compromise and exposure of PII and credentials. The public CVE and exploit highlight how learning code can become an attack vector if copied into production. Fixing the root cause and improving sample code reduces risk for many developers who depend on tutorial repositories.
References
- CVE record: https://www.cve.org/CVERecord?id=CVE-2020-24932 - NVD: https://nvd.nist.gov/vuln/detail/CVE-2020-24932 - Exploit-DB: https://www.exploit-db.com/exploits/48758 - Affected code: https://www.sourcecodester.com/download-code?nid=14206&title=Complaint+Management+System