Skip to content

Security: udhay8005/Inventory-management

Security

SECURITY.md

Security Policy

This repository hosts the WMS used by the Dakshin Vrindavan cow-care trust for their internal warehouse. It is published in the open so a successor admin can re-install it, but it is operationally a single-tenant install — there is no SaaS, no multi-tenant deployment, no public bug-bounty programme.

Reporting a vulnerability

If you discover a security issue that could affect this codebase, please email office.dakshinvrindavan@gmail.com with:

  • a brief description of the issue
  • the smallest reproduction you can construct
  • whether the fix appears to touch backup, restore, ACLs, or the audit trail

Please do not open a public GitHub issue for security defects. The trust will acknowledge within seven days and ship a fix (or a documented mitigation) on the same release cadence as functional work — see CHANGELOG.md and the v19.0.<release> tags.

Scope

In scope:

  • The seven custom addons (addons/wms_*)
  • The deployment scripts (scripts/*.ps1)
  • The /wms/* controllers and JSON endpoints
  • The backup + restore + off-site copy pipeline

Out of scope:

  • Defects in upstream Odoo 19 CE (report those at https://github.com/odoo/odoo)
  • Defects in PostgreSQL, Windows, or the host OS
  • Issues that require physical access to the prod machine
  • Speculation about the trust's specific deployment topology

Supported versions

Only the latest v19.0.<release> tag is supported. Older tags are kept for historical reference but do not receive security backports — upgrade.

Shipped security controls

The following controls are live in the current release. Internal hardening notes live in docs/08-security.md; this section is the externally-facing summary.

  1. Database manager UI hard-disabled. The Odoo database manager is shut off at three layers: list_db=False and db_listing=False in the runtime config, and /web/database/* requests are redirected to /web/login?error=manager_disabled. There is no path to create, drop, duplicate, or back up a database through the web UI.
  2. Role model. Three named base roles — WMS / Store Keeper (group_wms_user), WMS / Manager (group_wms_manager), WMS / Repair Tech (group_repair_tech) — plus an optional WMS / Buyer (group_buyer). Five capability sub-groups, all in the wms_location namespace: group_wms_can_scan_receive, group_wms_can_scan_issue, group_wms_can_file_damage, group_wms_can_submit_audit, group_wms_can_manage_catalog.
  3. Health endpoint is token-gated. /wms/health is declared auth='public' but gated by the ir.config_parameter wms_reports.health_token — a 32-hex secret auto-generated by install-native.ps1 at install time. Tokens are compared via odoo.tools.consteq and accepted either as ?token=<value> or via the X-Health-Token header. Missing or wrong token returns HTTP 401 with body {"status":"unauthorized"}.
  4. Backups are encrypted and integrity-checked. Backups use gpg --symmetric --cipher-algo AES256, with the passphrase supplied via a short-lived --passphrase-file invoked through cmd /c (this avoids the PowerShell 5.1 NativeCommandError triggered by gpg-agent stderr). Every artefact ships with a SHA-256 integrity checksum, and the weekly restore drill requires pg_restore --list to return ≥100 TOC entries before the drill is considered a pass. Every run writes an audit row to wms_backup_audit.
  5. Off-site copy is opt-in and failure-safe. BACKUP_OFFSITE_DIR is read only from .env. If blank, off-site is disabled and the local backup still succeeds. If set, the destination is created if missing, the .gpg artefact is copied, the SHA-256 is re-verified at the destination, and a mirrored retention pass runs (-Retain defaults to 14). Any off-site failure is logged but never fails the local backup.
  6. Scheduled tasks run as SYSTEM. WMS Daily Backup (4:30 PM daily), WMS Weekly Restore Drill (3:00 AM Sunday), and WMS Manual Backup (no trigger; run on demand by the in-app Backup Now wizard) run under NT AUTHORITY\SYSTEM with LogonType=ServiceAccount and RunLevel=Highest. This means BACKUP_OFFSITE_DIR, if set, must be a path reachable by SYSTEM (local disk or a UNC share with a SYSTEM-level credential).
  7. Placeholder password deny-list at install. install-native.ps1 rejects obvious placeholder admin passwords — changeme, changeme123, admin, password, and similar — before bootstrapping the database, so a fresh install cannot accidentally ship to production with a known-bad credential.
  8. Google Drive uploads use the minimal drive.file scope. The optional Drive integration requests exactly one OAuth scope — the app can see and touch only files it created (the Inventory_Backups tree), never the rest of the Drive or the Google account. The artefacts it uploads remain GPG AES256 ciphertext; the passphrase never leaves the box.
  9. The Drive refresh token is DPAPI machine-scope. The OAuth refresh token is stored at config\gdrive-token.json.dpapi, encrypted with DPAPI LocalMachine scope so the NT AUTHORITY\SYSTEM scheduled tasks can read it but an exfiltrated copy is useless off-box. The file is gitignored; rotate it by re-running scripts\setup-gdrive-auth.ps1.
  10. Drive uploads are checksum-verified. Every upload must report a Drive-side sha256Checksum matching the local SHA-256 of the artefact before it counts as success; a mismatch deletes the remote file and the upload is retried. Drive errors never fail the local backup.
  11. Drive restore into production is double-gated. gdrive-restore.ps1 refuses to restore into the live wms database unless BOTH -Force AND the literal -ConfirmTarget wms are passed — otherwise it exits 5 (PROD_GUARD) before any side effect.

There aren't any published security advisories