Follow-up from #6 (PR #16). Not already fixed — read the detail before closing.
The archive inspector verifies each inspected part two ways: a declared-size check and a CRC-32 check. The size check alone is tautological for deflate entries, which is what every real .docx and any hostile input uses.
fflate inflates a deflate entry with a pre-sized buffer (new u8(su)) and returns buf.subarray(0, bt) where bt <= su, so comparing the inflated length against the declared size can never fail in the understating direction — the direction the hole lives in. A stored entry is sliced by the compressed size instead, so the mismatch is visible there and invisible for deflate.
Concretely, with an understated size in the central directory and a w:ins past the truncation point:
- level 0 (stored) → rejected on the size check
- level 9 (deflate) → previously ACCEPTED,
unmappable: [], all tracked-change counts zero
That is a clean bill of health for a document containing a tracked insertion — the exact under-reporting the report exists to prevent, since the README treats an empty unmappable as "safe to write back".
PR #16 closes this by verifying CRC-32 per part, with tests at both compression levels. This issue exists because the first attempt at the fix shipped a green test that only exercised the stored path, so the hole survived with a passing test claiming otherwise.
Tasks
Note for future work: fflate 0.8.3 does not export crc() — it is internal, used only when writing archives, and UnzipFileInfo carries no checksum. The CRC-32 is implemented inline with its own central-directory walk.
Follow-up from #6 (PR #16). Not already fixed — read the detail before closing.
The archive inspector verifies each inspected part two ways: a declared-size check and a CRC-32 check. The size check alone is tautological for deflate entries, which is what every real
.docxand any hostile input uses.fflateinflates a deflate entry with a pre-sized buffer (new u8(su)) and returnsbuf.subarray(0, bt)wherebt <= su, so comparing the inflated length against the declared size can never fail in the understating direction — the direction the hole lives in. A stored entry is sliced by the compressed size instead, so the mismatch is visible there and invisible for deflate.Concretely, with an understated size in the central directory and a
w:inspast the truncation point:unmappable: [], all tracked-change counts zeroThat is a clean bill of health for a document containing a tracked insertion — the exact under-reporting the report exists to prevent, since the README treats an empty
unmappableas "safe to write back".PR #16 closes this by verifying CRC-32 per part, with tests at both compression levels. This issue exists because the first attempt at the fix shipped a green test that only exercised the stored path, so the hole survived with a passing test claiming otherwise.
Tasks
Note for future work:
fflate0.8.3 does not exportcrc()— it is internal, used only when writing archives, andUnzipFileInfocarries no checksum. The CRC-32 is implemented inline with its own central-directory walk.