DEV Community

Cover image for Getting started with antivirus scanning in Node.js (5 minutes)
Tommaso Bertocchi
Tommaso Bertocchi

Posted on • Originally published at pompelmi.app

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 — Homebrew

brew install clamav
Enter fullscreen mode Exit fullscreen mode

Linux — Debian / Ubuntu

sudo apt-get update && sudo apt-get install -y clamav
Enter fullscreen mode Exit fullscreen mode

Linux — RHEL / Fedora / CentOS

sudo dnf install -y clamav clamav-update
Enter fullscreen mode Exit fullscreen mode

Windows — Chocolatey

choco install clamav -y
Enter fullscreen mode Exit fullscreen mode

Verify the installation worked:

clamscan --version
# ClamAV 1.x.x/...
Enter fullscreen mode Exit fullscreen mode

Now download the virus database. ClamAV ships without definitions — you need to fetch them before any scan can work:

macOS and Windows

freshclam
Enter fullscreen mode Exit fullscreen mode

Linux

sudo freshclam
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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);
});
Enter fullscreen mode Exit fullscreen mode

Run it against any file:

node scan.js /etc/hosts
# Scanning: /etc/hosts
# Result: Clean — no threats found.
Enter fullscreen mode Exit fullscreen mode

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!
Enter fullscreen mode Exit fullscreen mode

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.


Originally published at pompelmi.app

Top comments (0)