Picarones / SECURITY.md
Claude
sprint24: durcissement sécurité institutionnelle
d86e268 unverified
|
Raw
History Blame
5.36 kB

SECURITY — Picarones

Picarones est conçu pour être déployé dans trois contextes très différents :

  1. Poste développeur (Codespaces, laptop) — accès local uniquement, le garde-fou est ouvert pour fluidifier l'itération.
  2. Serveur d'institution (intranet patrimonial, cluster scientifique) — accès authentifié interne, mais quelques utilisateurs peuvent lancer des benchmarks coûteux ; le serveur doit borner la consommation.
  3. Espace public (HuggingFace Space, démo en ligne) — n'importe quel visiteur peut atteindre l'API ; les clefs serveur (OpenAI, Anthropic, Mistral, Azure…) ne doivent pas être exposées au DoS-financier.

Ce document décrit les contrôles disponibles depuis le Sprint 24 et la configuration recommandée pour chaque cas.


Variables d'environnement de sécurité

Variable Défaut Effet
PICARONES_PUBLIC_MODE non défini Si 1/true : refuse OCR cloud + LLM mutualisés et active rate limit.
PICARONES_BROWSE_ROOTS (auto) Liste de chemins (séparateur : Unix / ; Windows) autorisés pour /api/corpus/browse. Surcharge le défaut.
PICARONES_MAX_UPLOAD_MB 100 Taille max d'une image uploadée.
PICARONES_MAX_CONCURRENT_JOBS 2 Plafond global de benchmarks simultanés (sémaphore en mémoire).
PICARONES_RATE_LIMIT_PER_HOUR 5 (en mode public) Jobs max par IP et par heure. 0 = désactivé.
PICARONES_CSP (politique durcie) Surcharge la Content-Security-Policy envoyée par le middleware.

Contrôles par contexte

🧑‍💻 Développement (défaut, PICARONES_PUBLIC_MODE non défini)

picarones serve --port 8000
  • Tous les moteurs OCR sont disponibles.
  • /api/corpus/browse voit cwd, ./uploads/, /workspaces, tempdir.
  • Pas de rate limit.
  • CSP appliquée mais permissive (unsafe-inline toléré tant que les templates web ne sont pas Jinja2 — voir Sprint 25).

🏛 Serveur d'institution

export PICARONES_BROWSE_ROOTS="/srv/corpus:/srv/uploads"
export PICARONES_MAX_CONCURRENT_JOBS=4
export PICARONES_MAX_UPLOAD_MB=500
picarones serve --host 0.0.0.0 --port 8000

À combiner avec une terminaison TLS et une authentification au niveau reverse-proxy (nginx + auth basic, ou Keycloak/SAML). Picarones n'embarque pas son propre système d'authentification — c'est un choix conscient pour ne pas réinventer un sous-système qui sera mieux servi par l'infra existante.

🌐 HuggingFace Space / démo publique

ENV PICARONES_PUBLIC_MODE=1
ENV PICARONES_RATE_LIMIT_PER_HOUR=5
ENV PICARONES_MAX_CONCURRENT_JOBS=2
ENV PICARONES_MAX_UPLOAD_MB=50
# Optionnel : surcharger les browse roots
# ENV PICARONES_BROWSE_ROOTS=/data/corpus

Effets en mode public :

  • ❌ Moteurs OCR cloud (mistral_ocr, google_vision, azure_doc_intel) refusés en 403.
  • ❌ Pipelines OCR+LLM (openai, anthropic, mistral, ollama) refusés en 403.
  • /api/corpus/browse se limite à ./uploads/.
  • /api/benchmark/start et /api/benchmark/run rate-limités en 429.
  • 🔒 Content-Security-Policy + X-Frame-Options: DENY + X-Content-Type-Options: nosniff + Referrer-Policy: strict-origin-when-cross-origin sur toutes les réponses.

Contrôles d'upload

Images

  • Validation Pillow systématique : Image.open(...).verify() dans un try/except qui capture les UnidentifiedImageError, DecompressionBombError, et l'exception générique.
  • Limite de taille par fichier (PICARONES_MAX_UPLOAD_MB).
  • Basename forcé : un nom de fichier multipart contenant .. ou / est tronqué à son nom de base avant écriture.

Archives ZIP

  • Bombe ZIP : taille décompressée bornée à 500 Mo, nombre de fichiers borné à 2000.
  • Path traversal : seuls les noms de base sont conservés (les répertoires internes du ZIP sont aplatis).
  • Filtres macOS : les fichiers ._* (AppleDouble) sont ignorés.
  • Symlinks : Python's zipfile n'extrait pas les symlinks par défaut ; un check explicite (ZipInfo.external_attr & 0xA000) est sur la roadmap comme défense en profondeur.

Modèle de menace

Menace Mitigation
Visiteur consomme la clef API mainteneur PICARONES_PUBLIC_MODE=1 → 403 sur LLM/OCR cloud.
DoS via 50 benchmarks concurrents PICARONES_MAX_CONCURRENT_JOBS (sémaphore) + rate limit par IP.
Bombe Pillow (CVE-2023-50447 & cie) Image.verify() levant DecompressionBombError.
Path traversal sur browse / image / delete Validation explicite + résolution + check is_relative_to.
Exfiltration via browse /etc ou /root PICARONES_BROWSE_ROOTS restreint, défaut public limité à uploads.
XSS via paramètres URL CSP default-src 'self', frame-ancestors 'none'.
Clickjacking X-Frame-Options: DENY.

Reporting de vulnérabilités

Les vulnérabilités potentielles peuvent être ouvertes via une Security Advisory GitHub (privée par défaut) sur github.com/maribakulj/Picarones.

Merci de ne pas divulguer publiquement avant qu'un correctif ne soit disponible. Les contributeurs prendront en charge la triage en moins de 14 jours.