Hey,
Odoo SQL queries are not really detected via SonarQube. We found out that some of our developers created code which is vulnerable to SQL injections but it wasn’t detected.
Example Code:
def get_used_purchase_orders(self):
self.ensure_one()
self.env.cr.execute("""
SELECT COALESCE(SUM(amount_total), 0), COUNT(*)
FROM purchase_order
WHERE service_id = %s
AND state IN ('purchase', 'done')
AND (company_id = %s OR company_id IS NULL)
""" % (self.id, self.env.user.company_id.id))
return self.env.cr.fetchall()[0]
Odoo uses psycopg2 under the hood. So the same rules for psycopg2 should be applied here. The correct code would be:
def get_used_purchase_orders(self):
self.ensure_one()
self.env.cr.execute("""
SELECT COALESCE(SUM(amount_total), 0), COUNT(*)
FROM purchase_order
WHERE service_id = %s
AND state IN ('purchase', 'done')
AND (company_id = %s OR company_id IS NULL)
""", (self.id, self.env.user.company_id.id))
return self.env.cr.fetchall()[0]
Here you find the code of the execute function: odoo/odoo/sql_db.py at bffaf28377f0adee0c988a98d6b730e7fbe30a6c · odoo/odoo · GitHub
Developer documentation: ORM API — Odoo 18.0 documentation
As reference: The tool bandit marks this as an issue:
>> Issue: [B608:hardcoded_sql_expressions] Possible SQL injection vector through string-based query construction.
Severity: Medium Confidence: Medium
CWE: CWE-89 (https://cwe.mitre.org/data/definitions/89.html)
More Info: https://bandit.readthedocs.io/en/1.8.6/plugins/b608_hardcoded_sql_expressions.html
Location: addons/blubb/models/purchase_order.py:317:28
316 self.ensure_one()
317 self.env.cr.execute("""
318 SELECT COALESCE(SUM(amount_total), 0), COUNT(*)
319 FROM purchase_order
320 WHERE service_id = %s
321 AND state IN ('purchase', 'done')
322 AND (company_id = %s OR company_id IS NULL)
323 """ % (self.id, self.env.user.company_id.id))
324 return self.env.cr.fetchall()[0]
- What language is this for?
- Python
- Which rule?
- python:S2077 or pythonsecurity:S3649
- Why do you believe it’s a false-positive/false-negative?
- It’s a false-negative because the code uses normal python formatting of the query and is not passing the arguments separately to the execute function.
- We are using
- SonarQube Server / Community Build - which version?
- Enterprise Edition v2025.3.1 (109879)
- SonarScanner CLI 7.2.0.5079
- SonarQube Server / Community Build - which version?
- How can we reproduce the problem? Give us a self-contained snippet of code (formatted text, no screenshots)
- see above