From 3632580d1bdf9c9d69f6e83bc1fc6916e6d5292b Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Mon, 11 May 2026 18:54:12 -0500 Subject: [PATCH] fix: address security and reliability findings from bugs.md review - Client IP: only trust X-Forwarded-For from RFC 1918 proxy IPs - Webhook auth: handle nil/blank secret with controlled error, not 500 crash - Sudo redirect: reuse validated return_path? from login to prevent open redirect - Map live: remove redundant inline script (ensureLeaflet hook handles loading) - Bang calls: convert crash-prone exact matches to case in QR live and API controllers --- bugs.md | 104 ++++++++++++++++++ .../api/v1/escalation_policies_controller.ex | 12 +- .../api/v1/schedules_controller.ex | 12 +- .../controllers/user_sudo_controller.ex | 16 ++- .../live/map_live/index.html.heex | 18 --- lib/towerops_web/live/mobile_qr_live.ex | 12 +- lib/towerops_web/plugs/webhook_auth.ex | 26 +++-- lib/towerops_web/remote_ip.ex | 30 +++-- lib/towerops_web/user_auth.ex | 18 ++- 9 files changed, 201 insertions(+), 47 deletions(-) create mode 100644 bugs.md diff --git a/bugs.md b/bugs.md new file mode 100644 index 00000000..719c5893 --- /dev/null +++ b/bugs.md @@ -0,0 +1,104 @@ +# Bugs And Risk Findings + +Review date: 2026-05-11 + +Scope: application-owned Elixir/Phoenix code, templates, config, deployment manifests, scripts, and dependency manifests. Vendored code and bundled third-party MIB data were not reviewed as first-party code. + +Validation run: + +- `mix credo --strict`: passed, no issues. +- `mix deps.audit`: passed, no vulnerabilities found. +- `mix hex.audit`: passed, no retired packages found. +- `npm audit --prefix e2e --audit-level=low`: passed, 0 vulnerabilities. + +## High + +### 3. Admin MIB archive upload is vulnerable to archive bombs and symlink/path surprises + +- Category: OWASP A05 Security Misconfiguration / A08 Software and Data Integrity Failures / Availability +- Evidence: `lib/towerops_web/controllers/api/v1/mib_controller.ex:197`, `lib/towerops_web/controllers/api/v1/mib_controller.ex:244`, `lib/towerops_web/controllers/api/v1/mib_controller.ex:373` +- Problem: uploaded `.tar.gz` and `.zip` files are extracted by external commands into temp storage without limits on archive size, extracted file count, total uncompressed bytes, nesting depth, or per-file size. `validate_extracted_paths/1` checks expanded paths after extraction, but does not prevent resource exhaustion during extraction and does not reject symlinks before `File.cp_r!/2`. +- Fix: enforce upload body limits, archive entry count limits, max uncompressed bytes, max nesting depth, and reject symlinks/device files before copying. Prefer an archive reader that can inspect entries before writing, or run extraction in a constrained worker/container. Add tests for zip-slip, symlink, and oversized archive rejection. + +### 4. MIB tokenizer creates atoms from untrusted file content + +- Category: OWASP A04 Insecure Design / Availability +- Evidence: `lib/snmpkit/snmp_lib/mib/snmp_tokenizer.ex:621`, `lib/snmpkit/snmp_lib/mib/snmp_tokenizer.ex:655`, `lib/snmpkit/snmp_lib/mib/parser.ex:535` +- Problem: uploaded/imported MIB content is converted with `String.to_atom/1`. Atoms are not garbage collected on the BEAM, so a malicious or simply very large set of unique identifiers can exhaust the VM atom table and crash the node. +- Fix: keep tokenizer identifiers as strings or use a bounded atom allowlist with `String.to_existing_atom/1` only for known reserved words. Add a regression test that parsing many unique identifiers does not grow the atom table. + +## Medium + +### 6. CSP is duplicated and weakened by inline scripts + +- Category: OWASP A05 Security Misconfiguration / A03 Injection defense in depth +- Evidence: `lib/towerops_web/router.ex:21`, `lib/towerops_web/plugs/security_headers.ex:20`, `lib/towerops_web/components/layouts/root.html.heex:35`, `lib/towerops_web/components/layouts/root.html.heex:71`, `lib/towerops_web/components/layouts/root.html.heex:80` +- Problem: CSP is set in both the browser pipeline and endpoint-level security plug, with different directives. The effective behavior depends on header overwrite order. The policy also requires `'unsafe-inline'` because templates include inline scripts, reducing CSP's value against XSS. +- Fix: centralize CSP construction in one plug. Move inline scripts into `assets/js/app.js` or LiveView hooks and remove `'unsafe-inline'` where possible. Consider nonces only for unavoidable inline bootstrapping. + +### 9. Custom CSS is rendered from database into a raw style tag + +- Category: OWASP A03 Injection / CSS injection +- Evidence: `lib/towerops_web/live/status_page_live.html.heex:26` +- Problem: `@config.custom_css` is rendered inside `