Skip to content

Security Nodes

Protect against malware and threats with virus scanning.

Plugin Package Operations Requirements
virusScanPlugin @uploadista/flow-security-clamscan Virus scanning, malware detection ClamAV installed on system
npm install @uploadista/flow-security-nodes @uploadista/flow-security-clamscan
import { createUploadistaServer } from "@uploadista/server";
import { virusScanPlugin } from "@uploadista/flow-security-clamscan";
const uploadista = await createUploadistaServer({
// ...
plugins: [
virusScanPlugin(),
],
});

ClamAV must be installed on your system. It can run in two modes:

  1. clamd daemon (recommended): Faster, persistent scanning service
  2. clamscan binary: Slower but works without daemon
Terminal window
sudo apt-get update
sudo apt-get install clamav clamav-daemon
sudo freshclam # Update virus definitions
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
import { createUploadistaServer } from "@uploadista/server";
import { virusScanPlugin } from "@uploadista/flow-security-clamscan";
// Default configuration (daemon preferred, fallback to binary)
const uploadista = await createUploadistaServer({
plugins: [virusScanPlugin()],
});
// Custom daemon configuration
const uploadistaCustom = await createUploadistaServer({
plugins: [
virusScanPlugin({
preference: "clamdscan",
clamdscan_socket: "/var/run/clamav/clamd.sock",
clamdscan_port: 3310,
debug_mode: false,
}),
],
});
// TCP connection instead of socket
const uploadistaTcp = await createUploadistaServer({
plugins: [
virusScanPlugin({
preference: "clamdscan",
clamdscan_host: "localhost",
clamdscan_port: 3310,
}),
],
});
Option Type Default Description
preference "clamdscan" | "clamscan" "clamdscan" Scanning method
clamdscan_socket string system default Daemon socket path (Unix)
clamdscan_host string - TCP host (alternative to socket)
clamdscan_port number 3310 TCP port
remove_infected boolean false Remove infected files (not recommended in flows)
debug_mode boolean false Enable debug logging
Mode Latency
Daemon (clamdscan) ~100-500ms for small files (<1MB)
Binary (clamscan) ~1-3s per scan (slower, requires process startup)

Scan files for viruses and malware using ClamAV.

Package: @uploadista/flow-security-nodes

import { createScanVirusNode } from "@uploadista/flow-security-nodes";
// Fail flow if virus detected (recommended for production)
const scanNode = yield* createScanVirusNode("scan-1", {
action: "fail",
timeout: 60000,
});
// Continue with metadata (useful for logging/auditing)
const auditNode = yield* createScanVirusNode("scan-2", {
action: "pass",
timeout: 120000,
});
// With keepOutput option
const keepOutputNode = yield* createScanVirusNode("scan-3", {
action: "fail",
}, {
keepOutput: true,
});
Parameter Type Required Default Description
action "fail" | "pass" No "fail" Action when virus detected
timeout number (1000-300000) No 60000 Max scan time in milliseconds
Option Type Default Description
keepOutput boolean false Keep output in flow results
Action Description
fail Stop flow execution when virus detected (recommended for production)
pass Continue processing with detection metadata (useful for logging/auditing)

All scan results are stored in file.metadata.virusScan:

type VirusScanMetadata = {
scanned: boolean; // Whether file was scanned
isClean: boolean; // Whether file is clean (no viruses)
detectedViruses: string[]; // Array of detected virus names
scanDate: string; // ISO 8601 timestamp
engineVersion: string; // Antivirus engine version
definitionsDate: string; // Virus definitions date
};
Error Code Description
VIRUS_DETECTED Malware found in file (when action=fail)
CLAMAV_NOT_INSTALLED ClamAV not available on system
VIRUS_SCAN_FAILED Generic scanning operation failure
SCAN_TIMEOUT Scanning exceeded timeout limit

import { createUploadistaServer } from "@uploadista/server";
import { virusScanPlugin } from "@uploadista/flow-security-clamscan";
import { imagePlugin } from "@uploadista/flow-images-sharp";
// Configure server with both plugins
const uploadista = await createUploadistaServer({
dataStore: s3Store({ /* ... */ }),
kvStore: redisKvStore({ /* ... */ }),
plugins: [
virusScanPlugin(),
imagePlugin(),
],
});
// Create a flow that scans before processing
// Flow: Input -> Scan -> Resize -> Store

Input -> Scan Virus -> Conditional (clean?)
|-- YES: Process -> Store
|-- NO: Quarantine / Reject

ClamAV uses virus definition databases that must be kept up-to-date.

Terminal window
# Update manually
sudo freshclam
# Set up automatic updates (cron)
# Add to crontab:
0 */6 * * * /usr/bin/freshclam --quiet

In your Dockerfile, update definitions at build time:

RUN freshclam

For production, set up a cron job or scheduled task to run freshclam regularly.


You can test virus detection using the EICAR test file - a harmless file that all antivirus software detects as malware:

// EICAR test string (safe, not actual malware)
const eicarTest = new TextEncoder().encode(
'X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*'
);
const result = yield* virusScanPlugin.scan(eicarTest);
// result.isClean === false
// result.detectedViruses === ["Eicar-Test-Signature"]

“ClamAV is not installed or not available”

Section titled ““ClamAV is not installed or not available””
  • Verify ClamAV is installed: clamscan --version
  • Check daemon is running: systemctl status clamav-daemon (Linux)
  • Try using binary mode: preference: "clamscan"

“Connection refused” / Daemon not responding

Section titled ““Connection refused” / Daemon not responding”
  • Ensure daemon is running: sudo systemctl start clamav-daemon
  • Check socket path matches your system’s configuration
  • Try TCP connection instead of socket
  • Increase timeout in scan virus node parameters
  • Consider using daemon mode (faster than binary)
  • Check system resources (CPU, memory)
Terminal window
# Check definitions age
freshclam --version
# Update definitions
sudo freshclam