Skip to content

Security Nodes

Protect against malware and threats with virus scanning.

PluginPackageOperationsRequirements
virusScanPlugin@uploadista/flow-security-clamscanVirus scanning, malware detectionClamAV 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,
}),
],
});
OptionTypeDefaultDescription
preference"clamdscan" | "clamscan""clamdscan"Scanning method
clamdscan_socketstringsystem defaultDaemon socket path (Unix)
clamdscan_hoststring-TCP host (alternative to socket)
clamdscan_portnumber3310TCP port
remove_infectedbooleanfalseRemove infected files (not recommended in flows)
debug_modebooleanfalseEnable debug logging
ModeLatency
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,
});
ParameterTypeRequiredDefaultDescription
action"fail" | "pass"No"fail"Action when virus detected
timeoutnumber (1000-300000)No60000Max scan time in milliseconds
OptionTypeDefaultDescription
keepOutputbooleanfalseKeep output in flow results
ActionDescription
failStop flow execution when virus detected (recommended for production)
passContinue 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 CodeDescription
VIRUS_DETECTEDMalware found in file (when action=fail)
CLAMAV_NOT_INSTALLEDClamAV not available on system
VIRUS_SCAN_FAILEDGeneric scanning operation failure
SCAN_TIMEOUTScanning 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