Repository navigation
The scanner, rebuilt around one streaming scan; three new projects (a browser
file viewer, image decoders, a perceptual image hash); and a long run of
fuzzing that fixed more than a hundred bounds and decoding bugs.
Highlights
- One scan for every input, at any size. A file, stdin, a FIFO,
INSTREAM,
ICAP and HTTP all go through the same pipeline. A file over
--max-object-bytes(256 MiB by default) now gets the full scan (wildcard and
logical signatures, PCRE, YARA, bytecode, carving, heuristics), read through
an 8 MiB block cache; it used to get a literal-and-hash pass only. What needs
the whole object in memory (PE structure, Authenticode, packers, YARA'spe,
elfanddotnetmodules, containers read whole) makes such a file
LIMITS-EXCEEDED, unless something is found.--all-matchesand
ALLMATCHSCANlist every detection at any size. - Faster. One index of signature literals replaces the automatons; a
signature with a narrow offset window is checked where it can start; whole-file
digests are computed once and only when a signature can use them; objects read
through the block cache are read far fewer times. A prebuilt database is
smaller and loads faster. - DWG and DXF drawings are scanned (R13 to 2018, ASCII and binary): the
files an OLE2FRAME embeds are extracted and scanned. @exav/viewer, a new npm package: a file viewer for the browser (PDF,
images, DWG and DXF, Word, Excel, PowerPoint, CSV, IFC and STL models, video,
audio, archives), each engine loaded on first use, with a sandboxed mode that
opens each file in its own<iframe sandbox>. Demo at exav.org/viewer/demo/.exav-render, memory-safe decoders for what to draw: TIFF, BMP and other
raster images, JPEG 2000, JBIG2, fax, DWG, DXF, IFC, STL.exav-imagehash,
a crate and a command: perceptual image hashes, with presets equal to
sigtool --fuzzy-imgand Pythonimagehash.phash; the scanner'sfuzzy_img#
now goes through it.- A Helm chart (
deploy/helm/exav-chart) and a Kubernetes guide, by
Bastien Ogier. exav-unpackhasunzip's command line:-l,-t,-p,-d,-x,
-o,-n,-Pand the rest mean what they mean to Info-ZIPunzip6.00,
with its exit statuses. It extracts every format the library reads, restores
times, modes and symlinks, never writes through a link, and reads a split ZIP
(.z01) or a RAR volume set from any part.- Releases carry
exav-unpack,exav-grep,exav-pe-emuandexav-imagehash
besideexav. exav.org is organised by product.
Breaking changes
- Removed:
--max-extracted-bytes(it stops the run with a message naming the
change: a scan holds 1 GiB, 400M under--clamav-compat, and
--max-process-byteslowers it);--build-shard-bytes; exav-core's
scan_stream(usescan_seekable);exav'schecksumsfeature; the
exav-unpack listandextractsubcommands (-l,-d DIR). - Renamed: environment variables without a flag are
EXAV_DEBUG_*
(EXAV_BC_TRACEisEXAV_DEBUG_BC_TRACE, and so on); the systemd unit is
exav.service(it wasexav-clamd.service). - The daemon's signals match clamd's:
SIGUSR2reloads the signatures and
SIGHUPreopens the--logfile.SIGUSR2used to kill the process. - A stream that ends before its terminator is answered
ERRORonINSTREAM
andEXINSTREAM. A signature path that loads nothing is an error. - YARA detections are named
YARA.<rule>outside--clamav-compat. A YARA
pattern keeps at most a million matches, as yara-x does. --max-process-bytesalso lowers--max-object-bytesto a quarter of the
memory a scan gets: a file past it isLIMITS-EXCEEDED, notout of memory.- A scan that fails behind the ICAP listener is a block.
- The published image uses Docker mediatypes, so podman honours its
HEALTHCHECK(by Nastaliss). This drops the buildx provenance attestation.
The 0.0.1 tags are OCI.
Added
--max-pcre-bytes,--min-scan-bytes(default 6) and
--max-pe-emulation-steps;--partial-as password-protected=foundreports
any encrypted member asHeuristics.Encrypted.*, as ClamAV's
--alert-encrypteddoes; theimage-hashandphishingfeatures, on by
default;.msudatabases under--detect pua.- Decoding: encrypted RAR with the caller's passwords (headers encrypted
included), RAR 7 headers, ZIP Shrink, Reduce, Implode and PPMd members, NSIS
with bzip2, ZIP members found by their local header, ZIP64 included. - A guide to sizing a server, with the flags for a 4 GB host; a health check in
the Compose and Kubernetes examples;make miri. - exav-unpack:
Prescananddetect_prescanned, and a modification time on
MemberMetaandEntry.
Changed
- Matching no longer copies an object whole, and PCRE no longer scans a copy of
it. Bytecode follows ClamAV 1.4.3 in four more places, and its triggers are
evaluated with the object's container. - A signature reload lets scans in progress finish. A DMG is walked without
decompressing its whole disk. - A compressed stream damaged part way keeps what was decoded before the damage
and is reported as damaged, not lost or complete.exav-unpack-wasm's
list()decodes nothing it can avoid. - Dependencies:
bincode(RUSTSEC-2025-0141) andserdeare gone from
exav-unpack; the RustCrypto crates move to their current generation
(digest0.11,cipher0.5);ureq3 for thehttpfeatures, which now
follows theHTTP_PROXY,HTTPS_PROXYandNO_PROXYenvironment;
tlsh21.x,ext4-view1.0 andlzma-rust20.21 with their upstream
fixes; the bzip2 decoder is vendored frombzip2-rswith a fix.
Fixed
Found by fuzzing, an arithmetic audit and the ClamAV comparison. The bugs that
could change a verdict:
- A decompression or parsing bomb now stops at a budget. About a hundred
header numbers added or multiplied unchecked are refused: the disk-image
readers (VMDK, QCOW2, VHDX, NTFS, WIM, ext, FAT, partitions), CHM, DWG
polylines and hatches, 7z folders, carving, signature files and databases
pastu32. ARC, ZOO and.Zdecoders no longer allocate without limit. - A damaged or cut-short member is never
OK. Truncated bzip2, Zstandard,
xz, UPX, NSIS, 7z PPMd, DMG and EGG data, a RAR member failing its CRC, and a
member cut off by the end of the file are reported as damaged or
UNSCANNABLE. - PCRE subsignatures match as ClamAV's PCRE2 does: bytes above 0x7F,
offsets, thegflag,\band\Bbeside a high byte, and a repeat that can
match nothing. - RAR: encrypted headers and stored members, the window of each member in
an archive, the x86, Itanium and ARM filters, empty members in a solid group,
a volume set missing a volume, a volume numbered 65,535 or 2^64 - 1. - ZIP: members found only by their local header, with other bytes before
the archive, in ZIP64 form, compressed with an unknown method, with LZMA or
Zstandard and cut short.--all-matcheswith--alert-exceeds-maxdropped
the alert on a decompression bomb and reported a clean scan. - Performance and portability: a YARA
xor(1-255)pattern cost 255
comparisons per position; a scan time limit above 100,000,000 seconds was
refused by macOS and left no limit. - Daemon: the watch of its signature source missed changes, so new
signatures were not loaded; a worker stopped mid-job answers withERROR
instead of closing the connection; scanning a URL took a server that answered
a range request with the whole object (200, not206) as the range, and is
an error now. - Emulator and decoders: a panic on a packed file with a bad import
directory; the x86 decoder sizedUMONITOR's register by the operand size;
a PE whose parse failed over one malformed directory lost the rest. - Documents: PDF encryption (revision 4, 40-bit RC4), encrypted DMG and
workbooks, VBA projects, lenient compound files,Ole10Nativeobjects, GIF
extension blocks, HTML and text signatures, JPEG checks under
--detect broken-media, andfuzzy_img#hashes now computed as ClamAV 1.4.6
does. - An object whose first read failed made the safetensors sniff panic.