# OWASP Top 10 Review (2021 edition) **Date**: 2026-05-13 **Framework**: [OWASP Top 10 — 2021](https://owasp.org/www-project-top-ten/) (the 2025 release is not yet finalized as of this audit; 2021 remains the current authoritative list). **Scope cross-reference**: every FAIL below cites a Phase 2 finding ID (`F-N`) for the underlying evidence. ## Per-Category Assessment | # | Category | Status | Findings | |---|----------|--------|----------| | A01 | Broken Access Control | **FAIL** | F-2 (path traversal via `dataFolder`) — F-1 closed via OTA feature revert | | A02 | Cryptographic Failures | PASS_WITH_WARNINGS | F-1 closed via revert; D-1 closed via Newtonsoft bump (13.0.4); F-7 (SHA-384 password hash, no salt/KDF) remains open as a hardening item | | A03 | Injection | **PASS** | linq2db parameterizes all queries; no string-concatenation SQL paths found in `Azaion.Services/*Service.cs` or `Azaion.Common/Database/*`. No `Process.Start` / `subprocess` usage in production code. No template injection paths. | | A04 | Insecure Design | PASS_WITH_WARNINGS | F-3 closed (UNIQUE INDEX `users_email_uidx` + `RegisterUser`/`RegisterDevice` consolidation); F-8 (no rate limiting on `/login`) remains as a hardening item | | A05 | Security Misconfiguration | **FAIL** | F-6 (container runs as root), F-13 (no HTTPS enforcement in code), F-9 (request DTOs missing validators), F-11 (placeholder credentials in `01_permissions.sql`). F-5 closed automatically (`EncryptionMasterKey` field deleted with the OTA revert). | | A06 | Vulnerable & Outdated Components | **PASS** | All `dotnet list package --vulnerable` checks return clean. D-1 (Newtonsoft.Json) was the only manual finding; closed in this audit by bumping to 13.0.4. Three deprecated-but-not-vulnerable packages noted in `dependency_scan.md`. | | A07 | Identification & Authentication Failures | PASS_WITH_WARNINGS | F-3 closed (DB UNIQUE INDEX now enforces one-row-per-email). F-7 (weak password hashing) and F-8 (no rate limiting) remain open as hardening items. | | A08 | Software & Data Integrity Failures | **PASS** | OTA flow that introduced the unsigned-manifest concern was reverted. CI/CD: secrets are env-injected, no in-repo secrets in `Dockerfile` / compose files used by prod. | | A09 | Security Logging & Monitoring Failures | **PASS_WITH_WARNINGS** | Serilog console + rolling file sink configured. F-12 (one unstructured log line in `ResourcesService`). No security-event-specific logger — login successes/failures, role changes, deletes are not separately auditable. | | A10 | Server-Side Request Forgery (SSRF) | **NOT_APPLICABLE** | The API never makes outbound HTTP calls based on user-controlled URLs. `CdnUrl` from `PublishResourceRequest` is stored and forwarded but never fetched server-side. | ## Cross-Reference Against `security_approach.md` The pre-cycle-1 `security_approach.md` "Known Security Observations" list is reconciled here: | Original observation | Status post-cycle-1 | |----------------------|---------------------| | 1. SHA-384 without per-user salt | **Still open** — F-7 | | 2. `hardware_hash` DB column unused | **Resolved by AZ-197** — column-level removal pending follow-up; field is now dead but the column is still in the schema (`02_structure.sql:9`). Not a security risk; cleanup task. | | 3. No path traversal protection on `dataFolder` | **Still open** — F-2 | | 4. Hardcoded DB credentials in test files | **Confirmed test-only** — F-10 | | 5. No rate limiting on `/login` | **Still open** — F-8 | | 6. No audit trail for security-relevant operations | **Still open** — A09 PASS_WITH_WARNINGS | | 7. No HTTPS enforcement in code | **Still open** — F-13 | | 8. Static encryption key salts hardcoded | **Resolved by cycle-2 cleanup** — `Security.GetApiEncryptionKey` was deleted entirely along with `EncryptTo` / `DecryptTo` and the encrypted-download endpoint. No hardcoded encryption-key salt remains in application code. (`ResourceColumnEncryption` was deleted along with the OTA revert.) | ## Cycle-2 Cleanup Verdict (2026-05-14) The cycle-2 cleanup removed three obsolete endpoints (`POST /resources/get/{dataFolder?}`, `GET /resources/get-installer`, `GET /resources/get-installer/stage`) and their orphaned support code (`Security.GetApiEncryptionKey` / `EncryptTo` / `DecryptTo`, `ResourcesService.GetEncryptedResource` / `GetInstaller`, `GetResourceRequest`, `WrongResourceName = 50`, `ResourcesConfig.SuiteInstallerFolder` / `SuiteStageInstallerFolder`). Net security impact: - **Observation 8 closed** (see table above) — the static encryption-key salt no longer exists in source. - **Attack surface reduced** under A02 (Cryptographic Failures): no more application-layer encryption stack means no more mis-keying, mis-IVing, or padding-oracle exposure to maintain. The remaining cryptographic surface in this codebase is JWT signing (HMAC-SHA256, library-managed) and SHA-384 password hashing. - **No new findings introduced.** Three endpoints fewer also means three fewer A01 / A05 surfaces to track. - **F-2 (path traversal via `dataFolder`)** remains open — the upload / list / clear endpoints still take `dataFolder` and still concatenate it directly with `ResourcesFolder`. The cleanup did not change this. ## Cycle-1 Specific Verdict The cycle-1 changes (AZ-513, AZ-196, AZ-183, AZ-197) introduced one new High-severity finding (F-1, on `/get-update`) and amplified one existing High (F-3, via `RegisterDevice`). Both were closed before any deploy: - **F-1 (resolved by feature revert)**: AZ-183 was reverted in full; the OTA delivery model itself is obsolete in the target architecture. - **F-3 (resolved)**: `RegisterDevice` now delegates to `RegisterUser`; `users.email` has a UNIQUE INDEX (`users_email_uidx`); UNIQUE-violation is translated to `EmailExists`. Other cycle-1 endpoints (`/devices`, `/classes/*`) have correct authorization wiring (`apiAdminPolicy`). ## Self-verification - [x] All current OWASP Top 10 categories assessed - [x] Each FAIL has at least one specific finding with evidence (F-N reference) - [x] NOT_APPLICABLE category has justification (A10)