Skip to content

AI Coding Agent for Odoo Security Auditing

DeployMonkey Team · March 23, 2026 14 min read

Why Security Auditing Matters for Odoo

Odoo modules handle sensitive business data: customer information, financial records, employee details, and trade secrets. Yet many custom modules are deployed with security gaps: missing access control lists, sudo() calls that bypass security, SQL queries vulnerable to injection, controllers that don't verify authentication, and XSS vulnerabilities in rendered HTML. AI security auditing agents scan your module code and identify these vulnerabilities before they reach production.

What AI Security Agents Check

1. Missing Access Control

# AI scans for models without proper access rules:

"Security Audit: Access Control

  CRITICAL — Models without ACL rules:
  ├── custom.payment.token (stores payment data!)
  │   No ir.model.access.csv entry found
  │   Risk: Any authenticated user can read/write all records
  │   Fix: Add access rules for appropriate groups
  │
  └── custom.api.log (stores API keys in log entries)
      No ir.model.access.csv entry found
      Risk: Sensitive data exposed to all users

  WARNING — Models with overly permissive rules:
  ├── custom.customer.note
  │   All internal users have read/write/create/delete
  │   Should this be limited to sales team?
  │
  └── custom.financial.report
      All internal users can read
      Should financial reports be restricted to accounting group?

  Missing record rules:
  ├── custom.support.ticket — no multi-company rule
  │   Users in Company A can see Company B tickets
  └── custom.employee.review — no manager-only rule
      All HR users can see all reviews"

2. SQL Injection Vulnerabilities

# AI detects unsafe SQL construction:

"CRITICAL — SQL Injection Vulnerabilities:

  File: models/custom_report.py, line 45
  Code: cr.execute('SELECT * FROM res_partner WHERE name = \'%s\'' % name)
  Risk: Direct string interpolation in SQL query
  Fix:  cr.execute('SELECT * FROM res_partner WHERE name = %s', (name,))

  File: controllers/api.py, line 128
  Code: domain = [('name', 'ilike', request.params.get('search'))]
  Risk: Unvalidated user input in ORM domain (lower risk but sanitize)
  Fix:  Validate and sanitize search parameter before use

  File: models/custom_export.py, line 67
  Code: cr.execute(f'DELETE FROM {table_name} WHERE id = {record_id}')
  Risk: Table name and record ID from variable — potential injection
  Fix:  Use ORM unlink() or parameterized query with whitelisted table"

3. Unsafe sudo() Usage

# AI identifies sudo() calls that bypass security:

"WARNING — sudo() Usage Review:

  File: controllers/portal.py, line 34
  Code: records = request.env['account.move'].sudo().search(domain)
  Risk: Bypasses record rules — portal user might access all invoices
  Context: Domain uses partner_id filter, but still risky
  Fix:  Use request.env['account.move'].search(domain) with proper
        record rules, or verify domain cannot be manipulated

  File: models/custom_workflow.py, line 89
  Code: order.sudo().write({'state': 'approved'})
  Risk: Current user might not have approval permission
  Context: Called from button action — check group on button
  Fix:  Add groups= attribute to button in view, or check
        self.env.user.has_group() before sudo() write

  Acceptable sudo() usage found (5 instances):
  ├── Mail template rendering (standard pattern) ✓
  ├── Sequence number generation (standard pattern) ✓
  └── System parameter read (standard pattern) ✓"

4. XSS Vulnerabilities

# AI checks for cross-site scripting risks:

"WARNING — Potential XSS:

  File: models/custom_product.py, line 23
  Field: description = fields.Html(sanitize=False)
  Risk: Unsanitized HTML stored and rendered
  Fix:  Use sanitize=True (default) or sanitize_tags=True

  File: controllers/website.py, line 56
  Code: return request.render('module.template', {'user_input': raw_input})
  Risk: If template uses t-raw on user_input, XSS is possible
  Check: Verify template uses t-esc (escaped) not t-raw (unescaped)

  File: static/src/js/widget.js, line 42
  Code: this.el.innerHTML = this.props.value;
  Risk: Direct innerHTML assignment with user-controlled value
  Fix:  Use this.el.textContent or sanitize before innerHTML"

5. Authentication & Authorization

# AI checks controller endpoints:

"Security Audit: Controllers

  CRITICAL — Unauthenticated endpoints:
  ├── /api/customer/data (type='json', auth='none')
  │   Returns customer data without any authentication
  │   Fix: Change to auth='user' or auth='public' with API key check
  │
  └── /api/export/csv (type='http', auth='none')
      Allows CSV export of any model without authentication
      Fix: Require authentication and verify model access

  WARNING — Missing CSRF protection:
  ├── /custom/webhook (type='json', auth='public', csrf=False)
  │   CSRF disabled — verify this is intentionally for webhooks
  │   If so: validate webhook signature/secret
  │
  └── /custom/form/submit (type='http', auth='public', csrf=False)
      Form submission without CSRF — vulnerable to forged requests
      Fix: Enable CSRF or add custom token validation"

Security Score

CategoryIssuesSeverityAuto-fixable
Access Control42 Critical, 2 WarningYes (CSV generation)
SQL Injection33 CriticalYes (parameterize)
sudo() Misuse22 WarningNeeds review
XSS31 Critical, 2 WarningPartial
Authentication42 Critical, 2 WarningPartial
Total167 Critical, 9 Warning

OWASP Top 10 Coverage

  • A01 Broken Access Control: ACL and record rule verification
  • A02 Cryptographic Failures: check for plaintext password storage
  • A03 Injection: SQL injection and ORM domain injection checks
  • A04 Insecure Design: architecture-level security review
  • A05 Security Misconfiguration: debug mode, default passwords
  • A06 Vulnerable Components: outdated Python package dependencies
  • A07 Authentication Failures: session handling, password policies
  • A08 Data Integrity: check for unsigned data in critical flows
  • A09 Logging Failures: sensitive data in logs, missing audit trail
  • A10 SSRF: check for user-controlled URLs in server-side requests

Automated Fix Generation

# AI generates fix patches:

# Fix 1: SQL injection — parameterize query
# File: models/custom_report.py
- cr.execute('SELECT * FROM res_partner WHERE name = \'%s\'' % name)
+ cr.execute('SELECT * FROM res_partner WHERE name = %s', (name,))

# Fix 2: Missing ACL — generate access rules
# File: security/ir.model.access.csv (append)
+ access_custom_payment_token_user,...,model_custom_payment_token,account.group_account_user,1,0,0,0
+ access_custom_payment_token_manager,...,model_custom_payment_token,account.group_account_manager,1,1,1,1

# Fix 3: Unsafe HTML field
# File: models/custom_product.py
- description = fields.Html(sanitize=False)
+ description = fields.Html(sanitize=True)

DeployMonkey AI Security Auditor

DeployMonkey's AI security agent scans your custom Odoo modules before deployment. It checks access controls, SQL injection, XSS, authentication, and sudo usage. Get a security score with prioritized fixes before any code reaches production.