Security Compliance Audit — HIPAA · SOC 2 Type II · FedRAMP Moderate
Date: 2026-03-19 Audited by: Internal engineering review Codebase: Nometria monorepo (backendPy/, backend/, apps/base44-downloader/, lib/, supabase/)
Overall status: ❌ NOT COMPLIANT with any of the three frameworks
How to Read This Document
Each requirement lists:- The exact control and its regulatory citation
- Status: ✅ Met · ⚠️ Partial · ❌ Not Met
- Evidence: What was found in the code (file + line)
- Risk: What breaks if this is not fixed
- Fix: The specific remediation
PART I — HIPAA Technical Safeguards
45 CFR Part 164, Subpart C
2025 NPRM note: HHS published proposed amendments on Jan 6, 2025 that would make all “addressable” controls (MFA, auto-logoff, encryption) strictly required. Final rule expected late 2025. All findings below already treat these as required.
164.312(a)(1) — Access Control
IA-1 · Unique User Identification (Required)
Every user and service must have a unique, traceable identity. No shared accounts.| Status | ⚠️ Partial |
| Evidence | Frontend uses Supabase Auth with individual user accounts (✅). However, unified-custom-sdk-supabase.js:62-65 exposes VITE_SUPABASE_SERVICE_ROLE_KEY — the all-powerful service role key — via a VITE_ prefixed env var, meaning Vite bundles it into the browser build. Any user can extract this key and impersonate any other user. |
| Risk | 🔴 Critical — service role bypasses all row-level security; attacker gets full DB read/write |
| Fix | Move service role key to server-side only. Prefix it SUPABASE_SERVICE_ROLE_KEY (no VITE_). Never reference it in any file under apps/*/src/. |
IA-2 · Emergency Access Procedure (Addressable → Required under NPRM)
| Status | ❌ Not Met |
| Evidence | No break-glass / emergency access procedure in code or docs. |
| Fix | Document and implement a time-limited emergency access role with automatic expiry and mandatory audit notification. |
IA-3 · Automatic Logoff (Addressable → Required under NPRM)
| Status | ❌ Not Met |
| Evidence | Auth.jsx:22 — AUTH_CACHE_TTL = 60000 (60 seconds). After login the session is cached client-side for 60 s with no inactivity timer. HIPAA requires automatic termination after a defined idle period (typically 15 minutes). unified-custom-sdk-supabase.js:43 — BROWSER_ME_CACHE_TTL_MS = 60000 adds a second layer of stale-auth caching. |
| Risk | 🟠 High — unattended workstations retain access |
| Fix | Implement idle timeout (15 min for ePHI-touching screens). Use supabase.auth.onAuthStateChange + an inactivity detector. Reduce cache TTL to ≤ 5 seconds for auth state, or eliminate the cache entirely. |
IA-4 · Encryption/Decryption (Addressable → Required under NPRM)
| Status | ❌ Not Met |
| Evidence | No encryption of ePHI at rest anywhere in the codebase. Files uploaded to uploads/ temp dir are unencrypted. No KMS integration visible. Supabase pgsodium is included in the docker-compose but not configured for column encryption. |
| Risk | 🔴 Critical — if storage medium is compromised, PHI is exposed in plaintext |
| Fix | Enable Supabase Vault for column-level encryption on sensitive fields. Encrypt uploaded files with AWS KMS before writing to disk/S3. Use pgcrypto for DB-level field encryption. |
164.312(b) — Audit Controls
AU-1 · Audit Logging (Required)
Record and examine activity in systems that contain or use ePHI.| Status | ❌ Not Met |
| Evidence | backendPy/main.py:131-141 — file URLs and parameters are printed with print() to stdout. There is no structured audit log capturing: who accessed what, when, from where, and what action was taken. No database audit table exists (confirmed by searching all .sql files — zero audit_log or audit_trail tables). |
| Risk | 🔴 Critical — HIPAA breach investigations require 6 years of audit records; without them, a breach cannot be investigated or reported correctly |
| Fix | Implement structured audit logging: every access to an ePHI endpoint must write {user_id, action, resource, timestamp, ip_address, result} to an append-only audit table. Use python-json-logger. Ship logs to CloudWatch/Datadog with 6-year retention. |
AU-2 · PHI in Logs (Required — corollary)
| Status | ❌ Not Met |
| Evidence | backendPy/main.py:139 — print(f" - File URL: {file_url}") logs raw file URLs which may contain patient identifiers (S3 signed URLs often encode user/patient info). backendPy/main.py:131 logs all payload keys. Multiple print() statements log operation details without PHI redaction. |
| Risk | 🟠 High — PHI in application logs = secondary exposure vector |
| Fix | Replace all print() with a logging.Logger instance that runs through a PHIRedactionFilter. Redact: URLs, email addresses, names, IDs from log output. |
164.312(c)(1) — Integrity
INT-1 · Data Integrity Mechanisms (Addressable → Required under NPRM)
| Status | ❌ Not Met |
| Evidence | All three FastAPI endpoints (/extract_file, /ai/invoke, /ai/generate-image) accept payload: dict = Body(...) — raw unvalidated dictionaries. No Pydantic models. No checksums or hash verification on uploaded files. backendPy/main.py:129. |
| Risk | 🟠 High — tampered payloads can corrupt OCR results or inject malicious file paths |
| Fix | Replace all dict = Body(...) with typed Pydantic models. Compute and store SHA-256 checksums of uploaded files. Verify checksums on retrieval. |
INT-2 · Transmission Integrity
| Status | ⚠️ Partial |
| Evidence | Production origins use HTTPS (supa.nometria.com, supa.nometria.com). However allow_methods=["*"], allow_headers=["*"] (backendPy/main.py:57-58) mean any HTTP verb and header is accepted — including non-standard ones that bypass integrity checks. No HSTS header enforcement visible. |
| Fix | Restrict CORS to explicit methods: ["POST", "GET"]. Add Strict-Transport-Security header. |
164.312(d) — Person or Entity Authentication
AUTH-1 · Multi-Factor Authentication (Addressable → Required under NPRM)
| Status | ❌ Not Met |
| Evidence | Auth.jsx:113-174 — only email/password and Google OAuth are implemented. Zero TOTP, SMS OTP, WebAuthn, or hardware key support. Password-only access to an application that processes medical records. |
| Risk | 🔴 Critical — credential stuffing, phishing, and password reuse are the #1 vector for healthcare breaches |
| Fix | Implement TOTP-based MFA via Supabase Auth MFA (it supports TOTP natively). Require MFA for any action that accesses, modifies, or exports records. |
AUTH-2 · Password Policy
| Status | ❌ Not Met |
| Evidence | Auth.jsx:185-188 — validation is only if (!email || !password). No minimum length, no complexity requirement, no breach-database check. |
| Risk | 🟠 High |
| Fix | Enforce minimum 12 characters, mixed case, numbers, special characters. Integrate haveibeenpwned.com Passwords API to reject known-breached passwords. |
AUTH-3 · Account Lockout
| Status | ❌ Not Met |
| Evidence | No rate limiting or lockout after failed login attempts visible anywhere. |
| Fix | Configure Supabase Auth rate limiting. Implement exponential backoff lockout: 5 failures → 5-minute lockout → escalating. |
164.312(e) — Transmission Security
TRANS-1 · Encryption in Transit (Addressable → Required under NPRM)
| Status | ⚠️ Partial |
| Evidence | Production domains use HTTPS (✅). backendPy/main.py:42-47 includes http://localhost origins (acceptable for dev, must not reach production). No TLS version pinning (TLS 1.2+ required). No Strict-Transport-Security header enforced at application level. |
| Risk | 🟡 Medium |
| Fix | Add HSTS header in nginx/proxy: Strict-Transport-Security: max-age=63072000; includeSubDomains; preload. Enforce TLS 1.2 minimum at load balancer. Ensure localhost CORS origins are stripped in production builds. |
TRANS-2 · End-to-End Encryption
| Status | ❌ Not Met |
| Evidence | Files uploaded to the OCR endpoint travel over HTTPS but are stored unencrypted in uploads/ then deleted. If the process crashes before cleanup, PHI sits on disk in plaintext. No server-side encryption for S3 bucket referenced in .env (BUCKET_NAME=own-my-app). |
| Fix | Enable S3 SSE-KMS on the bucket. Encrypt temp files with an ephemeral key on write, wipe the key on deletion. |
HIPAA Additional Requirements
HIPAA-ADD-1 · Minimum Necessary Access
| Status | ❌ Not Met |
| Evidence | unified-custom-sdk-supabase.js:62-65 — VITE_SUPABASE_SERVICE_ROLE_KEY is exposed to the browser (bypasses all RLS). Frontend operations that only need to read a user’s own records are performed with admin-level credentials. |
HIPAA-ADD-2 · Business Associate Agreement (BAA) Technical Implications
| Status | ❌ Not Met |
| Evidence | OpenAI is called via backendPy/main.py:310 and 358 with patient document content as the prompt. OpenAI does not have a default HIPAA BAA. Sending PHI to OpenAI without a signed BAA is a HIPAA disclosure violation. Sentry is integrated (package.json: @sentry/react) — also requires a BAA if PHI reaches error context. Mixpanel is used (Auth.jsx:160-164) and receives user.email — requires BAA or must be treated as a non-PHI-touching service. |
| Risk | 🔴 Critical — third-party disclosure without BAA = reportable breach |
| Fix | (1) Sign a BAA with OpenAI (available on Enterprise tier) OR strip all PHI before sending to AI. (2) Configure Sentry beforeSend to redact PHI. (3) Evaluate whether Mixpanel receives PHI. |
HIPAA-ADD-3 · Breach Detection
| Status | ❌ Not Met |
| Evidence | No intrusion detection, anomaly monitoring, or automated breach notification pipeline exists in the codebase. |
PART II — SOC 2 Type II
AICPA Trust Services Criteria (2017 + 2022 updates)
CC6 — Logical and Physical Access Controls
CC6.1 · Logical Access Security Measures
| Status | ❌ Not Met |
| Evidence | Zero authentication on any FastAPI endpoint. backendPy/main.py:127-130 — /extract_file is completely open. backendPy/main.py:274-276 — /ai/invoke is completely open. backendPy/main.py:435-437 — /ai/generate-image is completely open. Confirmed: grep -n "Depends|get_current_user|require_auth" returned zero results in both Python backends. Any internet-accessible client can call these endpoints. |
| Risk | 🔴 Critical |
| Fix | Add current_user = Depends(get_current_user) to every endpoint. Implement JWT validation middleware. |
CC6.2 · Prior to Issuing System Credentials
| Status | ❌ Not Met |
| Evidence | No identity verification, no access approval workflow. Signup is self-service with no domain restriction or admin approval. |
CC6.3 · Role-Based Access Control
| Status | ❌ Not Met |
| Evidence | No roles defined in the application. All authenticated users have identical permissions. No separation between admin, operator, and read-only roles. |
| Fix | Define roles in Supabase: admin, user, readonly. Enforce via RLS policies and application-level role checks. |
CC6.6 · Logical Access from Outside the Entity’s Network
| Status | ❌ Not Met |
| Evidence | backendPy/main.py:56-58 — allow_credentials=True + allow_methods=["*"] + allow_headers=["*"]. This combination means any origin in the list can make credentialed cross-origin requests with any HTTP method, including DELETE, PUT, PATCH. The combination of allow_credentials=True with allow_methods=["*"] is a misconfiguration — browsers will reject it unless origins are explicitly listed (not wildcards), but the over-broad method/header allowance remains. |
| Fix | allow_methods=["POST", "GET"], allow_headers=["Content-Type", "Authorization"], allow_credentials=False (use token auth instead). |
CC6.7 · Restrict Access to Confidential Information
| Status | ❌ Not Met |
| Evidence | No Row Level Security on any Supabase table. Confirmed: searched all .sql files in supabase/ — zero ENABLE ROW LEVEL SECURITY or CREATE POLICY statements. Any authenticated user can read all other users’ data via direct PostgREST API calls. |
| Risk | 🔴 Critical |
| Fix | For every table: ALTER TABLE [t] ENABLE ROW LEVEL SECURITY; + policies scoped to auth.uid(). |
CC6.8 · Prevent Unauthorized Access from Malicious Software
| Status | ❌ Not Met |
| Evidence | File uploads in backendPy/main.py:148-158 accept any file type (only soft MIME check at line 97-101 which is explicitly labeled “not fatal”). No antivirus scanning. A .exe disguised as .pdf would pass through to OCR processing. |
| Fix | Enforce strict MIME type + magic byte validation. Integrate ClamAV or VirusTotal API for malware scanning before processing. |
CC7 — System Operations
CC7.1 · Detect and Monitor for New Vulnerabilities
| Status | ❌ Not Met |
| Evidence | No pip-audit, npm audit, Snyk, or Dependabot configured. backendPy/requirements.txt pins opencv-python==4.6.0.66 and easyocr==1.7.1 — both have known CVEs in older versions. No dependency scanning in CI pipeline. |
| Fix | Add pip-audit and npm audit --audit-level=high to the CI pipeline. Add Dependabot to the GitHub repo. |
CC7.2 · Monitor System Components for Anomalous Behavior
| Status | ❌ Not Met |
| Evidence | No SIEM integration, no anomaly detection, no alerting for unusual access patterns (e.g., bulk data export, off-hours access). |
CC7.3 · Evaluate Security Events
| Status | ❌ Not Met |
| Evidence | No incident response runbook or security event escalation process visible. |
CC8 — Change Management
CC8.1 · Authorization of Changes
| Status | ⚠️ Partial |
| Evidence | Git is used (✅). No branch protection rules enforced at the code level (cannot verify GitHub settings from code alone). No required code review or security scan gate in CI visible. |
| Fix | Add CI pipeline with mandatory security scan (./scripts/run-tests.sh security:scan) as a required check before merge to main. |
PI1 — Processing Integrity
PI1.1 · Complete and Accurate Processing
| Status | ❌ Not Met |
| Evidence | All three API endpoints use payload: dict = Body(...) with no input schema. backendPy/main.py:129. Malformed, incomplete, or malicious payloads will be processed without validation errors, potentially producing corrupt OCR results silently. |
PI1.2 · Processing Error Handling
| Status | ❌ Not Met |
| Evidence | backendPy/main.py:186-193 — exceptions return {"error": str(e)} with the raw exception message to the caller. Internal system details, file paths, and Python tracebacks can be extracted by callers. |
| Fix | Catch all exceptions at the boundary, log internally with full details, return only a generic {"error": "Processing failed", "request_id": "..."} to the caller. |
C1 — Confidentiality
C1.1 · Confidential Information Identified and Protected
| Status | ❌ Not Met |
| Evidence | No data classification scheme. Files processed by OCR contain medical records but are not labeled, tracked, or protected differently from non-sensitive files. No encryption at rest. |
C1.2 · Dispose of Confidential Information
| Status | ⚠️ Partial |
| Evidence | backendPy/main.py:196-204 — temp files are deleted after processing (✅). However: (1) deletion is best-effort (try/except pass), so failures are silently swallowed; (2) no secure deletion (overwrite before unlink); (3) no retention/deletion policy for data stored in Supabase. |
| Fix | Use shutil.rmtree with error propagation or os.urandom() overwrite before deletion. Define and implement a data retention policy. |
P1 — Privacy
P1.1 · Privacy Notice
| Status | ⚠️ Partial |
| Evidence | apps/base44-downloader/src/pages/Privacy.jsx exists (✅). However, no data retention period, no right-to-deletion mechanism, and no data processing basis (consent/contract/legitimate interest) is documented in the codebase. |
PART III — FedRAMP Moderate
NIST SP 800-53 Rev 5 Baseline
AC — Access Control
AC-2 · Account Management
| Status | ❌ Not Met |
| Evidence | No account lifecycle management. Accounts are self-provisioned with no approval workflow, no periodic access review, no automatic disabling of inactive accounts. No privileged access management. |
AC-3 · Access Enforcement
| Status | ❌ Not Met |
| Evidence | No RBAC enforcement at the application layer. No RLS at the database layer. Confirmed: grep -n "Depends|role|permission" on backend files returns zero auth-related results. |
AC-6 · Least Privilege
| Status | ❌ Not Met |
| Evidence | unified-custom-sdk-supabase.js:62-65 — VITE_SUPABASE_SERVICE_ROLE_KEY (superadmin DB access) available in browser bundle. This is the opposite of least privilege. |
AC-7 · Unsuccessful Login Attempts
| Status | ❌ Not Met |
| Evidence | No account lockout after failed login attempts. Auth.jsx:181-234 — the form retries indefinitely. |
| Fix | Configure Supabase Auth’s built-in rate limiting. Add client-side exponential backoff. |
AC-17 · Remote Access
| Status | ⚠️ Partial |
| Evidence | HTTPS for web access (✅). No VPN or IP allowlist for admin/backend access. The FastAPI backend is network-accessible with zero authentication. |
AU — Audit and Accountability
AU-2 · Event Logging (FedRAMP: all of the following must be logged)
Required events: logon/logoff, privilege use, account management, policy changes, process creation, file access| Status | ❌ Not Met |
| Evidence | No structured event logging. backendPy/main.py uses print() exclusively. No log aggregation. No SIEM. Supabase has built-in auth logs but they are not being exported or monitored. |
AU-3 · Content of Audit Records
Each record must contain: date/time, source, event type, subject identity, outcome| Status | ❌ Not Met |
| Evidence | print() statements do not produce machine-parseable structured records with the required fields. |
AU-9 · Protection of Audit Information
| Status | ❌ Not Met |
| Evidence | Logs written to stdout only. No log integrity protection. Container restart destroys all logs. |
| Fix | Ship logs to CloudWatch/Datadog with write-once retention. Enable log signing. |
AU-11 · Audit Record Retention
FedRAMP Moderate requires 90 days online, 1 year archived| Status | ❌ Not Met |
| Evidence | No log retention policy anywhere in the codebase or configuration. |
IA — Identification and Authentication
IA-2 · Multi-Factor Authentication
FedRAMP requires MFA for ALL privileged users and ALL network access to non-privileged accounts| Status | ❌ Not Met |
| Evidence | Auth.jsx — email/password and Google OAuth only. No MFA of any kind. |
| Risk | 🔴 Critical — this is a hard FedRAMP requirement, not addressable |
IA-5 · Authenticator Management (Password Policy)
FedRAMP minimum: 15 chars, 1 upper, 1 lower, 1 number, 1 special. 60-day max age. No reuse of last 5.| Status | ❌ Not Met |
| Evidence | Auth.jsx:185-188 — only checks !email || !password. No length, complexity, or history requirements. |
IA-8 · Non-Organizational User Identification
| Status | ❌ Not Met |
| Evidence | No PIV/CAC or FICAM-approved credential support (required for federal use cases). |
SC — System and Communications Protection
SC-8 · Transmission Confidentiality and Integrity
FedRAMP requires FIPS 140-2 validated cryptography (TLS 1.2+)| Status | ⚠️ Partial |
| Evidence | Production uses HTTPS (✅). TLS version not pinned in application config. No FIPS 140-2 validated crypto module explicitly configured. Uvicorn without TLS termination at app level (relies on upstream proxy). |
| Fix | Document the TLS termination point. Verify TLS 1.2 minimum at load balancer. If direct TLS, configure with FIPS-validated cipher suites. |
SC-28 · Protection of Information at Rest
FedRAMP requires FIPS 140-2 validated encryption for data at rest| Status | ❌ Not Met |
| Evidence | No encryption at rest anywhere — not for uploaded files, not for database columns containing sensitive data, not for S3 bucket. |
SC-5 · Denial of Service Protection
| Status | ❌ Not Met |
| Evidence | No rate limiting on any endpoint. /extract_file accepts files up to 100 MB with no authentication and no per-IP rate limit — trivially weaponizable for resource exhaustion. |
| Fix | Add slowapi rate limiting middleware. Implement per-IP request quotas. |
SC-7 · Boundary Protection
| Status | ❌ Not Met |
| Evidence | The OCR backend (backendPy/) is a flat HTTP server with no authentication boundary, no WAF, no API gateway in front of it. It is directly internet-facing in the Docker setup. |
SI — System and Information Integrity
SI-2 · Flaw Remediation
| Status | ❌ Not Met |
| Evidence | No dependency scanning in CI. opencv-python==4.6.0.66 is pinned to a 2022 release. No documented patch cadence. |
SI-3 · Malware Protection
| Status | ❌ Not Met |
| Evidence | No malware scanning on file uploads. Containers run without host-level EDR. |
SI-7 · Software, Firmware, and Information Integrity
| Status | ❌ Not Met |
| Evidence | Docker images are not pinned by digest (FROM python:3.11-slim with no SHA256 pin). Rebuild could pull a different image. No SBOM generated. |
| Fix | Pin images: FROM python:3.11.9-slim-bookworm@sha256:<hash>. Generate SBOM with syft. |
SI-10 · Information Input Validation
| Status | ❌ Not Met |
| Evidence | All three FastAPI endpoints use dict = Body(...) — no schema, type, range, or format validation. backendPy/main.py:129, 275, 436. |
CM — Configuration Management
CM-6 · Configuration Settings
| Status | ❌ Not Met |
| Evidence | No hardened baseline configuration. Containers run as root (confirmed: no USER directive in Dockerfile, PATH="/root/.deno/bin:..." visible). No CIS benchmark applied. |
| Fix | Add RUN useradd -r -u 1001 appuser && chown -R appuser /app and USER appuser to all Dockerfiles. |
CM-7 · Least Functionality
| Status | ❌ Not Met |
| Evidence | Uvicorn is started without disabling the debug/docs endpoints. FastAPI auto-generates /docs (Swagger UI) and /redoc endpoints that fully document the API, including all request/response schemas, to any unauthenticated caller. |
| Fix | In production: app = FastAPI(docs_url=None, redoc_url=None, openapi_url=None) |
Master Compliance Scorecard
HIPAA Technical Safeguards (45 CFR 164.312)
| Control | Requirement | Status | Severity |
|---|---|---|---|
| 164.312(a)(1)-i | Unique user identification | ⚠️ Partial | 🔴 |
| 164.312(a)(1)-ii | Emergency access procedure | ❌ Not Met | 🟡 |
| 164.312(a)(1)-iii | Automatic logoff | ❌ Not Met | 🟠 |
| 164.312(a)(1)-iv | Encryption/decryption at rest | ❌ Not Met | 🔴 |
| 164.312(b) | Audit controls / logging | ❌ Not Met | 🔴 |
| 164.312(b) | No PHI in logs | ❌ Not Met | 🟠 |
| 164.312(c)(1) | Data integrity / input validation | ❌ Not Met | 🟠 |
| 164.312(c)(2) | Transmission integrity | ⚠️ Partial | 🟡 |
| 164.312(d) | MFA / strong authentication | ❌ Not Met | 🔴 |
| 164.312(d) | Password policy | ❌ Not Met | 🟠 |
| 164.312(d) | Account lockout | ❌ Not Met | 🟠 |
| 164.312(e)(1) | Encryption in transit | ⚠️ Partial | 🟡 |
| 164.312(e)(2) | Secure temp file handling | ⚠️ Partial | 🟡 |
| Additional | Minimum necessary access | ❌ Not Met | 🔴 |
| Additional | BAA with OpenAI / Sentry | ❌ Not Met | 🔴 |
| Additional | Breach detection capability | ❌ Not Met | 🟠 |
SOC 2 Type II (AICPA TSC)
| Control | Requirement | Status | Severity |
|---|---|---|---|
| CC6.1 | API authentication | ❌ Not Met | 🔴 |
| CC6.2 | Credential provisioning process | ❌ Not Met | 🟡 |
| CC6.3 | Role-based access control | ❌ Not Met | 🟠 |
| CC6.6 | CORS / remote access controls | ❌ Not Met | 🟠 |
| CC6.7 | Row-level security on DB | ❌ Not Met | 🔴 |
| CC6.8 | Malware prevention on uploads | ❌ Not Met | 🟠 |
| CC7.1 | Dependency vulnerability scanning | ❌ Not Met | 🟠 |
| CC7.2 | Anomaly monitoring / SIEM | ❌ Not Met | 🟡 |
| CC7.3 | Incident response process | ❌ Not Met | 🟡 |
| CC8.1 | Change management / CI gates | ⚠️ Partial | 🟡 |
| PI1.1 | Input validation | ❌ Not Met | 🟠 |
| PI1.2 | Error handling / no detail leakage | ❌ Not Met | 🟠 |
| C1.1 | Data classification & protection | ❌ Not Met | 🟠 |
| C1.2 | Secure data disposal | ⚠️ Partial | 🟡 |
| P1.1 | Privacy notice + rights | ⚠️ Partial | 🟡 |
FedRAMP Moderate (NIST SP 800-53 Rev 5)
| Control | Requirement | Status | Severity |
|---|---|---|---|
| AC-2 | Account management lifecycle | ❌ Not Met | 🟠 |
| AC-3 | Access enforcement / RBAC | ❌ Not Met | 🔴 |
| AC-6 | Least privilege | ❌ Not Met | 🔴 |
| AC-7 | Account lockout policy | ❌ Not Met | 🟠 |
| AC-17 | Remote access security | ⚠️ Partial | 🟡 |
| AU-2 | Required event logging | ❌ Not Met | 🔴 |
| AU-3 | Structured audit record content | ❌ Not Met | 🟠 |
| AU-9 | Log integrity protection | ❌ Not Met | 🟠 |
| AU-11 | 90-day online / 1-year log retention | ❌ Not Met | 🟠 |
| IA-2 | MFA (hard requirement) | ❌ Not Met | 🔴 |
| IA-5 | 15-char password policy | ❌ Not Met | 🟠 |
| IA-8 | Non-org user identity (PIV/FICAM) | ❌ Not Met | 🟡 |
| SC-5 | DoS protection / rate limiting | ❌ Not Met | 🟠 |
| SC-7 | Boundary protection / WAF | ❌ Not Met | 🟠 |
| SC-8 | TLS 1.2+ / FIPS crypto | ⚠️ Partial | 🟡 |
| SC-28 | Encryption at rest (FIPS) | ❌ Not Met | 🔴 |
| SI-2 | Patch / flaw remediation | ❌ Not Met | 🟠 |
| SI-3 | Malware protection | ❌ Not Met | 🟠 |
| SI-7 | Image integrity / SBOM | ❌ Not Met | 🟡 |
| SI-10 | Input validation | ❌ Not Met | 🟠 |
| CM-6 | Hardened config / non-root containers | ❌ Not Met | 🟡 |
| CM-7 | Least functionality (disable Swagger) | ❌ Not Met | 🟡 |
Remediation Roadmap
🔴 WEEK 1 — Stop the Bleeding (Critical)
These must be done before processing any real customer or patient data.| # | Action | File(s) | Effort |
|---|---|---|---|
| 1 | Remove VITE_ prefix from SUPABASE_SERVICE_ROLE_KEY — move it server-side only | lib/unified-custom-sdk-supabase.js, all .env files | 2h |
| 2 | Add JWT authentication to all FastAPI endpoints via Depends(get_current_user) | backendPy/main.py, backend/main.py | 1 day |
| 3 | Enable Row Level Security on all Supabase tables | supabase/ migrations | 1 day |
| 4 | Disable FastAPI /docs and /openapi.json in production | backendPy/main.py:38 | 30 min |
| 5 | Evaluate and either sign BAA with OpenAI or strip PHI before sending | backendPy/main.py:310-415 | 1 day |
| 6 | Configure Sentry beforeSend with PHI redaction filter | package.json, app init | 2h |
🟠 WEEK 2 — Authentication & Input Hardening
| # | Action | File(s) | Effort |
|---|---|---|---|
| 7 | Implement TOTP MFA via Supabase Auth | Auth.jsx | 2 days |
| 8 | Replace all dict = Body(...) with Pydantic models | backendPy/main.py, backend/main.py | 1 day |
| 9 | Add password policy (12+ chars, complexity, haveibeenpwned check) | Auth.jsx | 1 day |
| 10 | Add slowapi rate limiting to all endpoints | backendPy/main.py | 4h |
| 11 | Replace print() with structured logger + PHI redaction filter | backendPy/main.py, backend/main.py | 1 day |
| 12 | Restrict CORS: explicit methods/headers, remove credentials | backendPy/main.py:53-58 | 1h |
| 13 | Reduce auth cache TTL to ≤5s; add inactivity auto-logoff (15 min) | Auth.jsx:22, unified-custom-sdk-supabase.js:43 | 4h |
🟡 WEEK 3 — Encryption & Observability
| # | Action | File(s) | Effort |
|---|---|---|---|
| 14 | Enable S3 SSE-KMS on own-my-app bucket | AWS console + backendPy/main.py | 4h |
| 15 | Implement audit logging table + middleware that logs all data access | backendPy/main.py, new supabase/ migration | 2 days |
| 16 | Add pip-audit and npm audit to CI pipeline | scripts/run-tests.sh | 2h |
| 17 | Pin Docker base images to SHA256 digest + add USER appuser | backendPy/Dockerfile, apps/base44-downloader/Dockerfile | 2h |
| 18 | Add HSTS header enforcement at nginx/proxy level | deployment/ | 2h |
| 19 | Implement strict MIME type + file extension validation on uploads | backendPy/main.py:148-158 | 4h |
| 20 | Define and implement data retention + deletion policy | supabase/ migrations | 1 day |
Note: FedRAMP certification additionally requires a 3PAO (Third-Party Assessment Organization) assessment, a System Security Plan (SSP), and continuous monitoring. The above addresses only the technical code/DB controls. Operational, administrative, and organizational controls are outside the scope of this document.