Skip to main content

File security pipeline: security model

This page describes the security guarantees of the pipeline that scans every file before Docling, OCR, media storage, transcription and RAG: quarantine, ClamAV, YARA-X, verdicts, blocking, locked rules, roles and evidence. Engine installation, settings and signature updates are in the File security guide. Code: services/control-plane/src/eai/domains/file_security, migration sql/postgres/V199, screen portal/src/screens/file-security.tsx.

Version française : ../file-security-pipeline.md

Mandatory chain​

upload -> quarantine -> clamav -> yara_x -> validation -> docling -> rag
  1. Quarantine. The quarantined record is committed in its own transaction before any analysis: a crash leaves the file quarantined, never released.
  2. Builtin checks. Type detected from the content (eai.domains.file_security.checks), allowed types, archives (depth 3 at most, 10,000 members at most), Office macros, mismatch between declared and real type.
  3. ClamAV then YARA-X. Each engine is called over HTTPS (EAI_CLAMAV_URLS, EAI_YARAX_URLS, Bearer keys, CA EAI_FILE_SCAN_CA_FILE) through the egress guard. Several endpoints are tried in turn; a failed endpoint goes last for EAI_FILE_SCAN_ENDPOINT_DOWN_SECONDS.
  4. Decision. The most severe verdict wins; only clean releases the file (released), any other blocking verdict blocks it (blocked).
  5. Scan clearance. Only a released scan mints a ScanClearance sealed with a process secret and bound to the exact digest of the bytes. Docling, OCR, store_media, the media adapters and transcription call clearance.require before reading the bytes: an unscanned file cannot reach them, even through a code mistake.

No transaction is open during a scan (a scan inside an open db.tx raises NestedScan). Not files, so outside the pipeline: realtime PCM16 audio frames, POST /v1/encryption/encrypt (bytes encrypted and returned, never parsed) and connector tests.

Verdicts​

VerdictMeaningStatus
malwareClamAV signature or YARA-X malware ruleblocked (always)
suspiciousSuspicious YARA-X rule or builtin checkblocked when the rule blocks
unscannableEncrypted file, limits exceeded, broken archive, size above the ceilingblocked (always)
policy_violationType not allowed, archive refused, macro, type mismatchblocked
scan_errorEvery endpoint of an engine failedblocked (fail closed)
cleanNo blocking findingreleased

Precedence (PRECEDENCE): malware, suspicious, unscannable, policy_violation, scan_error. A YARA-X rule with action = "report" is logged without blocking.

Locked rules and tenant policy​

The locked rules are constants of the code (LOCKED in eai.domains.file_security.policy), never stored nor writable: scan before any ingestion, both engines (clamav, yara_x) required, fail closed, malware and uninspectable files blocked. An attempt to change them answers 422 file_security_rule_locked.

A tenant can only tighten the other settings (GET /v1/file-security/policy, PUT /v1/file-security/policy):

SettingDefault
max_file_bytesEAI_FILE_SCAN_MAX_BYTES (never above)
allowed_typesevery known type except executable
allow_archivestrue
block_office_macrostrue
block_type_mismatchtrue
retain_samplestrue
quarantine_retention_days30
max_signature_age_hours48
stale_signatureswarn (block refuses every scan while the signatures are too old)

Enforcement mode​

  • EAI_FILE_SCAN_MODE=enforce: both engines required; none reachable gives 503 (fail closed). Mandatory in production: the startup guard refuses another mode, an engine URL outside https:// and a missing Bearer key.
  • dev (refused in production): an unconfigured engine is noted not_configured; a configured engine applies exactly as in enforce.

Blocked files​

  • The sample of a blocked file is kept encrypted (tenant key file-security-quarantine, eaienc1 envelope) when retain_samples is true; a released file never leaves a sample.
  • POST /v1/file-security/scans/{scan_id}/rescan scans the retained sample again in a new record (rescan_of); it never releases the original upload (409 file_sample_unavailable without a sample).
  • DELETE /v1/file-security/scans/{scan_id}/sample deletes the sample at once (audited). The file_scan_samples_purge worker job deletes samples past quarantine_retention_days.

Roles​

OperationRouteRoles
Engine statusGET /v1/file-security/statustenant_admin, security_officer, auditor
Read the policyGET /v1/file-security/policytenant_admin, security_officer, auditor
Update the policyPUT /v1/file-security/policysecurity_officer, tenant_admin
Scan without ingestingPOST /v1/file-security/scansany tenant member
List, read scansGET /v1/file-security/scans, GET /v1/file-security/scans/{scan_id}readers: all; others: their own scans
Rescan, purge the samplePOST /v1/file-security/scans/{scan_id}/rescan, DELETE /v1/file-security/scans/{scan_id}/samplesecurity_officer, tenant_admin
StatisticsGET /v1/file-security/statsreaders: all; others: their own scans

Evidence and detection​

  • Every scan is audited (file_security.scan) with the source (knowledge, media, multimodal, transcription, connector, channel, api), the digest, the verdict and the reasons.
  • A blocked file raises the security event security.file.blocked (or security.file.scan_unavailable when the engines did not answer); the SOC audit scanner turns it into a detection for the malware and suspicious verdicts (soc-runbook.md).
  • The file_scan_probe job (EAI_WORKER_FILE_SCAN_PROBE_SECONDS) measures engine status and signature age.

Components​

ComponentManifestPinned versionLicence
ClamAV (clamd, freshclam, HTTPS gateway)catalog/components/clamav.yaml1.4.6GPL-2.0-only
YARA-X (rule worker)catalog/components/yara-x.yaml1.22.1BSD-3-Clause

Both are installed by the Navin Manager; see the File security guide.