Skip to content

Scanning

exav prints clamscan’s output format. The flags are exav’s own, and there is a fourth exit code. This guide covers everyday scanning; see the CLI reference for every flag.

Terminal window
exav file.bin # scan one file
exav /var/www # scan a directory, recursively
exav --no-recursive /var/www # just the directory's own files
exav --quiet /data # only print detections, partial results and errors
exav --files-from list.txt # paths from a file, one per line
cat file.zip | exav - # scan stdin
exav --allow-http-scan https://host/obj.zip # over HTTP range requests (an `http-scan` build)
exav -d ./mydb /data # use a signature database (file or dir)

Examples without -d load --sig-dir: /var/lib/exav by default, or EXAV_SIG_DIR as set in the quick start. See Signatures.

Stdin, and a FIFO given as a path, is held before it is scanned (in RAM, then in a temporary file past 16 MiB), then gets the same scan as a file. See buffering a stream for the bounds.

The server must answer range requests. An object up to --max-object-bytes is read once, in full; a larger one is read in ranges as the scan needs them, some parts more than once (see the block cache).

To pay in disk instead of transfer (metered egress, a slow link, per-request billing), download the object and scan the file:

Terminal window
curl -fsSO https://host/obj.zip && exav obj.zip

-f matters: without it an error page is saved and scanned as OK.

The human-readable output is one line per file, followed by a clamscan-style summary:

Terminal window
/path/to/file: Win.Trojan.Agent-1234 FOUND
/path/to/clean: OK
/path/to/missing: No such file or directory (os error 2) ERROR
/path/to/huge.bin: file size 9663676416 exceeds max-input-bytes 4294967296; scanned first 4294967296 bytes only LIMITS-EXCEEDED PARTIAL
/path/to/secret.zip: encrypted ZIP member PASSWORD-PROTECTED PARTIAL

A file that could not be fully examined ends with the reason, then the category of the condition, then the status PARTIAL. (The huge.bin line comes from a run with --max-input-bytes 4G; by default there is no input size limit.)

--quiet suppresses the OK lines and the summary, never an error; -v adds detail.

--json emits newline-delimited JSON: one object per scanned input, then a summary object (left out under --quiet). Keys come out in alphabetical order, and findings (the detected type, and more with --detect exav-heuristics) is on every result that has any, with or without -v:

Terminal window
$ exav --json /data
{"file":"/data/file","method":"pattern","offset":1234,"signature":"Win.Trojan.Agent-1234","status":"FOUND"}
{"file":"/data/clean.txt","findings":[{"detail":"ASCII text","label":"type"}],"status":"OK"}
{"category":"LIMITS-EXCEEDED","file":"/data/huge.bin","findings":[{"detail":"ASCII text","label":"type"}],"reason":"file size 9663676416 exceeds max-input-bytes 4294967296; scanned first 4294967296 bytes only","status":"PARTIAL"}
{"summary":{"data_scanned_bytes":4294972634,"elapsed_secs":0.042,"errors":0,"infected":1,"partial":1,"scanned":3}}

status is on every result object and is the word the human line ends with. category only appears on a PARTIAL, so filter on status:

Terminal window
exav --json /data | jq 'select(.status=="PARTIAL" or .partial)' # not fully examined
exav --json /data | jq 'select(.status and .status != "OK")' # everything not clean

.partial covers --all-matches, where a result lists its detections in signatures and carries "partial":true and partial_reasons when the search stopped short.

-v / --verbose prints informational findings alongside the verdict: the detected file type, and with --detect exav-heuristics also the imphash, section entropy and the static score.

By default exav stops at the first matching signature per file. --all-matches reports every match (clamscan’s --allmatch):

Terminal window
exav --all-matches /data

Include and exclude by path regex, repeatable, with clamscan’s semantics:

Terminal window
exav /data --exclude '\.log$' --exclude-dir 'node_modules' --include '\.exe$'

--exclude-dir matches a directory’s own path, which has no trailing separator: node_modules skips the directory, while /node_modules/ only skips what is nested below it and lets files directly inside through. To anchor it, write /node_modules($|/).

0 OK, 1 FOUND, 2 ERROR (exav could not do its job), 3 PARTIAL (a file could not be fully examined). 3 is kept apart from 2 so that “the scanner broke” and “this file needs a decision” are different signals; --partial-as maps it to another status. See which code a run exits with.

An encrypted member is reported PASSWORD-PROTECTED. Supply passwords to decrypt it and scan inside:

Terminal window
exav --passwords secret --passwords hunter2 /data # tried in order
exav --passwords-from /etc/exav/passwords /data # kept out of `ps`

Passwords also load from a ClamAV .pwdb database in the signature directory, and a few common ones are tried without being asked. See Encryption and passwords for the formats exav decrypts and the passwords it tries by default.

An encrypted ZIP appended to a picture or a document (a polyglot that archive tools open by its trailing directory) is reported the same way once its structure is confirmed.

A small set of low-false-positive heuristics runs by default, the ones ClamAV itself reports: imphash matching, the PDF obfuscated-name check, overlapping ZIP records and the XZ dictionary-size check. --detect exav-heuristics adds exav’s own (TLSH fuzzy matching, a hand-weighted static scorer, and a packed-with-injection-imports check), which carry more false-positive risk and are opt-in:

Terminal window
exav --detect exav-heuristics -v sample.exe

--detect takes all, none, or a comma-separated list of exav-heuristics, macros, broken, broken-media, partition-intersection, phishing, packed, pua.