Files
jobtrackingapp/docs/verification/sec-007-parser-isolation.md
T
cesnimda 19c5251612 fix(cv): isolate document parsing
Run untrusted document decoders in a secret-free, resource-bounded child process and terminate its process tree on deadline. Harden the production container and enforce parser and lint gates in CI.
2026-08-30 11:12:25 +02:00

2.5 KiB

SEC-007 parser isolation verification

Implemented boundary

  • The FastAPI web process reads at most 5 MiB and performs cheap extension, signature and DOCX-container preflight checks.
  • TXT, Markdown, PDF, DOCX and image decoding runs in parser_child.py, never in the web process.
  • Only one parser child is admitted at a time; excess work receives a stable busy response instead of building an in-memory parser queue.
  • The child receives a minimal environment without AI provider keys or the service token.
  • Linux applies CPU, address-space, output-file, open-file and core-dump limits before importing parser libraries.
  • The parent enforces a 25-second deadline and terminates the process group/tree, including OCR descendants.
  • Per-request work uses an owner-private temporary directory. Old work-* directories are reconciled without following symlinks or removing unrelated paths.
  • The backend has no PDF/DOCX/image fallback. Stable messages replace unexpected internal exceptions and paths.

Container boundary

The production Compose definition resolves the AI service with:

  • non-root Dockerfile user;
  • read-only root filesystem;
  • all Linux capabilities dropped;
  • no-new-privileges;
  • 96 PID, 2 CPU and 2 GiB memory limits;
  • 768 MiB noexec,nosuid,nodev /tmp tmpfs;
  • one writable named volume only for the Hugging Face model cache.

Local proof

  • Parser tests: 37/37 passed.
  • Focused backend extraction/operation tests: 51/51 passed.
  • Full backend: 719/719 passed.
  • Python compilation: app.py and parser_child.py passed.
  • Compose config: valid with all intended controls present.
  • Timeout regression spawns a harmless sleeping descendant and proves the process tree is gone after the deadline.
  • Environment regression proves GEMINI_API_KEY, GROQ_API_KEY and AI_SERVICE_TOKEN are absent from the child.

Remaining external proof

Docker Desktop's Linux daemon is offline, so the image could not be built or run. Before activation:

  1. Build the hash-locked image and record its digest.
  2. Confirm the runtime UID is non-root and the root filesystem rejects writes.
  3. Inspect the applied CPU/memory/PID/capability/tmpfs settings.
  4. Exercise benign TXT, Markdown, PDF, DOCX and image extraction within the configured budgets.
  5. Measure peak parent/child memory and OCR duration; lower or evidence any limit increase.
  6. Run the authenticated browser upload/review journey with synthetic files.
  7. Canary in production only after explicit authorization; disable CV import rather than removing the boundary if the budget is insufficient.