Scan for Malware with Node.js / TypeScript
Use AttachmentScanner to scan files and URLs for viruses and malware using Node's built-in fetch API.
Scan a URL
The simplest way to scan — pass a URL and get back a result:
const response = await fetch(`${ATTACHMENT_SCANNER_URL}/v1.0/scans`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ url: "https://www.attachmentscanner.com/eicar.com" }),
});
const result = await response.json();
console.log(result.status); // "found"
console.log(result.matches); // ["Eicar-Test-File-Signature"]
Scan a File
Upload a file directly from disk:
const fs = require("fs");
const formData = new FormData();
formData.append("file", new Blob([fs.readFileSync("/path/to/file.pdf")]), "file.pdf");
const response = await fetch(`${ATTACHMENT_SCANNER_URL}/v1.0/scans`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_TOKEN}`,
},
body: formData,
});
const result = await response.json();
console.log(result.status); // "ok" if clean, "found" if malware detected
Async Scan with Callback
For large files or non-blocking workflows, use async: true with a callback URL.
The API returns immediately with a pending status and POSTs the result to your callback
when the scan completes:
// 1. Submit the scan
const response = await fetch(`${ATTACHMENT_SCANNER_URL}/v1.0/scans`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://example.com/large-file.zip",
async: true,
callback: "https://your-app.com/webhooks/scan-complete",
}),
});
const { id, status } = await response.json();
console.log(id); // "a1b2c3d4-..."
console.log(status); // "pending"
// 2. Receive the callback (Express example)
app.post("/webhooks/scan-complete", express.json(), (req, res) => {
const { id, status, matches } = req.body;
if (status === "found") {
console.log(`Malware detected in scan ${id}:`, matches);
// quarantine or delete the file
} else if (status === "ok") {
// file is clean — move to final storage
}
res.json({ received: true });
});
You can also poll for results instead of using a callback:
// Poll for results
const result = await fetch(`${ATTACHMENT_SCANNER_URL}/v1.0/scans/${id}`, {
headers: { Authorization: `Bearer ${API_TOKEN}` },
});
const scan = await result.json();
console.log(scan.status); // "ok", "found", "pending", etc.
Express Integration
A full Express app that accepts file uploads and scans them:
const express = require("express");
const multer = require("multer");
const upload = multer({ storage: multer.memoryStorage() });
const app = express();
const { ATTACHMENT_SCANNER_URL, ATTACHMENT_SCANNER_API_TOKEN } = process.env;
// Scan by URL
app.post("/scan/url", express.json(), async (req, res) => {
const response = await fetch(`${ATTACHMENT_SCANNER_URL}/v1.0/scans`, {
method: "POST",
headers: {
Authorization: `Bearer ${ATTACHMENT_SCANNER_API_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ url: req.body.url }),
});
const result = await response.json();
res.json(result);
});
// Scan by file upload
app.post("/scan/file", upload.single("file"), async (req, res) => {
const formData = new FormData();
formData.append("file", new Blob([req.file.buffer]), req.file.originalname);
const response = await fetch(`${ATTACHMENT_SCANNER_URL}/v1.0/scans`, {
method: "POST",
headers: {
Authorization: `Bearer ${ATTACHMENT_SCANNER_API_TOKEN}`,
},
body: formData,
});
const result = await response.json();
res.json(result);
});
// Webhook callback handler
app.post("/webhooks/scan-complete", express.json(), (req, res) => {
const { status, matches } = req.body;
if (status === "found") {
// quarantine or delete the file
}
res.json({ received: true });
});
app.listen(3000, () => console.log("Listening on :3000"));
TypeScript
Type-safe wrapper with full response types:
interface ScanResult {
id: string;
status: "pending" | "ok" | "found" | "failed";
callback: string | null;
url: string | null;
filename: string | null;
content_length: number | null;
md5: string | null;
sha256: string | null;
matches: string[];
created_at: string;
updated_at: string;
}
class AttachmentScanner {
constructor(
private baseUrl: string,
private apiToken: string
) {}
private get headers() {
return { Authorization: `Bearer ${this.apiToken}` };
}
async scanUrl(url: string): Promise<ScanResult> {
const response = await fetch(`${this.baseUrl}/v1.0/scans`, {
method: "POST",
headers: { ...this.headers, "Content-Type": "application/json" },
body: JSON.stringify({ url }),
});
return response.json() as Promise<ScanResult>;
}
async scanFile(file: Blob, filename: string): Promise<ScanResult> {
const formData = new FormData();
formData.append("file", file, filename);
const response = await fetch(`${this.baseUrl}/v1.0/scans`, {
method: "POST",
headers: this.headers,
body: formData,
});
return response.json() as Promise<ScanResult>;
}
async scanAsync(
url: string,
callback: string
): Promise<ScanResult> {
const response = await fetch(`${this.baseUrl}/v1.0/scans`, {
method: "POST",
headers: { ...this.headers, "Content-Type": "application/json" },
body: JSON.stringify({ url, async: true, callback }),
});
return response.json() as Promise<ScanResult>;
}
async getScan(id: string): Promise<ScanResult> {
const response = await fetch(`${this.baseUrl}/v1.0/scans/${id}`, {
headers: this.headers,
});
return response.json() as Promise<ScanResult>;
}
}
// Usage
const scanner = new AttachmentScanner(
process.env.ATTACHMENT_SCANNER_URL!,
process.env.ATTACHMENT_SCANNER_API_TOKEN!
);
const result = await scanner.scanUrl("https://www.attachmentscanner.com/eicar.com");
if (result.status === "found") {
console.log("Malware detected:", result.matches);
}
curl Equivalent
# Scan by URL
curl -X POST https://YOUR_SCANNER_URL/v1.0/scans \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.attachmentscanner.com/eicar.com"}'
# Scan by file upload
curl -X POST https://YOUR_SCANNER_URL/v1.0/scans \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-F "file=@/path/to/file.pdf"
# Async scan with callback
curl -X POST https://YOUR_SCANNER_URL/v1.0/scans \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/file.zip", "async": true, "callback": "https://your-app.com/webhooks/scan-complete"}'