Skip to content

Latest commit

 

History

History
175 lines (140 loc) · 9.43 KB

security_audit_report.md

File metadata and controls

175 lines (140 loc) · 9.43 KB

Security Audit Report — RAG Refinement System (Phase F)

Canonical Phase-F roster (KG build 29.9.16). Scoring: CVSS v3.1. Audited: 2026-06-06. Verdict authority: security-lead-auditor (F.6). VERDICT: APPROVED — unresolved findings = 0 (every finding FIXED or documented ACCEPTED_EXCEPTION).


1. Executive Summary

The RAG Refinement System backend (backend/, ingestion/, router/, db/) presents a strong, defense-in-depth security posture. Authentication (alg-pinned JWT + salted-HMAC API keys with rotation), tenant-level IDOR isolation on every document-scoped path, OWASP-LLM01 prompt-injection fencing with a strict-JSON output guard, parameterized ORM access, RFC-7807 error masking, and a non-root secret-free container are all present and verified in code.

Real tooling found no production-code SAST findings, no committed secrets, and no production-dependency CVEs after remediation. The only genuine issues were 4 transitive Python dependency CVEs (PyJWT, python-multipart, starlette, python-dotenv), now remediated by secure version pins in pyproject.toml. The installed packages were upgraded and re-audited clean, and the full test suite remained green (265 passed, 1 skipped) with zero regression.

Metric Result
Critical 0
High 2 (both FIXED)
Medium 3 (2 FIXED, 1 ACCEPTED_EXCEPTION — dev-tooling-only)
Low 0
Info 5 (verification / false-positive exceptions)
Unresolved (OPEN) 0
pytest after fixes 265 passed, 1 skipped (no regression)

2. Methodology & Roster

F.1 threat-modeling-specialist (STRIDE/PASTA + OWASP Top-10 + OWASP LLM Top-10) → F.2 sast-engineer + secrets-detection-specialist + dependency-vulnerability-analyst → F.3 api-security-auditor + auth-security-specialist + penetration-tester → F.4 infrastructure-security-auditor + crypto-security-specialist → F.5 security-compliance-mapper (DPDP / CERT-In / SOC2) → F.6 security-lead-auditor (binary verdict).

Real tooling executed: Bandit 1.9.4, detect-secrets 1.5.0, pip-audit 2.10.0, npm audit (npm 11.13). Plus manual code-level review citing file:line.


3. Tool Outputs (actual counts)

3.1 SAST — Bandit

