Corrupt and malformed test files for error handling, free and CC0

Most test files are meant to be read successfully. These are not, or not unambiguously. Every file under edge/ is wrong on purpose, or ambiguous on purpose, in one declared way: empty, cut short, malformed, carrying bytes that do not match the name and content type it is served with, or valid as two formats at once so that nothing decides which it is.

Each is served as the type its extension claims, because that is the situation worth testing. edge/png-with-pdf-extension.pdf arrives as application/pdf and is a PNG; edge/pdf-truncated-60pct.pdf reads as a PDF until it stops mid-object. Sniffing the type from the extension, or assuming a parser raises a tidy error, are mistakes these files find.

Each also says what is wrong with it: every row below carries a damage sentence, the valid file to compare_with, and an outcome: must-fail when every conforming reader must refuse it, may-recover when part of it still reads, varies when readers disagree. Only must-fail means a reader that copes is wrong.

The two polyglots are edge/pdf-zip-polyglot.pdf, a PDF and a zip archive, and edge/gif-zip-polyglot.gif, a GIF and a zip. That shape is also how malware travels, so scanners and corporate proxies sometimes refuse a polyglot or strip the archive in transit: if a download arrives short, check sha256sums.txt first.

Use them on upload forms, import pipelines, thumbnailers and archive extractors. edge/zip-directory-traversal-name.zip holds an entry named ../evil.txt and tells you whether yours writes outside the directory it was given. Related: PDF, ZIP.

21 files. The same list as JSON: https://loremfile.dev/edge/index.json

