Scan for Malware with Go
Use AttachmentScanner to scan files and URLs for viruses and malware using Go's standard library net/http — no external dependencies required. These snippets use map[string]interface{} for brevity — see the Typed section for a ScanResult struct.
Scan a URL
The simplest way to scan — pass a URL and get back a result:
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
scannerURL := os.Getenv("ATTACHMENT_SCANNER_URL")
apiToken := os.Getenv("ATTACHMENT_SCANNER_API_TOKEN")
payload, _ := json.Marshal(map[string]string{
"url": "https://www.attachmentscanner.com/eicar.com",
})
req, _ := http.NewRequest("POST", scannerURL+"/v1.0/scans", bytes.NewReader(payload))
req.Header.Set("Authorization", "Bearer "+apiToken)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
fmt.Println(result["status"]) // "found"
fmt.Println(result["matches"]) // [Eicar-Test-File-Signature]
}
Scan a File
Upload a file directly from disk:
func scanFile(filePath string) (map[string]interface{}, error) {
file, _ := os.Open(filePath)
defer file.Close()
var buf bytes.Buffer
writer := multipart.NewWriter(&buf)
part, _ := writer.CreateFormFile("file", filepath.Base(filePath))
io.Copy(part, file)
writer.Close()
req, _ := http.NewRequest("POST", scannerURL+"/v1.0/scans", &buf)
req.Header.Set("Authorization", "Bearer "+apiToken)
req.Header.Set("Content-Type", writer.FormDataContentType())
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
return result, nil // result["status"] is "ok" if clean, "found" if malware
}
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
payload, _ := json.Marshal(map[string]interface{}{
"url": "https://example.com/large-file.zip",
"async": true,
"callback": "https://your-app.com/webhooks/scan-complete",
})
req, _ := http.NewRequest("POST", scannerURL+"/v1.0/scans", bytes.NewReader(payload))
req.Header.Set("Authorization", "Bearer "+apiToken)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var scan map[string]interface{}
json.NewDecoder(resp.Body).Decode(&scan)
fmt.Println(scan["id"]) // "a1b2c3d4-..."
fmt.Println(scan["status"]) // "pending"
// 2. Receive the callback
http.HandleFunc("POST /webhooks/scan-complete", func(w http.ResponseWriter, r *http.Request) {
var result map[string]interface{}
json.NewDecoder(r.Body).Decode(&result)
switch result["status"] {
case "found":
fmt.Printf("Malware detected: %v\n", result["matches"])
// quarantine or delete the file
case "ok":
// file is clean — move to final storage
}
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"received": true}`))
})
// 3. Poll for results (alternative to callback)
scanID := scan["id"].(string)
req, _ := http.NewRequest("GET", scannerURL+"/v1.0/scans/"+scanID, nil)
req.Header.Set("Authorization", "Bearer "+apiToken)
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
fmt.Println(result["status"]) // "ok", "found", "pending", etc.
Typed
Type-safe wrapper with full response types:
type ScanResult struct {
ID string `json:"id"`
Status string `json:"status"`
Callback *string `json:"callback"`
URL *string `json:"url"`
Filename *string `json:"filename"`
ContentLength *int64 `json:"content_length"`
MD5 *string `json:"md5"`
SHA256 *string `json:"sha256"`
Matches []string `json:"matches"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
func scanURL(apiURL, token, targetURL string) (*ScanResult, error) {
payload, _ := json.Marshal(map[string]string{"url": targetURL})
req, _ := http.NewRequest("POST", apiURL+"/v1.0/scans", bytes.NewReader(payload))
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result ScanResult
json.NewDecoder(resp.Body).Decode(&result)
return &result, nil
}
func scanFile(apiURL, token, filePath string) (*ScanResult, error) {
file, _ := os.Open(filePath)
defer file.Close()
var buf bytes.Buffer
writer := multipart.NewWriter(&buf)
part, _ := writer.CreateFormFile("file", filepath.Base(filePath))
io.Copy(part, file)
writer.Close()
req, _ := http.NewRequest("POST", apiURL+"/v1.0/scans", &buf)
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", writer.FormDataContentType())
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result ScanResult
json.NewDecoder(resp.Body).Decode(&result)
return &result, nil
}
// Usage
result, err := scanURL(scannerURL, apiToken, "https://www.attachmentscanner.com/eicar.com")
if err != nil {
log.Fatal(err)
}
if result.Status == "found" {
fmt.Println("Malware detected:", result.Matches)
}
HTTP Server Integration
A full Go HTTP server that accepts file uploads and scans them:
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
)
type ScanResult struct {
ID string `json:"id"`
Status string `json:"status"`
Callback *string `json:"callback"`
URL *string `json:"url"`
Filename *string `json:"filename"`
ContentLength *int64 `json:"content_length"`
MD5 *string `json:"md5"`
SHA256 *string `json:"sha256"`
Matches []string `json:"matches"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
var (
scannerURL = os.Getenv("ATTACHMENT_SCANNER_URL")
apiToken = os.Getenv("ATTACHMENT_SCANNER_API_TOKEN")
)
func scanURL(w http.ResponseWriter, r *http.Request) {
var body struct {
URL string `json:"url"`
}
json.NewDecoder(r.Body).Decode(&body)
payload, _ := json.Marshal(map[string]string{"url": body.URL})
req, _ := http.NewRequest("POST", scannerURL+"/v1.0/scans", bytes.NewReader(payload))
req.Header.Set("Authorization", "Bearer "+apiToken)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
defer resp.Body.Close()
w.Header().Set("Content-Type", "application/json")
io.Copy(w, resp.Body)
}
func scanFile(w http.ResponseWriter, r *http.Request) {
file, header, err := r.FormFile("file")
if err != nil {
http.Error(w, err.Error(), 400)
return
}
defer file.Close()
var buf bytes.Buffer
writer := multipart.NewWriter(&buf)
part, _ := writer.CreateFormFile("file", header.Filename)
io.Copy(part, file)
writer.Close()
req, _ := http.NewRequest("POST", scannerURL+"/v1.0/scans", &buf)
req.Header.Set("Authorization", "Bearer "+apiToken)
req.Header.Set("Content-Type", writer.FormDataContentType())
resp, err := http.DefaultClient.Do(req)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
defer resp.Body.Close()
w.Header().Set("Content-Type", "application/json")
io.Copy(w, resp.Body)
}
// Webhook callback handler
func scanCallback(w http.ResponseWriter, r *http.Request) {
var result ScanResult
json.NewDecoder(r.Body).Decode(&result)
switch result.Status {
case "found":
fmt.Printf("Malware detected: %v\n", result.Matches)
// quarantine or delete the file
case "ok":
// file is clean — move to final storage
}
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"received": true}`))
}
func main() {
http.HandleFunc("POST /scan/url", scanURL)
http.HandleFunc("POST /scan/file", scanFile)
http.HandleFunc("POST /webhooks/scan-complete", scanCallback)
fmt.Println("Go example listening on :3000")
http.ListenAndServe(":3000", nil)
}
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"}'