How to Scan File Uploads for Viruses on Heroku
If your Heroku app accepts file uploads, those files aren't scanned for malware. Heroku handles routing, scaling, and deployment — but a user can upload a malicious file and it'll be stored and served like any other attachment.
The AttachmentScanner addon adds malware scanning with a single command. Files are checked against multiple antivirus engines and you get back a clear result: clean, malicious, or suspicious.
This guide covers provisioning the addon, scanning files from your application code, and setting up async scanning for production workloads. For the full picture on scanning strategies, see the complete guide to scanning user uploads.
Provision the Addon
heroku addons:create attachment-scanner
Heroku sets two config vars automatically:
ATTACHMENT_SCANNER_URL— your scanner's base URLATTACHMENT_SCANNER_API_TOKEN— your API token
Pull them into your local .env for development:
heroku config:get ATTACHMENT_SCANNER_URL -s >> .env
heroku config:get ATTACHMENT_SCANNER_API_TOKEN -s >> .env
The addon works on all Heroku plans. You can open the dashboard to view scan history and manage settings:
heroku addons:open attachment-scanner
Your First Scan
Test the connection with the EICAR test file — a standardised test file that every antivirus engine detects:
curl -H "Authorization: Bearer $ATTACHMENT_SCANNER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.attachmentscanner.com/eicar.com"}' \
-XPOST $ATTACHMENT_SCANNER_URL/v1.0/scans
{
"status": "found",
"filename": "eicar.com",
"matches": ["Eicar-Test-Signature"]
}
That's it — the addon is working. Now let's integrate it into your app.
Scanning from Your App
The examples below use Node.js and Ruby, but AttachmentScanner works with any language. See the documentation for examples in Python, Go, and more.
Node.js
const response = await fetch(
`${process.env.ATTACHMENT_SCANNER_URL}/v1.0/scans`,
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ATTACHMENT_SCANNER_API_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ url: fileUrl }),
}
);
const result = await response.json();
if (result.status === "found") {
// Reject the upload
}
To scan a file upload directly, send it as multipart/form-data:
const formData = new FormData();
formData.append("file", fileBuffer, filename);
const response = await fetch(
`${process.env.ATTACHMENT_SCANNER_URL}/v1.0/scans`,
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ATTACHMENT_SCANNER_API_TOKEN}`,
},
body: formData,
}
);
Ruby
conn = Faraday.new(ENV['ATTACHMENT_SCANNER_URL']) do |f|
f.request :json
f.response :json
f.authorization :Bearer, ENV['ATTACHMENT_SCANNER_API_TOKEN']
end
response = conn.post('/v1.0/scans', {
url: 'https://www.attachmentscanner.com/eicar.com'
})
puts response.body['status'] # => "found"
If you're using CarrierWave, there's a gem that scans uploads automatically:
gem 'carrierwave-attachmentscanner'
class DocumentUploader < CarrierWave::Uploader::Base
include CarrierWave::AttachmentScanner
end
Every file uploaded through this uploader is scanned before it's stored.
Going Async: The Recommended Approach
The examples above are synchronous — your server blocks while the scan runs. This works for simple cases, but for production we recommend async scanning with callbacks. Your upload handler returns immediately, and AttachmentScanner POSTs the result to your callback URL when the scan finishes.
// Upload handler — returns immediately
await fetch(`${process.env.ATTACHMENT_SCANNER_URL}/v1.0/scans`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ATTACHMENT_SCANNER_API_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: presignedUrlFor(stagedPath),
async: true,
callback: "https://your-app.herokuapp.com/webhooks/scan-complete",
}),
});
return res.status(202).json({ status: "processing" });
The uploads guide covers the full async pattern including
callback handling, staging areas, and the warning status.
Getting Started
- Provision the addon:
heroku addons:create attachment-scanner - Test with EICAR to confirm scanning works
- Set up async scanning with callbacks for production
- Open the dashboard with
heroku addons:open attachment-scannerto view scan history
If you need help with your integration, get in touch — we're always happy to help.
AttachmentScanner Team
Other Articles
Scanning User Uploads for Malware
AttachmentScanner Team
Scan DigitalOcean Spaces for Malware
AttachmentScanner Team
Scan AWS S3 Files for Malware
AttachmentScanner Team