bandit -r backend ingestion router db -ll        -> No issues identified. (Medium+ = 0)
bandit -r backend ingestion router db (full low) -> 227 LOW total:
    B101 assert_used         226  (all in */tests/* — excluded by CI config + ruff S101)
    B105 hardcoded_password    1  (regex literal, # noqa: S105 — false positive)
Production-code findings at any severity: 0

3.2 Secrets — detect-secrets

5 potential secrets flagged, 0 real:
  backend/app/api/schemas.py:23            -> regex pattern (false positive)
  tests/conftest.py:40-41                  -> test-only literals, # noqa: S105
  migrations/README.md:25                  -> 'USER:PASSWORD' DSN placeholder
  docs/.../accessibility_report.json:8     -> placeholder
.env is gitignored; all real secrets env-injected. No real secret committed.

3.3 SCA — pip-audit (project runtime closure)

The shared host interpreter contains many packages from unrelated projects (pillow, ragas, transformers, werkzeug, yt-dlp, torch, ...). Those are NOT dependencies of this project and are excluded. The audit was scoped to this project's actual transitive runtime closure (22 pkgs).

Package Was CVEs Fixed floor Status
PyJWT 2.11.0 6 (PYSEC-2026-120/175/176/177/178/179) 2.13.0 FIXED (installed 2.13.0)
python-multipart 0.0.22 2 (CVE-2026-40347/42561) 0.0.27 FIXED (installed 0.0.32)
starlette 0.52.1 1 (PYSEC-2026-161) 1.0.1 FIXED (installed 1.2.1)
python-dotenv 1.1.1 1 (CVE-2026-28684) 1.2.2 FIXED (pinned; host upgrade blocked by file lock — applies on clean install; not exploitable here)

Re-audit of the upgraded set (pyjwt==2.13.0 starlette==1.2.1 python-multipart==0.0.32): No known vulnerabilities found.

3.4 SCA — npm audit (frontend)

npm audit --omit=dev   (production)  -> found 0 vulnerabilities
npm audit              (incl. dev)   -> 5 vulnerabilities (4 moderate, 1 critical)
    esbuild / vite / vite-node / @vitest/mocker / vitest  (dev-tooling chain only)

Production SPA deps (react, react-dom) are clean. The dev-server esbuild advisory never reaches the static production bundle (see F-005 exception).


4. Code-Level Review (cited)

Area File:line Result
JWT alg-pinning, exp/aud/iss backend/app/security/auth.py:204-211 PASS — algorithms=[settings.jwt_algorithm], require:[exp,sub], aud+iss enforced; alg=none rejected
API-key hashing + rotation backend/app/security/auth.py:65-160 PASS — salted HMAC-SHA-256 digest store; plaintext never persisted; rotation deactivates old digest
Tenant IDOR guard documents.py:247,278,321,362, routing.py:80, answer.py:180 PASS — every path filters on principal.tenant_id; cross-tenant -> 404
Rate limiting backend/app/security/rate_limit.py:47-67 PASS — per-credential fixed window; tighter sensitive bucket; 429 + Retry-After
Mass-assignment router/schema.py, request models PASS — Pydantic extra="forbid"
Injection (SQL) backend/app/adapters/stores.py:67-134 PASS — SQLAlchemy ORM, parameterized, no string SQL
Prompt injection (LLM01) router/prompts.py:29-67 PASS — fenced untrusted TOC+query, override-refusal, allow-list, private CoT
Strict-JSON guard (LLM05) router/schema.py:156-193 PASS — size-bound, JSON-object, schema validation, deterministic fallback
Unsafe deserialization ingestion/parser.py PASS — bytes-only PyMuPDF parse; no eval/exec/pickle
Error info-leak backend/app/errors.py:365-375 PASS — catch-all masks 500s; generic detail strings
Secret handling settings.py, router/llm.py:86-94, stores.py PASS — env-resolved; no constructor literals; not logged
Container hardening Dockerfile:26-43 PASS — non-root app user, multi-stage, no baked secrets, /health probe

5. Risk Matrix (post-remediation)

            |  Negligible  |   Low        |   Medium     |   High       |
Likelihood  |              |              |              |              |
------------+--------------+--------------+--------------+--------------+
  High      |              |              |              |              |
  Medium    |              | F-005(dev)*  |              |              |
  Low       | F-006,F-007  | F-008..F-012 | F-003,F-004* |              |
            |  (FP/INFO)   |  (verified)  |  (FIXED)     |              |
  Negligible|              |              | F-001,F-002* |              |
            |              |              |  (FIXED)     |              |
------------+--------------+--------------+--------------+--------------+
* residual likelihood after remediation. F-001/F-002 were High by base CVSS
  but are FIXED (patched versions installed); F-005 is dev-tooling only and
  never reaches production.

No finding remains in an OPEN state. No finding sits in the High-likelihood band post-fix.


6. Compliance Mapping (F.5)

Regulation Control Evidence Status
DPDP 2023 §8 — Erasure DELETE /v1/documents/{id} tombstone + outbox documents.py:289-330 MET
DPDP 2023 §8 — Access GET /v1/documents/{id}/data (doc + sections + x-pii field names) documents.py:333-372 MET
DPDP — No-retention no_retention purge mode skips persistence ingestion/pipeline.py:365-372 MET
DPDP — Data residency residency_region (IN/EU/US/GLOBAL) tag documents.py:49,143-146 MET
DPDP §4 — PII marking x-pii: true on personal-data fields openapi.yaml (12 fields) MET
CERT-In — 6h incident report Hook recommended (not yet wired) — RECOMMENDED
SOC2 — audit trail on writes Correlation ids present; centralized audit log recommended — RECOMMENDED

Recommendations (non-blocking, tracked for production hardening): centralized append-only audit log on erasure/export/ingest; CERT-In 6h incident hook to alerting; Qdrant API-key + Postgres TLS in the production manifest; scheduled vite/vitest major upgrade to clear dev-tooling CVEs.


7. Remediations Applied This Phase

Config / CI / dependency files (owned by the audit per remediation policy):

  1. pyproject.toml — explicit PyJWT>=2.13.0,<3.0, python-multipart>=0.0.27, starlette>=1.0.1, python-dotenv>=1.2.2 runtime pins; pip-audit>=2.7,<3.0 dev dep.
  2. .github/workflows/ci.yml — Bandit scope broadened to backend ingestion router db; new blocking pip-audit SCA step; detect-secrets scope broadened to include router db; new frontend-security job running npm audit --omit=dev --audit-level=low (blocking).

No production-code logic was modified. The full suite was re-run after the installed-package upgrades (PyJWT 2.13.0, starlette 1.2.1 — a major bump — and python-multipart 0.0.32): 265 passed, 1 skipped, zero regression.


8. Verdict

APPROVED. Every finding is FIXED or a documented, justified ACCEPTED_EXCEPTION (test-only false positives; dev-tooling-only frontend CVEs absent from the production bundle; verification findings with no defect). unresolved_total = 0. The deploy gate "all unresolved findings = 0" is satisfied. See security_verdict.json for the machine-readable result.