The Detection Gap
Two years of research. 98% of antivirus engines failed the same test. Format destruction defeated the rest. This is the full story.
Detection assumes structure is truthful. That a compression method field means what it says. That a file with headers is what those headers describe. That structure equals identity.
That assumption is false.
Two techniques, two years of research. Zombie ZIP exploits ambiguity inside a file format. Veriduct eliminates file format entirely. Different mechanics. Same principle underneath: detection depends on structure, and structure is optional.
Detection depends on structure. Structure is optional.
Contents
Zombie ZIP: Ambiguity Inside the Format
ZIP files have a compression method field. Set it to 0, the file is stored uncompressed. Set it to 8, the file is DEFLATE compressed.
What happens when you lie? Claim the file is uncompressed, but actually compress it?
Antivirus engines read the header, expect raw bytes, scan compressed noise, find nothing. The payload is right there, DEFLATE compressed, but the scanner never decompresses it because the header says it's already raw. The file is malformed. The payload is invisible to 98% of engines tested. Any loader that ignores the declared method and attempts DEFLATE recovers the payload correctly.
I call these Zombie ZIPs. Technically dead. Functionally alive.
Twenty Years of Parser Differentials
This class of attack isn't new. In 2004, CERT/CC published VU#968818: "Anti-virus software may not properly scan malformed zip archives." Ange Albertini's Corkami research established the theoretical foundation: a file has no intrinsic meaning. Its truth depends on the parser.
What's notable is not that this technique exists. It's that twenty years later, 98% of antivirus engines still fail to handle it.
This is not a new vulnerability class. It's evidence that a known vulnerability class remains systematically unpatched.
The Parser Differential
The same malformed ZIP produces opposite outcomes depending on who reads it:
ZOMBIE ZIP FILE
Method: 0 (STORED)
Data: DEFLATE compressed
CRC: Matches uncompressed payload
ANTIVIRUS ENGINE 7-ZIP
1. Read Method = 0 1. Read Method = 0
2. Read data as raw bytes 2. Read data as raw bytes
3. Scan compressed noise 3. Write to file
4. No signature match 4. CRC check -> FAILS
5. Report "CRC Failed"
Result: CLEAN Result: CORRUPT FILE
Malware invisible 68 bytes of DEFLATE noise
A purpose-built loader ignores the method field,
decompresses as DEFLATE, and recovers the payload.
Both tools read the stream as-is, bypassing decompression entirely, because the header says STORED. The AV scans the noise and says clean. 7-Zip writes the noise to a file and reports a CRC error. Neither one attempts DEFLATE. The payload is invisible to both.
The Relevant Fields
The compression method field appears in both the local header and central directory. Method 0 means STORED (no compression). Method 8 means DEFLATE. When an AV engine scans a ZIP, it reads this field, applies the corresponding decompression, and scans the result.
Local File Header (30 bytes + filename):
Offset 0: 0x04034b50 (signature)
Offset 8: compression method (2 bytes)
Offset 18: compressed size
Offset 22: uncompressed size
If method = 0: data follows as raw bytes
If method = 8: data follows as DEFLATE stream
When method = 0 (STORED), compressed size must equal uncompressed size. No compression means no size change. When we set method = 0 but those sizes differ, that's already a red flag. Most engines ignore it.
The Technique
Create a ZIP file where the compression method field says 0 (STORED), the actual data is DEFLATE compressed, the CRC-32 is set to the uncompressed payload's checksum, and the sizes reflect the compressed data length.
Header says: method = 0 (STORED, no compression)
Data is: DEFLATE compressed stream
CRC-32: Checksum of UNCOMPRESSED payload (deliberate mismatch)
AV Engine:
-> Reads method 0
-> Expects raw bytes
-> Scans compressed noise
-> No signature match
-> "Clean"
7-Zip:
-> Reads method 0
-> Reads bytes as-is
-> CRC check fails
-> Dumps raw compressed bytes to file
-> File appears valid (correct name, expected size)
-> Content is compressed garbage, not the payload
-> User sees a file, thinks extraction worked
The CRC mismatch is intentional. Setting the CRC to the uncompressed payload's checksum ensures it won't match the compressed bytes on disk. 7-Zip detects the failure and dumps the raw bytes. The extracted file looks right but contains noise. A purpose-built loader that knows the real compression method decompresses it correctly.
Results
Tested with the EICAR test string to isolate static archive scanning behavior. 68 bytes. Every antivirus engine on earth should detect it. The baseline establishes expected detection. The method mismatch isolates the parser trust failure.
| File | Technique | VT Detection | 7-Zip | WinRAR |
|---|---|---|---|---|
| baseline.zip | Correct ZIP | 56/65 | Extracts | Extracts |
| method_mismatch.zip | Method 0 + DEFLATE + Orig CRC | 1/63 | Extracts (corrupt) | Rejects |
| wrong_crc.zip | Invalid CRC-32 only | 44/63 | Extracts | Rejects |
| zlib_wrapped.zip | zlib header in DEFLATE | 1/63 | Rejects | Rejects |
The baseline: 56 of 65 engines detected EICAR in a valid ZIP. The method mismatch variant: 1 of 63. 98% evasion from changing a few bytes in the header.
Other Zombie Variants
The other variants demonstrate the scope of parser trust failure, not delivery viability. Method mismatch is the strongest primitive. The rest show the attack surface is wider than one field.
zlib Wrapper Injection. ZIP requires raw DEFLATE (RFC 1951). Use zlib-wrapped DEFLATE (RFC 1950) and you get a 2-byte header (78 DA) before the compressed data. Most AV engines strictly follow the spec and fail to decompress. Detection drops from 56/65 to 1/63. But 7-Zip also rejects this variant. Effective for evading scanning, doesn't deliver the payload.
CRC Corruption. Set the CRC-32 to 0xDEADBEEF. Some engines bail on CRC mismatch before scanning. Detection drops from 56/65 to 44/63. 7-Zip extracts with a CRC warning. Partial evasion.
Local/Central Directory Mismatch. The local header and central directory both contain the filename. Make them disagree. Local header says eicar.com, central directory says readme.txt. Some tools use one, some use the other. Detection: 51/64. Marginal evasion, but it demonstrates the principle.
Proof of Concept
This is not an exploit. It is a minimal demonstration of how little needs to change to invalidate scanning assumptions.
import struct
import zlib
def make_zombie_zip(payload, filename):
# Compress with DEFLATE
compressor = zlib.compressobj(9, zlib.DEFLATED, -zlib.MAX_WBITS)
compressed = compressor.compress(payload) + compressor.flush()
# Build header with the "lie"
# Method: 0 (STORED) - but data is actually DEFLATE
# CRC: Of UNCOMPRESSED payload - creates mismatch with compressed bytes
local_header = struct.pack('<IHHHHHIIIHH',
0x04034b50, # Signature
20, # Version
0, # Flags
0, # Method: STORED (the lie)
0, 0, # Time/Date
zlib.crc32(payload) & 0xffffffff, # CRC of UNCOMPRESSED data
len(compressed), # Compressed size
len(payload), # Uncompressed size
len(filename), # Filename length
0 # Extra field length
)
# ... build central directory and EOCD ...
# Full code on GitHub
186-byte ZIP file. The critical elements: compression method 0x00 instead of 0x08, and CRC-32 computed from the original uncompressed payload. The full generator, including central directory and EOCD construction, is available on GitHub.
Why This Works
Security tools are strict. They follow the spec. Method says STORED? Read raw bytes. CRC doesn't match? Abort or skip. This makes sense for stability.
But "strict" means "trusting." The scanner reads the method field and acts on it without verifying the actual data. It scans compressed noise as if it were the payload. The real payload, sitting right there in DEFLATE format, never gets decompressed, never gets scanned.
7-Zip is also strict about the method field. It reads Method 0, dumps raw bytes, notices the CRC failure, and produces a corrupt file. It doesn't recover the payload either. But 7-Zip isn't a security tool. Its job is extraction, not detection.
The vulnerability is in the scanner. Known-malicious content sits inside a container, and the scanner can't see it because it trusts a two-byte field in the header. A purpose-built dropper or loader that knows the real compression method decompresses correctly and gets the payload. The scanner never had a chance.
The scanner trusts the header. The header lies. The payload sits in the gap between what the header declares and what the data actually is.
Impact
The core finding: the same EICAR payload that triggers 56/65 detections in a valid ZIP triggers 1/63 in a method mismatch ZIP. The decompressed content is byte-identical. The scanner just never sees it.
Standard archive tools don't recover the payload either. 7-Zip extracts a file with the right name but the content is compressed garbage. WinRAR rejects the file. Windows Explorer fails with an error. No off-the-shelf tool hands the user the real payload.
But that's not how staged malware delivery works. A purpose-built loader or dropper that knows the real compression method decompresses the data correctly. The loader itself can be a minimal script, small enough to deliver via macro, LNK file, or other initial access vector. The attack chain: malware packed into a Zombie ZIP, delivered via file sharing, cloud storage, USB, or download link. Endpoint AV scans the archive, sees noise, reports it clean. A loader on the target reads the actual DEFLATE data, decompresses it, and executes. The AV never saw the payload. This is consistent with how campaigns like SHADOW#REACTOR already operate: custom loaders handling the reconstruction, not user-facing archive tools.
Email gateways may block ZIP attachments containing executables regardless of format. But files shared via Google Drive, Dropbox, Discord, Slack, USB drives, or direct downloads don't face the same restrictions. The AV evasion matters at the endpoint.
Affected: Across multiple VirusTotal scans, only 1 engine (Kingsoft) consistently detected the malformed archive. Every major vendor failed: Avast, AVG, Bitdefender, ClamAV, ESET, Kaspersky, Malwarebytes, McAfee, Microsoft Defender, Sophos, TrendMicro, and others. Detection rates varied from 1/51 to 1/63 depending on scan timing, but the result was consistent: 98% evasion.
EICAR is a test string. Real malware works the same way. The evasion is at the format parsing layer, not the signature layer. If the scanner can't decompress the file, it can't scan the contents. Payload doesn't matter.
Veriduct: Eliminating Format Entirely
Zombie ZIP exploits ambiguity inside a format. The format still exists. The parser just reads it wrong.
Zombie ZIP proves scanners trust structure. Veriduct asks the next question: what happens when structure disappears entirely? Same failure mode, taken to its logical extreme.
What if there's no format at all?
Signature detection needs something to parse. Headers, magic bytes, section tables, import directories. Pattern matching requires patterns.
So I removed them.
Veriduct fragments files into chunks. The payload's headers, magic bytes, section tables, import directories are annihilated. The chunks go into a SQLite database, which is itself a benign file format. AV sees a database. The chunks aren't malware. The keymap isn't malware. Only the combination is dangerous, and that combination does not exist as a static artifact.
How It Works
Take any file. Malware, documents, executables. Veriduct reads it as raw bytes and splits it into chunks. Each chunk gets a salted hash for identification. The chunks go into a SQLite database in randomized order. The original file structure is annihilated. No magic bytes. No file headers. No section tables. Nothing for a scanner to parse.
A compressed keymap stores reconstruction instructions: chunk order, original filename, integrity hashes. Without the keymap, the chunks are meaningless. With it, the file reassembles byte-perfect.
Original: cobalt_strike_beacon.bin
-> VirusTotal: 53/68 detections
Annihilate: chunks in SQLite database
-> VirusTotal: 0/62 detections
-> VirusTotal identifies file as: "SQLite database"
Reassemble: cobalt_strike_beacon.bin (verification only)
-> VirusTotal: 53/68 detections
-> SHA256: identical to original
Zero detections in the middle. Full detection on both ends. Same file. The hash proves it.
Test Results
Tested with known malware samples, not just EICAR. Every sample that triggers signatures in its original form triggers zero detections once annihilated:
| Sample | Original | Annihilated | Reassembled |
|---|---|---|---|
| EICAR | 65/68 | 0/62 | 65/68 |
| Cobalt Strike beacon | 53/68 | 0/62 | 53/68 |
| Emotet | 31/72 | 0/62 | 31/72 |
| ValleyRAT | 52/72 | 0/62 | 52/72 |
Cobalt Strike, Emotet, ValleyRAT. Production malware that every vendor has signatures for. Every signature became worthless the moment the format disappeared. (Denominator varies between columns because VirusTotal's engine count fluctuates between scans. The result is consistent: zero detections on annihilated samples.)
The "Reassembled" column exists for verification. I wrote the file back to disk to confirm byte-perfect reconstruction and hash matching. In operational use, the file reassembles only in memory and executes without touching disk.
No format, no parsing. No parsing, no detection.
Beyond Fragmentation
The current version, Veriduct Prime, goes further than fragmentation. It doesn't just destroy files. It executes them without ever writing the original back to disk.
Semantic Shatter Mapping. Before chunking, null bytes get injected at random positions throughout the data. The positions are stored in the keymap. On reassembly, the nulls are removed. The chunks themselves don't contain contiguous sequences from the original file. Even with every chunk, you can't reconstruct the payload without the shatter map.
XOR Entanglement. Chunks get XOR'd together in groups. To recover any chunk in a group, you need all the others. No single chunk carries recoverable data.
Substrate Poisoning. Fake chunks get inserted into the database at a configurable ratio. They look identical to real chunks. Without the keymap, you can't tell which are real and which are noise.
Native Execution. This is the part that matters operationally. Veriduct Prime includes a dependency-free PE and ELF loader implemented in Python using ctypes for native memory management. It implements a full user-mode execution path: reassemble the binary in memory, parse headers, resolve imports by walking the Process Environment Block (no hooked API calls), apply relocations, handle TLS callbacks, SEH, CRT initialization, security cookies, and transfer execution to the entry point. The file never exists on disk. There is nothing to scan at the file layer.
I implemented a minimal networked agent to validate execution viability. The agent binary gets annihilated into chunks. On the target, Veriduct reassembles and executes it from memory. HTTP beaconing, command execution, file transfer. All functional. The binary that AV would detect at 53/68 runs without triggering a single alert because the binary never exists as a file.
The file doesn't evade detection. The file doesn't exist. You can't scan what was never written.
How Veriduct Got Here
Veriduct didn't start as an offensive tool. It started as a backup system.
Late 2024. I was building a file snapshot tool. Anti-ransomware. The idea: chunk files by content hash, store the chunks separately, and if ransomware encrypts your files, reconstruct them from the chunk store. Incremental backups based on content deduplication.
The early prototype was about 150 lines of Python. Dictionary-based tokenization. Encode files into chunks, decode them back. Basic data protection.
The next version added proper file system scanning. Walk a directory tree, hash each file, store changed chunks incrementally, generate a manifest with integrity verification. It had a tkinter GUI. It was a tool for protecting data.
Then I noticed something.
The chunk store had no file format information in it. The chunks were just raw bytes. If you pointed a scanner at the chunk store, it wouldn't find anything. The malware signatures were gone. Not hidden. Not encrypted. Just structurally absent.
That was the moment. The realization that file format is not intrinsic to data. It's imposed by structure. Remove the structure, the identity disappears. Put it back, the identity returns. The data doesn't change. Only the interpretation changes.
I rebuilt around that insight.
| Version | Capabilities | What Changed |
|---|---|---|
| file_snapshot_poc | Text tokenization, dictionary encode/decode | The seed. Data transformation as a concept. |
| dyw_enhanced | Directory scanning, chunk storage, incremental snapshots, GUI | Anti-ransomware backup tool. Content-addressed storage. |
| Veriduct (initial) | SQLite chunk DB, encryption, Zstandard compression, disguised keymaps | First offensive pivot. Chunks moved to encrypted SQLite. Keymap disguised as CSV/log/conf. |
| Veriduct | Salted hashing, HMAC integrity, variable chunking, batch ops | Production hardening. Annihilate/reassemble CLI. First VT validation: 143 -> 0 -> 143. |
| Veriduct Combined | SSM, XOR entanglement, substrate poisoning, native PE/ELF loader | The jump. Semantic shatter mapping, chunk entanglement, native execution from memory. |
| Veriduct File/Run | Streaming execution, VeriductExecutionCore | Streaming chunk-by-chunk execution. Files run as they reassemble. |
| Veriduct Prime | StealthResolver (PEB walking), CRT init, TLS, SEH, delay-load imports, C2, blob builder | Full native loader. Resolves imports via PEB instead of API calls. Working C2 agent. Self-executing blob format. |
A backup tool to a format destruction framework with native binary execution from memory.
The key transitions:
Snapshot to format destruction. Recognizing that the chunk store had no format signatures wasn't a side effect to fix. It was a property to exploit.
File reconstruction to in-memory execution. Writing the reassembled file to disk means AV catches it. So don't write it. Reassemble in memory and execute directly. This required building a PE loader from scratch: parse headers, map sections, resolve imports, apply relocations, set proper page permissions, jump to entry point.
Standard imports to PEB walking. The earliest native loader called LoadLibrary and GetProcAddress. Those calls get monitored by EDR. Veriduct Prime walks the Process Environment Block to find loaded modules and export tables without making any hooked API calls. The StealthResolver reads the PEB, walks the LDR module list, parses export directories, and resolves function addresses directly from memory structures.
Each version proved a progressively more uncomfortable fact. Format destruction defeats static scanning. In-memory execution defeats file-based scanning. PEB-based resolution defeats API monitoring. The detection surface kept shrinking.
Already In the Wild
This is not theoretical. These techniques are being used in active campaigns.
SHADOW#REACTOR (January 2026). Securonix documented a campaign using text-based payload fragmentation with in-memory reassembly. The infection chain retrieves fragmented payloads from remote hosts, stores them as plain text files, and reconstructs them into executable loaders. The fragments "appear as harmless text data to automated security systems." The payload was Remcos RAT.
Gootloader. Uses malformed ZIP concatenation to confuse parsers. Multiple ZIP archives appended together, exploiting the fact that different tools read the central directory from different positions. Parser confusion for payload delivery.
SHADOW#REACTOR is a degraded version of format destruction. Same principle: fragment payloads so they don't look like payloads, reassemble at runtime, execute from memory. They used text files and PowerShell. Veriduct uses content-addressed chunk databases and native PE loading. The concept is identical. The implementation quality differs.
Attackers figured this out independently. They didn't need my research. The principle emerges naturally once you stop assuming files must look like files. The question was never whether threat actors would discover this. It was whether the industry would prepare for it.
They didn't.
The Path Here
I tried to do this the right way. For over a year.
Late 2024. Built the first prototype. By February 2025 I had the core detection pattern validated: 143 detections on VirusTotal for a test sample, destroy the format, 0 detections, reassemble, 143 detections again. Same SHA256 hash both times.
I spent 12 months attempting responsible disclosure to 51+ security firms. The responses ranged from silence to rejection.
April 2025. Trail of Bits took a meeting. I presented. Sent the whitepaper afterward. Then nothing. No response to follow-ups.
April through June 2025. I emailed individual researchers. Phil Zimmermann. Micah Lee. Haroon Meer. Daniel Miessler. Patrick McKenzie. Thomas Ptacek. None replied. I don't interpret silence as malice. Only as lack of ownership.
December 5, 2025. Presented at DEF CON DC862. Afterward I contacted vendors directly. Microsoft MSRC. Palo Alto Networks. Rapid7. Others. No meaningful engagement.
December 20, 2025. Open-sourced Veriduct on GitHub.
January 12, 2026. Securonix published SHADOW#REACTOR. Text-based payload fragmentation. In-memory reassembly. The same technique, in the wild, being used against real targets. While the industry was ignoring the research, attackers were building their own version of it.
The vulnerability class behind Zombie ZIP was documented in 2004. VU#968818. Twenty years. Format destruction was demonstrated and disclosed directly to vendors for over a year. The research got rejected, ignored, or met with silence at every step.
The tools are open source. The research is public. The evidence speaks for itself.
What This Means
Two failures. Two remediation paths.
Zombie ZIP Is Fixable
Vendors can fix this. When the declared compression method produces data that doesn't match the CRC, try other methods. Don't trust a two-byte field as the final word on what the data is. Attempt DEFLATE on anything that looks like high-entropy noise. Flag method/size mismatches as suspicious. This is not hard.
The fact that it hasn't been fixed in 20 years, since VU#968818 was published in 2004, is a choice.
Format Destruction Is Not Fixable by Static Scanning
There is no signature for "no format." You cannot write a YARA rule for "this file used to be malware before its structure was removed." The chunks in the SQLite database are not malicious. The keymap is not malicious. The malware only exists in the combination, and the combination only exists at runtime, in memory.
This is not a bug in a product. It's an architectural limitation of the detection model. Static file scanning assumes malicious files look like malicious files. Format destruction breaks that assumption.
Defending against this requires different approaches:
Behavioral analysis. Watch what processes do, not what files look like. A Python script reading a SQLite database and then allocating executable memory is suspicious regardless of what the database contains.
Memory scanning. Scan process memory at runtime. The payload has to exist in memory to execute. That's the one place it can't hide.
Delivery controls. Restrict what enters the environment. Allowlisting. Application control. If the stager can't reach the endpoint, the technique doesn't matter.
Process monitoring. Track parent-child process relationships. If python.exe spawns a process that beacons to an external IP, flag it. The execution behavior is the signal, not the file format.
Static scanning alone will not catch this. It can't. The model is broken for this class of attack.
Questions for Your Vendors
What happens when a file declares one format but contains another? What happens when there's no format at all? How much of your detection is signature matching versus behavioral analysis? If an attacker fragments a known malware sample into a SQLite database, will your product detect it? If that database is reassembled and executed from memory without writing to disk, will your product detect it?
If the answer to the last two is "no," you have a detection gap.
Scope and Precision
I want to be precise about what was tested.
Zombie ZIP was tested against VirusTotal engines using the EICAR test string. Across multiple scans, detection on the malformed archive ranged from 1/51 to 1/63 — consistent 98% evasion. This measures static archive scanning capability: can the engine identify known-malicious content inside a malformed container? Standard archive tools (7-Zip, WinRAR, Windows Explorer) do not recover the payload from the malformed ZIP. The attack vector requires a purpose-built loader that handles the compression method correctly, which is consistent with staged malware delivery in practice.
Veriduct was tested against VirusTotal static scanning (0 detections on chunks across all samples) and local Microsoft Defender with real-time protection enabled (chunks undetected). The C2 agent was validated through local execution testing. The focus was on proving that format destruction eliminates static detection and that in-memory execution bypasses file-based scanning. I have not tested against every EDR product in a live enterprise deployment.
The claim is specific: static file scanning fails against both techniques. Behavioral detection may catch execution depending on the product and its configuration.
That specificity is deliberate. The gap is in the static scanning model, which is the primary detection layer most organizations depend on.
The Principle
Both attacks exploit the same assumption: that format fields mean what they say. That structure is truth. That if a file looks like something, it is that thing.
Zombie ZIP lies about the compression method. The scanner believes the lie and scans noise. The payload sits right there, compressed, invisible.
Veriduct removes structure entirely. The scanner has nothing to believe. The runtime reconstructs what it needs from parts that individually mean nothing.
When you internalize this, you stop asking "what does the header say?" and start asking "what will each parser actually do with these bytes?" Format confusion isn't a bug in any single tool. It's an emergent property of a world where many tools must agree on what bytes mean, and they don't.
Format destruction goes further. It asks: what if there are no bytes to agree on? What if the thing you're looking for doesn't exist in any recognizable form until the moment it runs?
The interpreter defines meaning. The file is just a container. Containers are optional.
Links
Veriduct Prime: github.com/Bombadil-Systems/veriduct-prime
Zombie ZIP: github.com/reapermunky/Zombie-Zip
VU#968818 (2004): kb.cert.org
Corkami: github.com/corkami/docs