Getting started with antivirus scanning in Node.js (5 minutes)
You've built a Node.js app that accepts file uploads. Great. Now how do you make sure those files don't contain viruses?
The answer is ClamAV — a free, open-source antivirus engine that has been around since 2001, is maintained by Cisco, and is used by thousands of applications worldwide. It runs entirely on your own machine. No subscription, no API key, no files leaving your server.
pompelmi is a tiny Node.js package that calls ClamAV for you and gives back a clean result you can act on in JavaScript. Let's set it up.
Step 1 — Install ClamAV
ClamAV is a system-level tool. Install it with your operating system's package manager, not via npm.
macOS — Homebrewbrew install clamavLinux — Debian / Ubuntu
sudo apt-get update && sudo apt-get install -y clamavLinux — RHEL / Fedora / CentOS
sudo dnf install -y clamav clamav-updateWindows — Chocolatey
choco install clamav -y
Verify the installation worked:
clamscan --version # ClamAV 1.x.x/...
Now download the virus database. ClamAV ships without definitions — you need to fetch them before any scan can work:
macOS and WindowsfreshclamLinux
sudo freshclam
freshclam download takes a few minutes — the database
is several hundred megabytes. Subsequent runs are incremental and fast.
For detailed platform-specific instructions see
How to install ClamAV for Node.js on macOS, Linux and Windows.
Step 2 — Install pompelmi
In your Node.js project directory:
npm install pompelmi
pompelmi has zero runtime dependencies. It uses Node's
built-in child_process module to call clamscan
and nothing else. No transitive packages to audit or update.
Step 3 — Scan your first file
Create a file called scan.js:
const { scan, Verdict } = require('pompelmi');
async function main() {
// Pass any file path you want to scan
const filePath = process.argv[2];
if (!filePath) {
console.error('Usage: node scan.js <file>');
process.exit(1);
}
console.log('Scanning:', filePath);
const verdict = await scan(filePath);
if (verdict === Verdict.Clean) {
console.log('Result: Clean — no threats found.');
} else if (verdict === Verdict.Malicious) {
console.log('Result: Malicious — malware detected!');
process.exit(1);
} else if (verdict === Verdict.ScanError) {
console.log('Result: ScanError — could not complete scan.');
process.exit(2);
}
}
main().catch(err => {
console.error('Error:', err.message);
process.exit(3);
});
Run it against any file:
node scan.js /etc/hosts # Scanning: /etc/hosts # Result: Clean — no threats found.
That's it. Three verdicts, one function, zero configuration.
Step 4 — Test malware detection with EICAR
How do you test that the malicious path actually works without using real malware? The EICAR test file is a harmless string that every antivirus engine is required to detect as "malicious" for exactly this purpose. It was invented in 1991 and contains no actual malicious code.
# Create the EICAR test file echo 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' \ > /tmp/eicar.txt # Scan it node scan.js /tmp/eicar.txt # Scanning: /tmp/eicar.txt # Result: Malicious — malware detected!
freshclam again — the virus database may
not have downloaded properly.
What's next?
You now have a working scanner. The next step is wiring it into your web framework so uploads are scanned automatically.
- How to scan file uploads for viruses in Node.js — explains the full upload-scan-store pattern with a complete Express example.
- Scanning file uploads with pompelmi in Express.js — in-depth guide with reusable middleware, multi-file scanning, and TypeScript.
- How to use pompelmi in a NestJS application — NestJS interceptor pattern with dependency injection and unit tests.
- Running pompelmi with ClamAV in Docker Compose — containerize your scanner with a clamd sidecar for production deployments.