Truncatie-check ontbreekt op content/URL-import-pad (openDeckFromContent) #1350

Closed
opened 2026-08-07 22:08:30 +00:00 by brenno · 0 comments
Owner

Bevinding

FileService.openDeckDetailed (het schijf-pad) weigert een bestand met
complete frontmatter maar lege slide-body als OpenFailure.corrupt via
_looksTruncated — een afgebroken bestand opent dus niet stil als een
bijna-leeg deck.

FileService.openDeckFromContent (gebruikt voor web-URL-import en in-memory
open) loopt door dezelfde fail-closed poort (safety scan → marp-sniff → parse),
maar niet door de truncatie-check. Een afgebroken download — frontmatter
wel, body niet — opent hier stil als een deck met één placeholder-slide in
plaats van corrupt te signaleren.

De gebruiker ziet een bijna-leeg deck en denkt dat de bron leeg was, in plaats
van dat de transfer stuk liep. Dat is een stille data-verlies-ervaring op een
pad dat verder bewust fail-closed is.

Locatie

  • lib/services/file_service.dart: openDeckDetailed met _looksTruncated
    (regels ~639-645), openDeckFromContent (regels ~903-931).
  • De scheidslijn is de content == null-guard in _looksTruncated: de check
    draait nu alleen voor het schijf-pad.

Oplossingsrichting

De truncatie-check heffen naar een gedeelde helper of dupliceren in
openDeckFromContent, zodat beide open-paden dezelfde weigering geven. De
conditie content == null in de huidige check is precies wat dit gat maakt —
die guard is er nu alleen voor het schijf-pad, terwijl de semantiek
("complete header, geen body = afgeknapt") ook geldt voor content die uit een
netwerkdownload kwam.

Klein diff: de check factoren of dupliceren in openDeckFromContent, met een
falende test die een truncated deck via openDeckFromContent aanbiedt en
OpenFailure.corrupt verwacht.

Herkomst

Gevonden tijdens security research naar de robustness van OciDeck bij het
openen van corrupte bestanden en resource-uitputting (decompressie-bommen,
decode-bommen, zip-slip, truncatie). De overige paden — zip-slip
(safeOutPath), decompressie-bommen (_CappedOutputStream), decode-bommen
(kMaxImageDecodeDimension), sidecar-isolatie, UTF-8/parse-fail-closed —
bleken volwassen. Dit was de enige echte asymmetrie tussen twee open-paden
die dezelfde poort zouden moeten delen.

## Bevinding `FileService.openDeckDetailed` (het schijf-pad) weigert een bestand met complete frontmatter maar lege slide-body als `OpenFailure.corrupt` via `_looksTruncated` — een afgebroken bestand opent dus niet stil als een bijna-leeg deck. `FileService.openDeckFromContent` (gebruikt voor web-URL-import en in-memory open) loopt door dezelfde fail-closed poort (safety scan → marp-sniff → parse), maar **niet** door de truncatie-check. Een afgebroken download — frontmatter wel, body niet — opent hier stil als een deck met één placeholder-slide in plaats van `corrupt` te signaleren. De gebruiker ziet een bijna-leeg deck en denkt dat de bron leeg was, in plaats van dat de transfer stuk liep. Dat is een stille data-verlies-ervaring op een pad dat verder bewust fail-closed is. ## Locatie - `lib/services/file_service.dart`: `openDeckDetailed` met `_looksTruncated` (regels ~639-645), `openDeckFromContent` (regels ~903-931). - De scheidslijn is de `content == null`-guard in `_looksTruncated`: de check draait nu alleen voor het schijf-pad. ## Oplossingsrichting De truncatie-check heffen naar een gedeelde helper of dupliceren in `openDeckFromContent`, zodat beide open-paden dezelfde weigering geven. De conditie `content == null` in de huidige check is precies wat dit gat maakt — die guard is er nu alleen voor het schijf-pad, terwijl de semantiek ("complete header, geen body = afgeknapt") ook geldt voor content die uit een netwerkdownload kwam. Klein diff: de check factoren of dupliceren in `openDeckFromContent`, met een falende test die een truncated deck via `openDeckFromContent` aanbiedt en `OpenFailure.corrupt` verwacht. ## Herkomst Gevonden tijdens security research naar de robustness van OciDeck bij het openen van corrupte bestanden en resource-uitputting (decompressie-bommen, decode-bommen, zip-slip, truncatie). De overige paden — zip-slip (`safeOutPath`), decompressie-bommen (`_CappedOutputStream`), decode-bommen (`kMaxImageDecodeDimension`), sidecar-isolatie, UTF-8/parse-fail-closed — bleken volwassen. Dit was de enige echte asymmetrie tussen twee open-paden die dezelfde poort zouden moeten delen.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
LibreKAT/Ocideck#1350
No description provided.