Header Image How to Scan File Uploads for Malware on Railway

How to Scan File Uploads for Malware on Railway

If your Railway app accepts file uploads, those files aren't scanned for malware. Railway handles deployment, networking, and scaling — but it won't check whether an uploaded file is safe before your app stores or serves it.

AttachmentScanner adds malware scanning with a single API call. Files are checked against multiple antivirus engines and you get back a clear result: clean, malicious, or suspicious.

This guide covers adding scanning to a Railway service. For the full picture on scanning strategies, see the complete guide to scanning user uploads.

Set Your Service Variables

Sign up for an account to get your API token and scanner URL. Add them as service variables in your Railway dashboard, or via the CLI:

railway variables set ATTACHMENT_SCANNER_URL=https://scans.attachmentscanner.com
railway variables set ATTACHMENT_SCANNER_API_TOKEN=your_token_here

That's all the configuration you need. Your app reads these like any other environment variable.

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 — scanning is working. Now let's integrate it into your app.

Scanning from Your App

The examples below use TypeScript, but AttachmentScanner works with any language. See the documentation for examples in Ruby, Python, Go, and more.

Scan by URL

If your files are in cloud storage, pass a URL and AttachmentScanner fetches the file directly:

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
}

Scan a File Upload Directly

To scan a file from a multipart upload, 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,
  }
);

The examples above are synchronous — your server blocks while the scan runs. For production, use async scanning with callbacks. Your upload handler returns immediately, and AttachmentScanner POSTs the result to your callback URL when the scan finishes.

Your App stage upload async + callback AttachmentScanner multi-engine scan callback ok → move to uploads found → quarantine

// 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.up.railway.app/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.

Works Everywhere

AttachmentScanner is cloud-agnostic — the same API works whether you're on Railway, Heroku, Fly.io, Vercel, or your own infrastructure. If you move between platforms, the integration stays the same.

Getting Started

  1. Sign up and grab your API token
  2. Set ATTACHMENT_SCANNER_URL and ATTACHMENT_SCANNER_API_TOKEN as Railway service variables
  3. Test with EICAR to confirm scanning works
  4. Set up async scanning with callbacks for production

If you need help with your integration, get in touch — we're always happy to help.

2026-04-02
Profile Image: AttachmentScanner Team AttachmentScanner Team

Other Articles