edge-case files
FileSizePropertiesDescription
csv-ragged-rows.csv 65 B invalid-syntax, varies A CSV whose rows carry different field counts: one short, one long.
Damage
The header names 3 fields; of 5 rows, row 3 carries 2 and row 4 carries 4.
Outcome
varies: readers disagree, and neither outcome is guaranteed
Compare with
csv/people-10.csv
Snippets
<a href="https://loremfile.dev/edge/csv-ragged-rows.csv">download</a>
curl -O https://loremfile.dev/edge/csv-ragged-rows.csv
gif-zip-polyglot.gif 200 B polyglot, varies One file that is a valid GIF image and a valid zip archive at once: the archive is everything after the GIF trailer. Scanners and proxies sometimes refuse polyglots outright; see the notes on the page.
Damage
Both grammars match these 200 bytes: it opens with the GIF signature 47 49 46 38 37 61 at byte 0 and carries the ZIP signature 50 4B 03 04 at byte 42, so nothing in the file decides which of the two it is.
Outcome
varies: readers disagree, and neither outcome is guaranteed
Compare with
gif/1x1.gif
Snippets
<a href="https://loremfile.dev/edge/gif-zip-polyglot.gif">download</a>
curl -O https://loremfile.dev/edge/gif-zip-polyglot.gif
jpg-truncated-50pct.jpg 7.5 KB (7,496 bytes) truncated, may-recover The first half of jpg/640x480.jpg: scan data ends with no end-of-image marker.
Damage
Cut to 7,496 of 14,992 bytes, the first 50% of jpg/640x480.jpg: the scan stops mid-row and the FFD9 end-of-image marker never arrives.
Outcome
may-recover: part of it can still be read, and a reader that does is not wrong
Compare with
jpg/640x480.jpg
Cut from
jpg/640x480.jpg
Snippets
<a href="https://loremfile.dev/edge/jpg-truncated-50pct.jpg">download</a>
curl -O https://loremfile.dev/edge/jpg-truncated-50pct.jpg
json-bom.json 80 B bom, varies Valid JSON preceded by a UTF-8 byte-order mark, which RFC 8259 does not allow.
Damage
The first 3 bytes are EF BB BF, a byte-order mark, before an otherwise valid JSON document of 77 bytes.
Outcome
varies: readers disagree, and neither outcome is guaranteed
Compare with
json/all-types.json
Snippets
<a href="https://loremfile.dev/edge/json-bom.json">download</a>
curl -O https://loremfile.dev/edge/json-bom.json
json-trailing-comma.json 64 B invalid-syntax, must-fail JSON with a trailing comma in an array and an object: valid JavaScript, invalid JSON.
Damage
2 commas stand directly before a closing bracket, at bytes 58 and 60; RFC 8259 allows no comma after the last member of an object or array.
Outcome
must-fail: every conforming reader must refuse it
Compare with
json/all-types.json
Snippets
<a href="https://loremfile.dev/edge/json-trailing-comma.json">download</a>
curl -O https://loremfile.dev/edge/json-trailing-comma.json
mp4-truncated-50pct.mp4 987.3 KB (987,287 bytes) truncated, may-recover The first half of mp4/720p-5s.mp4: a partial media stream inside a box that claims more.
Damage
Cut to 987,287 of 1,974,574 bytes, the first 50% of mp4/720p-5s.mp4: it ends inside the 'mdat' box at offset 6,704, which declares 1,967,870 bytes and has 980,583.
Outcome
may-recover: part of it can still be read, and a reader that does is not wrong
Compare with
mp4/720p-5s.mp4
Cut from
mp4/720p-5s.mp4
Snippets
<a href="https://loremfile.dev/edge/mp4-truncated-50pct.mp4">download</a>
curl -O https://loremfile.dev/edge/mp4-truncated-50pct.mp4
pdf-truncated-60pct.pdf 2.6 KB (2,610 bytes) truncated, may-recover The first 60% of pdf/a4-3pages.pdf: the header reads, then the file stops mid-object.
Damage
Cut to 2,610 of 4,351 bytes, the first 60% of pdf/a4-3pages.pdf: the cross-reference table, the trailer and the %%EOF marker are all past the end.
Outcome
may-recover: part of it can still be read, and a reader that does is not wrong
Compare with
pdf/a4-3pages.pdf
Cut from
pdf/a4-3pages.pdf
Snippets
<a href="https://loremfile.dev/edge/pdf-truncated-60pct.pdf">download</a>
curl -O https://loremfile.dev/edge/pdf-truncated-60pct.pdf
pdf-with-png-extension.png 1.8 KB (1,795 bytes) mismatched-extension, varies The bytes of pdf/a4-1page.pdf under a .png name, served as image/png.
Damage
The bytes are pdf/a4-1page.pdf unchanged, starting with the PDF signature 25 50 44 46, while the file name and the Content-Type announce png.
Outcome
varies: readers disagree, and neither outcome is guaranteed
Compare with
png/100x100.png
Cut from
pdf/a4-1page.pdf
Snippets
<a href="https://loremfile.dev/edge/pdf-with-png-extension.png">download</a>
curl -O https://loremfile.dev/edge/pdf-with-png-extension.png
pdf-zip-polyglot.pdf 800 B polyglot, varies One file that is a valid PDF and a valid zip archive at once: a PDF reader shows a page, a zip reader extracts readme.txt. Scanners and proxies sometimes refuse polyglots outright; see the notes on the page.
Damage
Both grammars match these 800 bytes: it opens with the PDF signature 25 50 44 46 2D at byte 0 and carries the ZIP signature 50 4B 03 04 at byte 589, so nothing in the file decides which of the two it is.
Outcome
varies: readers disagree, and neither outcome is guaranteed
Compare with
pdf/minimal.pdf
Snippets
<a href="https://loremfile.dev/edge/pdf-zip-polyglot.pdf">download</a>
curl -O https://loremfile.dev/edge/pdf-zip-polyglot.pdf
png-with-pdf-extension.pdf 1.4 KB (1,387 bytes) mismatched-extension, varies The bytes of png/100x100.png under a .pdf name, served as application/pdf.
Damage
The bytes are png/100x100.png unchanged, starting with the PNG signature 89 50 4E 47, while the file name and the Content-Type announce pdf.
Outcome
varies: readers disagree, and neither outcome is guaranteed
Compare with
pdf/minimal.pdf
Cut from
png/100x100.png
Snippets
<a href="https://loremfile.dev/edge/png-with-pdf-extension.pdf">download</a>
curl -O https://loremfile.dev/edge/png-with-pdf-extension.pdf
utf8-invalid-bytes.txt 143 B invalid-encoding, may-recover Text served as UTF-8 that contains byte sequences UTF-8 does not allow.
Damage
2 byte sequences are not UTF-8: C3 at offset 121 (the start of a 2-byte sequence, and the byte after it cannot continue it) and A0 at offset 136 (a continuation byte with nothing before it).
Outcome
may-recover: part of it can still be read, and a reader that does is not wrong
Compare with
txt/utf8-multilingual.txt
Snippets
<a href="https://loremfile.dev/edge/utf8-invalid-bytes.txt">download</a>
curl -O https://loremfile.dev/edge/utf8-invalid-bytes.txt
xml-unclosed-tag.xml 122 B invalid-syntax, must-fail XML with an element that is never closed, so it is not well-formed.
Damage
2 <item> elements are opened and 1 closed, the last opening at byte 78; XML 1.0 requires every element to be closed.
Outcome
must-fail: every conforming reader must refuse it
Compare with
xml/people-10.xml
Snippets
<a href="https://loremfile.dev/edge/xml-unclosed-tag.xml">download</a>
curl -O https://loremfile.dev/edge/xml-unclosed-tag.xml
zero-byte.csv 0 B zero-byte, must-fail An empty file served as text/csv, with no header row.
Damage
The file holds no bytes at all: no header row and no record, and RFC 4180 requires at least one.
Outcome
must-fail: every conforming reader must refuse it
Compare with
csv/people-10.csv
Snippets
<a href="https://loremfile.dev/edge/zero-byte.csv">download</a>
curl -O https://loremfile.dev/edge/zero-byte.csv
zero-byte.json 0 B zero-byte, must-fail An empty file served as application/json, where a parser expects at least a value.
Damage
The file holds no bytes at all: no JSON value, and RFC 8259 requires one.
Outcome
must-fail: every conforming reader must refuse it
Compare with
json/all-types.json
Snippets
<a href="https://loremfile.dev/edge/zero-byte.json">download</a>
curl -O https://loremfile.dev/edge/zero-byte.json
zero-byte.mp4 0 B zero-byte, must-fail An empty file served as video/mp4.
Damage
The file holds no bytes at all: no ftyp box, so nothing declares what the container is.
Outcome
must-fail: every conforming reader must refuse it
Compare with
mp4/720p-5s.mp4
Snippets
<a href="https://loremfile.dev/edge/zero-byte.mp4">download</a>
curl -O https://loremfile.dev/edge/zero-byte.mp4
zero-byte.pdf 0 B zero-byte, must-fail An empty file served as application/pdf.
Damage
The file holds no bytes at all: no %PDF- header, and nothing after it to read.
Outcome
must-fail: every conforming reader must refuse it
Compare with
pdf/minimal.pdf
Snippets
<a href="https://loremfile.dev/edge/zero-byte.pdf">download</a>
curl -O https://loremfile.dev/edge/zero-byte.pdf
zero-byte.png 0 B zero-byte, must-fail An empty file served as image/png.
Damage
The file holds no bytes at all: no eight-byte PNG signature, so nothing identifies it as an image.
Outcome
must-fail: every conforming reader must refuse it
Compare with
png/100x100.png
Snippets
<a href="https://loremfile.dev/edge/zero-byte.png">download</a>
curl -O https://loremfile.dev/edge/zero-byte.png
zero-byte.txt 0 B zero-byte, varies An empty file served as text/plain.
Damage
The file holds no bytes at all: no text to read.
Outcome
varies: readers disagree, and neither outcome is guaranteed
Compare with
txt/lorem-1kb.txt
Snippets
<a href="https://loremfile.dev/edge/zero-byte.txt">download</a>
curl -O https://loremfile.dev/edge/zero-byte.txt
zero-byte.zip 0 B zero-byte, must-fail An empty file served as application/zip, with not even an end-of-central-directory record.
Damage
The file holds no bytes at all: no local file header and no end-of-central-directory record.
Outcome
must-fail: every conforming reader must refuse it
Compare with
zip/3-text-files.zip
Snippets
<a href="https://loremfile.dev/edge/zero-byte.zip">download</a>
curl -O https://loremfile.dev/edge/zero-byte.zip
zip-directory-traversal-name.zip 782 B hostile-name, varies A readable zip holding an entry named ../evil.txt. An extractor that joins entry names to a destination without sanitising them writes outside that directory.
Damage
The archive itself is well formed and reads; entry 2 of 2 is named '../evil.txt', which climbs out of the directory it is extracted into.
Outcome
varies: readers disagree, and neither outcome is guaranteed
Compare with
zip/3-text-files.zip
Snippets
<a href="https://loremfile.dev/edge/zip-directory-traversal-name.zip">download</a>
curl -O https://loremfile.dev/edge/zip-directory-traversal-name.zip
zip-truncated-50pct.zip 911 B truncated, may-recover The first half of zip/3-text-files.zip: local headers survive, the central directory does not.
Damage
Cut to 911 of 1,822 bytes, the first 50% of zip/3-text-files.zip: 2 local file headers survive, and the central directory that lists them is past the end.
Outcome
may-recover: part of it can still be read, and a reader that does is not wrong
Compare with
zip/3-text-files.zip
Cut from
zip/3-text-files.zip
Snippets
<a href="https://loremfile.dev/edge/zip-truncated-50pct.zip">download</a>
curl -O https://loremfile.dev/edge/zip-truncated-50pct.zip

Every edge-case file in one command, each checked against its hash: npx loremfile get --format edge, or loremfile get --format edge after pip install loremfile.

File names follow the naming grammar. Verify a download against sha256sums.txt.