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 — Homebrew
brew install clamav
Linux — Debian / Ubuntu
sudo apt-get update && sudo apt-get install -y clamav
Linux — RHEL / Fedora / CentOS
sudo dnf install -y clamav clamav-update
Windows — 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 Windows
freshclam
Linux
sudo freshclam
The first freshclam download takes a few minutes — the database is several hundred megabytes. Subsequent runs are incremental and fast.
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() {
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!
If you see "Result: Malicious" on the EICAR file, your setup is working correctly. If you see "Clean", run 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
- Scanning file uploads with pompelmi in Express.js
- How to use pompelmi in a NestJS application
- Running pompelmi with ClamAV in Docker Compose
Originally published at pompelmi.app
Top comments (0)