Skip to content

zentinelproxy/zentinel-agent-content-scanner

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Content Scanner Agent

A Zentinel agent that scans uploaded files for malware using ClamAV daemon.

Features

  • ClamAV Integration: Connects to clamd via Unix socket using INSTREAM protocol
  • Content-Type Filtering: Only scan specific content types (or all)
  • Path Exclusions: Skip scanning for health checks and other paths
  • Method Filtering: Configure which HTTP methods to scan (POST, PUT, PATCH)
  • Size Limits: Skip scanning for bodies exceeding configured size
  • Fail-Open/Closed: Configurable behavior when ClamAV is unavailable
  • Scan Metrics: Headers include scan time and detection status

Installation

Using Bundle (Recommended)

# Install just this agent
zentinel bundle install content-scanner

# Or install all bundled agents
zentinel bundle install

The bundle command downloads the correct binary for your platform and places it in the standard location. See the bundle documentation for details.

Using Cargo

cargo install zentinel-agent-content-scanner

From Source

git clone https://github.com/zentinelproxy/zentinel-agent-content-scanner
cd zentinel-agent-content-scanner
cargo build --release

Configuration

Create a config.yaml file:

# Content Scanner Agent Configuration

settings:
  enabled: true
  fail_action: allow           # allow or block when ClamAV unavailable
  log_detections: true
  log_clean: false

# Body handling
body:
  max_size: 52428800           # 50MB max body to scan
  content_types:               # Only scan these content types (empty = all)
    - "application/octet-stream"
    - "application/zip"
    - "application/x-zip-compressed"
    - "application/gzip"
    - "application/x-gzip"
    - "application/x-tar"
    - "application/pdf"
    - "application/msword"
    - "application/vnd.openxmlformats-officedocument.*"
    - "multipart/form-data"

# ClamAV daemon configuration
clamd:
  enabled: true
  socket_path: "/var/run/clamav/clamd.ctl"
  timeout_ms: 30000            # 30 second scan timeout
  chunk_size: 65536            # 64KB chunks to clamd

# Paths to skip scanning
skip_paths:
  - "/health"
  - "/ready"
  - "/metrics"

# Methods to scan (empty = POST, PUT, PATCH)
scan_methods:
  - "POST"
  - "PUT"
  - "PATCH"

Usage

# Run with default config
./zentinel-content-scanner-agent -c config.yaml

# Run with custom socket path
./zentinel-content-scanner-agent -c config.yaml -s /tmp/content-scanner.sock

# Print example configuration
./zentinel-content-scanner-agent --example-config

# Validate configuration
./zentinel-content-scanner-agent -c config.yaml --validate

ClamAV Setup

The agent requires ClamAV daemon (clamd) to be running and accessible via Unix socket.

macOS (Homebrew)

brew install clamav
# Initialize database
freshclam
# Start daemon
clamd

Linux (Ubuntu/Debian)

sudo apt-get install clamav-daemon
sudo systemctl start clamav-daemon

Linux (RHEL/CentOS)

sudo yum install clamav-server clamav-update
sudo freshclam
sudo systemctl start clamd@scan

Response Headers

Header Description
x-content-scanned Set to "true" when body was scanned
x-scan-time-ms Scan duration in milliseconds
x-malware-detected Set to "true" when malware found
x-malware-name Virus/malware signature name
x-scan-skipped Reason scan was skipped (size-exceeded, content-type-excluded, clamd-unavailable)

Content-Type Matching

The agent supports flexible content-type matching:

  • Exact match: application/json
  • Wildcard subtype: application/* matches any application type
  • Glob suffix: application/vnd.* matches application/vnd.ms-excel

Testing

Test with EICAR standard antivirus test string:

# Clean file (should return 200)
echo "Hello World" | curl -X POST -H "Content-Type: application/octet-stream" -d @- http://localhost:8080/upload

# EICAR test file (should return 403)
echo 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' \
  | curl -X POST -H "Content-Type: application/octet-stream" -d @- http://localhost:8080/upload

Environment Variables

Configuration values can use environment variables with ${VAR_NAME} syntax:

clamd:
  socket_path: "${CLAMD_SOCKET_PATH}"

License

MIT

Packages

 
 
 

Contributors