# 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. ### 11. Nested API helpers fetch child records without organization in the query - Category: OWASP A01 Broken Access Control / Performance / Idiomatic Ecto - Evidence: `lib/towerops_web/controllers/api/v1/schedules_controller.ex:356`, `lib/towerops_web/controllers/api/v1/schedules_controller.ex:363`, `lib/towerops_web/controllers/api/v1/schedules_controller.ex:370`, `lib/towerops_web/controllers/api/v1/escalation_policies_controller.ex:279`, `lib/towerops_web/controllers/api/v1/escalation_policies_controller.ex:286` - Problem: child resources are fetched by global ID and then checked against the parent ID in Elixir. The parent is scoped first, so this is not an immediate data leak, but the database does unnecessary global lookups and the pattern is easy to copy into a real authorization bug. - Fix: move nested-resource lookups into the `OnCall` context and query with all available scope predicates in SQL, including organization via joins when possible. ## Low ### 16. MIB vendor listing counts files synchronously on request - Category: Performance - Evidence: `lib/towerops_web/controllers/api/v1/mib_controller.ex:350`, `lib/towerops_web/controllers/api/v1/mib_controller.ex:373` - Problem: each `GET /admin/api/mibs` request recursively walks the whole MIB directory with `Path.wildcard("**/*")`. This can be expensive with the large MIB tree already present in the repo and can block request processes under load. - Fix: cache counts, keep metadata in the database, or compute counts asynchronously.