CVE-2024-36039
Medium · 6.3CVSS
6.3
EPSS
0.7%
Published
May 21, 2024
CISA due date
—
Cloudanix analysis
A flaw in a database library can let a malicious user manipulate database queries if an application accepts specially crafted JSON input.
- Exploitation
- Remote Authenticated
- Attacker needs
- Low Privilege
- Complexity
- Moderate
- Impact
- Data Tampering
- Component
- Library
- Class
- SQL Injection
- Remediation
- Upgrade
- Effort
- Medium
- Patch risk
- Low
What it actually does
PyMySQL through 1.1.0 can generate unsafe SQL when an application passes attacker-controlled JSON/dictionary data into PyMySQL escaping routines that rely on escape_dict. The flaw is that dictionary keys are not escaped correctly, so a crafted key can break out of the intended SQL literal or JSON structure and alter the resulting SQL statement. Depending on how the application builds queries and what database privileges are available, this can allow unauthorized reads, writes, or destructive SQL operations against a MySQL-compatible database.
Why it matters to the business
Applications that accept user-supplied JSON and use vulnerable PyMySQL versions may be exposed to data theft, unauthorized data modification, account or transaction manipulation, and database disruption. The CVSS score is moderate and public exploitation maturity is currently listed as none, EPSS is low at 0.00691, and it is not in CISA KEV; however, because SQL injection can directly affect sensitive business data, vulnerable code paths should still be prioritized for remediation, especially in externally reachable services or administrative APIs.
How an attack unfolds
An attacker first identifies an application endpoint that accepts JSON or dictionary-like input and causes that input to be passed to PyMySQL query construction or escaping. The attacker then supplies a malicious JSON key designed to terminate or alter the SQL fragment produced by escape_dict. If the application uses the escaped dictionary output in a SQL statement, the malformed key can inject attacker-controlled SQL. The attacker may start with harmless probes that cause SQL syntax errors or timing differences, then progress to extracting data, modifying records, bypassing application logic, or attempting destructive statements, limited by the database account permissions and whether stacked queries or relevant SQL functions are allowed.
How to fix it
Upgrade PyMySQL to a version that includes the upstream fix for commit 2cab9ecc641e962565c6254a5091f90c47f59b35 or a later release containing that change. Treat PyMySQL through 1.1.0 as vulnerable where untrusted JSON or dictionary keys can reach SQL escaping or query construction. In addition to upgrading, avoid building SQL from serialized JSON/dictionary structures; use parameterized queries, validate allowed JSON keys with an allowlist, reject keys containing SQL metacharacters where keys are expected to be identifiers, and ensure database accounts have least-privilege permissions. If immediate upgrade is not possible, block untrusted dictionary keys from reaching escape_dict-dependent code paths and add strict schema validation at API boundaries.
How to confirm the fix worked
Confirm dependency inventories, lockfiles, container images, and deployed runtime environments no longer use PyMySQL through 1.1.0 unless patched with commit 2cab9ecc641e962565c6254a5091f90c47f59b35. Review code for calls that pass untrusted dict or JSON objects into PyMySQL escaping, formatting, or dynamically constructed SQL. Add a regression test that submits JSON with keys containing quotes, comments, parentheses, semicolons, and SQL keywords and verify the resulting database operation is rejected or safely parameterized. Run software composition analysis and runtime package checks, such as `pip show PyMySQL`, `pip freeze`, or lockfile inspection, to confirm the remediated version is deployed in all build and execution paths.
Typical attack path
- Find an application endpoint, API, form, or backend workflow that accepts JSON input.
- Determine whether the input is stored or queried through a Python application using PyMySQL through 1.1.0.
- Send JSON objects with unusual or SQL-like keys to test whether dictionary keys influence generated SQL.
- Observe application errors, response differences, database error messages, or timing behavior that indicate SQL injection.
- Refine the malicious JSON key to alter the SQL query while preserving valid request structure.
- Use the injection to read sensitive rows, modify records, bypass authorization checks, or disrupt database operations, depending on database privileges.
How to detect it
Investigate exposure by correlating application access logs, API gateway logs, web server logs, WAF events, application exception traces, and MySQL general, slow query, and error logs. Look for requests containing JSON object keys with SQL metacharacters, comments, quote characters, semicolons, or SQL keywords, especially followed by database syntax errors or unusual response codes. Review application logs for PyMySQL, MySQLdb, or SQL syntax exceptions after JSON-heavy requests. In database telemetry, look for unexpected UNION clauses, tautologies, stacked statements, sleep/time-delay functions, metadata table access, or DDL/DML operations from application accounts that normally only perform limited queries. If exploitation is suspected, compare affected database records against audit logs, inspect recently changed privileged users and application data, and preserve request bodies and database logs for forensic review.
- pymysql.err.ProgrammingError
- pymysql.err.OperationalError
- You have an error in your SQL syntax
- check the manual that corresponds to your MySQL server version
- ER_PARSE_ERROR
- SQL syntax; check the manual
- information_schema.tables
- information_schema.columns
- UNION SELECT
- UNION ALL SELECT
- SLEEP(
- BENCHMARK(
- ' OR '1'='1
- " OR "1"="1
- --
- #
- /*
- */
- ; DROP TABLE
- ; INSERT INTO
- ; UPDATE
- ; DELETE FROM
What your security team should do
- Inventory all Python applications, containers, serverless functions, and build artifacts that include PyMySQL, prioritizing internet-facing services and APIs that accept JSON input.
- Upgrade PyMySQL to a fixed release or a build containing commit 2cab9ecc641e962565c6254a5091f90c47f59b35; ensure lockfiles and base images are rebuilt, not only source manifests changed.
- Search application code for dynamic SQL construction involving JSON, dictionaries, `escape_dict`, `escape_string`, `literal`, `%` formatting, `.format()`, or f-strings near PyMySQL database calls.
- Add strict JSON schema validation with allowlisted keys before database interaction, especially for filters, metadata, search parameters, and admin workflows.
- Review database user privileges used by affected applications and remove unnecessary write, DDL, FILE, SUPER, or administrative permissions.
- Enable or review application, database, and web access logs for SQL error spikes, suspicious JSON keys, and anomalous queries during the exposure window.
- Add regression tests and SAST rules to prevent untrusted dictionary keys from being used in SQL construction.
The record
PyMySQL through 1.1.0 allows SQL injection if used with untrusted JSON input because keys are not escaped by escape_dict.
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|---|---|---|
| PyPI | pymysql | 0 | 1.1.1 |
| AlmaLinux:8 | python3.11-PyMySQL | 0 | 1.0.2-2.el8_10 |
| AlmaLinux:8 | python3.12-PyMySQL | 0 | 1.1.0-3.el8_10 |
| AlmaLinux:9 | python3.11-PyMySQL | 0 | 1.0.2-2.el9 |
| AlmaLinux:9 | python3.11-PyMySQL+rsa | 0 | 1.0.2-2.el9 |
| AlmaLinux:9 | python3.12-PyMySQL | 0 | 1.1.0-3.el9 |
| AlmaLinux:9 | python3.12-PyMySQL+rsa | 0 | 1.1.0-3.el9 |
| Chainguard | datadog-agent | 0 | 7.54.0-r1 |
| Chainguard | datadog-agent-core-integrations | 0 | 7.54.0-r1 |
| Chainguard | datadog-agent-fakeintake | 0 | 7.54.0-r1 |
| Chainguard | datadog-agent-jmx | 0 | 7.54.0-r1 |
| Chainguard | datadog-agent-oci-compat | 0 | 7.54.0-r1 |
| Chainguard | datadog-agent-s6-overlay | 0 | 7.54.0-r1 |
| Chainguard | datadog-cluster-agent | 0 | 7.54.0-r1 |
| Chainguard | datadog-cluster-agent-oci-compat | 0 | 7.54.0-r1 |
| Chainguard | dogstatsd | 0 | 7.54.0-r1 |
| Chainguard | py3-pymysql | 0 | 1.1.1-r0 |
| Chainguard | py3-supported-pymysql | 0 | 1.1.1-r0 |
| Chainguard | py3.10-pymysql | 0 | 1.1.1-r0 |
| Chainguard | py3.11-pymysql | 0 | 1.1.1-r0 |
| Chainguard | py3.12-pymysql | 0 | 1.1.1-r0 |
| Chainguard | py3.13-pymysql | 0 | 1.1.1-r0 |
| Debian:10 | python-pymysql | 0 | 0.9.3-1+deb10u1 |
| Debian:11 | python-pymysql | 0 | 0.9.3-2+deb11u1 |
| Debian:12 | python-pymysql | 0 | 1.0.2-2+deb12u1 |
| Debian:13 | python-pymysql | 0 | 1.1.1-1 |
| Red Hat:enterprise_linux:8::appstream | python3.11-PyMySQL | 0 | 0:1.0.2-2.el8_10 |
| Red Hat:enterprise_linux:8::appstream | python3.12-PyMySQL | 0 | 0:1.1.0-3.el8_10 |
| Red Hat:enterprise_linux:9::appstream | python3.11-PyMySQL | 0 | 0:1.0.2-2.el9 |
| Red Hat:enterprise_linux:9::appstream | python3.11-PyMySQL+rsa | 0 | 0:1.0.2-2.el9 |
| Red Hat:enterprise_linux:9::appstream | python3.12-PyMySQL | 0 | 0:1.1.0-3.el9 |
| Red Hat:enterprise_linux:9::appstream | python3.12-PyMySQL+rsa | 0 | 0:1.1.0-3.el9 |
| Rocky Linux:9 | python3.11-PyMySQL | 0 | 0:1.0.2-2.el9 |
| Rocky Linux:9 | python3.12-PyMySQL | 0 | 0:1.1.0-3.el9 |
| SUSE:Linux Enterprise Module for Package Hub 15 SP5 | python-PyMySQL | 0 | 0.7.11-150000.3.3.1 |
| SUSE:Linux Enterprise Module for Package Hub 15 SP6 | python-PyMySQL | 0 | 0.7.11-150000.3.3.1 |
| Ubuntu:16.04:LTS | python-pymysql | 0 | No fix |
| Ubuntu:18.04:LTS | python-pymysql | 0 | No fix |
| Ubuntu:20.04:LTS | python-pymysql | 0 | 0.9.3-2ubuntu3.1 |
| Ubuntu:22.04:LTS | python-pymysql | 0 | 1.0.2-1ubuntu1.22.04.1 |
| Ubuntu:23.10 | python-pymysql | 0 | 1.0.2-1ubuntu1.23.10.1 |
| Ubuntu:24.04:LTS | python-pymysql | 0 | 1.0.2-2ubuntu1.1 |
| Ubuntu:24.10 | python-pymysql | 0 | 1.1.1-1ubuntu1 |
| Ubuntu:25.04 | python-pymysql | 0 | 1.1.1-1ubuntu1 |
| Ubuntu:Pro:16.04:LTS | python-pymysql | 0 | No fix |
| Ubuntu:Pro:18.04:LTS | python-pymysql | 0 | No fix |
| Wolfi | datadog-agent | 0 | 7.54.0-r1 |
| Wolfi | datadog-agent-core-integrations | 0 | 7.54.0-r1 |
| Wolfi | datadog-agent-fakeintake | 0 | 7.54.0-r1 |
| Wolfi | datadog-agent-jmx | 0 | 7.54.0-r1 |
| Wolfi | datadog-agent-oci-compat | 0 | 7.54.0-r1 |
| Wolfi | datadog-agent-s6-overlay | 0 | 7.54.0-r1 |
| Wolfi | datadog-cluster-agent | 0 | 7.54.0-r1 |
| Wolfi | datadog-cluster-agent-oci-compat | 0 | 7.54.0-r1 |
| Wolfi | dogstatsd | 0 | 7.54.0-r1 |
| Wolfi | py3-pymysql | 0 | 1.1.1-r0 |
| Wolfi | py3-supported-pymysql | 0 | 1.1.1-r0 |
| Wolfi | py3.10-pymysql | 0 | 1.1.1-r0 |
| Wolfi | py3.11-pymysql | 0 | 1.1.1-r0 |
| Wolfi | py3.12-pymysql | 0 | 1.1.1-r0 |
| Wolfi | py3.13-pymysql | 0 | 1.1.1-r0 |
| openSUSE:Leap 15.5 | python-PyMySQL | 0 | 0.7.11-150000.3.3.1 |
| openSUSE:Leap 15.6 | python-PyMySQL | 0 | 1.1.0-150600.3.3.1 |
Related vulnerabilities
- CVE-2025-64329 containerd CRI server: Host memory exhaustion through Attach goroutine leak Also affects datadog-agent
- CVE-2024-25621 containerd affected by a local privilege escalation via wide permissions on CRI directory Also affects datadog-agent
- CVE-2025-8869 When extracting a tar archive pip may not check symbolic links point into the extraction… Also affects datadog-agent
- CVE-2025-47908 Middleware causes a prohibitive amount of heap allocations when processing malicious… Also affects datadog-agent
- CVE-2025-50182 urllib3 does not control redirects in browsers and Node.js Also affects datadog-agent
- CVE-2025-4565 protobuf-python has a potential Denial of Service issue Also affects datadog-agent
- CVE-2024-47081 Requests is a HTTP library. Also affects datadog-agent
- CVE-2025-47273 setuptools has a path traversal vulnerability in PackageIndex.download that leads to… Also affects datadog-agent