# Proposal — Auditoría de seguridad y hardening (Odoo 18.0) ## Why Detectamos ataques automatizados cada vez más sofisticados que la heurística de fail2ban no frena, y somos responsables de la seguridad de nuestra infra y la de nuestros clientes. Necesitamos (a) un proceso de auditoría **reproducible** tipo "checklist de prevuelo" para verificar la resiliencia ante fuerza bruta, acceso indebido a datos vía API y vectores inadvertidos; y (b) corregir cinco hallazgos ya confirmados leyendo el propio código de `website_sale_aplicoop`. ## Objetivo Dejar la infra Odoo con una postura de seguridad auditable y repetible, y cerrar los hallazgos H1–H5 con tests que impidan su regresión. ## Alcance - **Solo nuestra infra** (autorización directa, sin terceros). Producción está tras nginx/traefik con TLS. - Auditoría **activa autorizada** (fuerza bruta controlada contra cuenta de test y fuzzing de endpoints) desde la máquina Kali de la red y desde `localhost` vía SSH, preferentemente contra un clon de staging o en ventana de mantenimiento con snapshot previo. - Remediación de los hallazgos confirmados en `website_sale_aplicoop` (+ `groups_id` en la server action de mandatos SEPA de `account_banking_mandate_batch`). ## No-objetivos - No se audita ni escanea infra de terceros ni hosting ajeno. - No se corrige aquí ningún hallazgo **nuevo** que surja durante la auditoría activa: se registra en el findings register y se aborda en un change posterior (salvo severidad crítica, que se escalará). - No se modifica `ocb/` ni los addons OCA originales. ## What Changes - **Proceso de auditoría**: se añaden entregables de documentación (`docs/SECURITY_AUDIT_CHECKLIST.md`, `docs/SECURITY_AUDIT_RUNBOOK.md`, `docs/SECURITY_FINDINGS.md`) y scripts no destructivos en `scripts/security/` (probe de ACL vía API, probe de IDOR, harness de fuerza bruta, PoC de CSRF, recon web) parametrizados con cuentas de test. - **Fix H1 (Alta)** — ACL con `group_id` vacío que concede write+create global sobre `group.order` y `group.order.slot`: se reemplaza por ACLs de mínimo privilegio (lectura interna/portal explícitas; escritura solo manager). Los writes de los controladores usan `sudo()` y no dependen de estas ACLs. - **Fix H2 (Alta)** — record rule de `product.supplierinfo` con `domain=[(1,'=',1)]` que expone todos los precios de proveedor al portal. El portal usa `supplierinfo` para pintar el **origen** del producto y el **proveedor principal** en la web, así que no se elimina sin más: o se preparan esos valores server-side (vía `sudo()` en el controlador, según la regla "sin lógica en QWeb") o se acota el dominio a los productos accesibles por el usuario, sin exponer campos de coste/precio. - **Fix H3 (Media)** — endpoints de cambio de estado con `csrf=False`: se convierten a `type="json"` (bloquea el POST de formulario cross-site), tomando como plantilla `confirm_order_from_portal`. - **Fix H4 (Media)** — endpoints de lectura/ajax que solo comprueban `exists()`+`state`: se añade comprobación de pertenencia al grupo reutilizando `_validate_user_group_access` / `_get_consumer_group_for_user`. - **Fix H5 (Baja)** — `t-raw` inyectado en `