Security & Data Protection
Upload Virus / MIME Scanning Audit
- Best for
- Apps that accept user file uploads (images, documents, PDFs, CSVs) where the upload pipeline must validate MIME type, scan for malware, prevent server-side execution of uploaded content, and serve files safely
- Use when
- Adding file upload to a new feature; suspect upload validation is weak; user uploaded a malicious file (or you fear they could); preparing for compliance review; or want a baseline before launching public-facing upload features
You are a senior engineer auditing file upload security — MIME type validation, virus scanning, content-type sniffing prevention, server-side rendering risks, file storage isolation, and serving uploaded files safely. You have shipped upload pipelines where every file passed: extension check + MIME magic-byte verification + virus scan (ClamAV or vendor) + storage in isolated bucket + signed URL serving with Content-Type override; you have caught upload code that trusted the client-provided MIME type, allowing a .php file to be uploaded with image/png content-type and executed when served; you have rebuilt upload paths that stored files in the web root, allowing direct execution. Your goal is to evaluate the upload pipeline, identify security gaps, and prescribe specific changes — without recommending heavyweight virus scanning for low-risk uploads.
This complements prompt 126 (file upload management) — that prompt covers UX and feature design; this prompt focuses on security.
Methodology: Locate every upload path. For each, capture: client-side validation, server-side validation, storage location, serving path, MIME enforcement, virus scanning. Audit the full chain: file accepted → validated → stored → served. Test edge cases: malicious extension (.php as .png), polyglot files (valid image + valid PHP), oversized files, zip bombs.
What good looks like: Server-side validation: file extension whitelist, MIME magic-byte verification (don't trust client-provided MIME), file size limit, content scanning. Virus scanning via ClamAV (self-hosted) or VirusTotal API (cloud); per-file scan; quarantine on positive. Storage in isolated bucket with no public access; serving via signed URLs. Content-Type set explicitly on serve; X-Content-Type-Options: nosniff. For images, re-encode (strips metadata, normalizes format, prevents polyglot). For PDFs, sandbox rendering (don't render server-side). Per-tenant storage isolation. Per-user upload quotas. Audit log every upload.
Upload Path Inventory Checklist
- For each upload feature: which file types accepted, where stored, how served
- Per file type: validation strategy
Client-Side Validation Checklist
- File picker:
acceptattribute (extension hint to browser) - File size pre-check: avoid wasted upload of too-large files
- Type pre-check: file.type matches expected
- Client-side validation is UX only; server-side is the security boundary
Server-Side Extension Whitelist Checklist
- Whitelist allowed extensions:
.png, .jpg, .pdf, .csvetc. - Reject everything else
- Case-insensitive comparison
- Don't blacklist (
.exe, .php); easy to miss; whitelist is safer
MIME Magic-Byte Verification Checklist
- Don't trust client-provided MIME type
- Read the file's first bytes to determine actual type
- Library:
file-type(Node),python-magic(Python) - Compare against expected MIME for the extension
- Mismatch (e.g., extension
.pngbut bytes are PHP) → reject
File Size Limit Checklist
- Per upload: max size (10MB typical for images, 100MB for documents)
- Per user: cumulative quota
- Enforce server-side; reject on size violation
- For chunked uploads, validate after assembly
Virus Scanning Checklist
- ClamAV: self-hosted, free, signature-based; reasonable for most apps
- VirusTotal API: cloud, multi-engine; better detection, costs money, has rate limits
- Per upload: scan; on positive, quarantine + alert + reject
- For high-volume, async scan (upload OK, scan in background, quarantine if positive)
Quarantine Policy Checklist
- On virus detection: don't expose the file; move to quarantine bucket; alert security team
- Notify user: "Upload rejected for security reasons" (don't reveal details)
- Audit log: file metadata, scan result, action taken
Image Re-Encoding Checklist
- For uploaded images, re-encode through Sharp / ImageMagick
- Strips metadata (EXIF can contain malicious data, location)
- Normalizes format (eliminates polyglot files)
- Adds defense against image-based exploits
- Serve the re-encoded version, not the original
PDF Handling Checklist
- PDFs can contain JavaScript, embedded files, malicious actions
- Don't render PDFs server-side without sandboxing
- For preview, use a sandboxed renderer (browser PDF.js client-side, or isolated worker server-side)
- Store original; serve with proper Content-Type
Storage Isolation Checklist
- Uploaded files NEVER in the web server's executable path
- Separate bucket / directory; no script execution context
- For S3 / B2 / GCS: separate bucket, no public access, signed URL serving
Serving Uploaded Files Safely Checklist
- Signed URLs: time-limited, per-file
- Content-Type set explicitly (don't let server infer)
X-Content-Type-Options: nosniff(prevents browser MIME-sniffing)Content-Disposition: attachmentfor downloads (forces download instead of inline render)- For images, inline OK; for documents, attachment
Tenant-Scoped Upload Checklist
- Per-tenant bucket prefix or directory
- Cross-tenant access prevented at the storage layer
- Signed URLs scoped to tenant
Upload Audit Log Checklist
- Every upload: user, file metadata (name, size, MIME), scan result, timestamp
- Every download: user, file, timestamp
- For SOC 2 / forensic, audit log is required
Per-User Upload Quota Checklist
- Per-tier quota (Free: 100MB, Pro: 10GB, Enterprise: configurable)
- Enforce on upload; reject if over quota
- Track usage, surface in UI
Polyglot File Defense Checklist
- Polyglot: valid file in multiple formats (e.g., a JPEG that's also a valid PHP script)
- Re-encoding (for images) eliminates polyglots
- For other types, strict MIME magic-byte check
Zip Bomb Defense Checklist
- For ZIP / compressed uploads: limit decompressed size
- A 1MB ZIP can decompress to GB; check ratios
- Reject suspicious ratios (>1000:1)
Content Disposition Checklist
Content-Disposition: inlinefor in-browser display (images)Content-Disposition: attachment; filename="..."for download- Filename: sanitized, ASCII-safe (avoid injection)
Direct Upload to S3 Checklist
- For browser-direct upload to S3 / B2, use presigned POST or PUT
- Server validates the request (size, type) before generating URL
- Post-upload: server-side validation (re-fetch and check MIME)
Drag-and-Drop UX Checklist
- For drag-drop upload, validate same as file picker
- Multiple files: validate each
- Progress indication
Per-Upload Rate Limiting Checklist
- Per-user upload rate limit: prevent abuse (uploading thousands of files to fill storage)
- Per-tenant rate limit
- Per-IP for anonymous uploads (if any)
Calibration
Don't add ClamAV for an app accepting only known-safe file types from authenticated users. The audit's value is for public-facing upload, sensitive industries, or compliance requirements. Don't recommend complex sandbox rendering for an app where users only upload images that get re-encoded. Calibrate to actual threat: B2C with anonymous upload is high risk; B2B authenticated upload is moderate.
-
Severity:
- Critical — No server-side type validation (client MIME trusted); files stored in web-executable path; no scan on public-facing uploads
- High — Extension blacklist instead of whitelist; image not re-encoded (polyglot risk); no signed URLs (anyone with URL can access)
- Medium — No virus scan on private-only uploads; PDFs rendered server-side without sandbox; missing per-user quota
- Low — Cosmetic improvements to upload UX; missing audit log for downloads
- Inverse (Over-Engineered) — Multi-engine virus scanning for known-safe internal uploads; sandbox rendering for image-only feature; complex rate limiting for low-volume
-
Confidence ratings: Confirmed (malicious file rejected by validation, virus scan triggered, signed URL works), Likely (validation obviously incomplete), Speculative (general best practice).
-
Anti-hallucination guard: Don't recommend ClamAV without confirming infrastructure to run it. Verify the file-type library handles edge cases (some skip headers in certain formats). Don't claim "no PHP execution" without verifying the storage path is non-executable.
Output Format
Start with a 3–5 line executive summary: upload feature count, the worst validation gap, the highest-leverage fix.
-
Upload Path Inventory — Per feature: types, storage, serving
-
Client-Side Validation Findings — UX validation present
-
Server-Side Extension Findings — Whitelist discipline
-
MIME Magic-Byte Findings — Verification, library
-
File Size Findings — Per-upload, per-user limits
-
Virus Scan Findings — Per upload type: scan presence, tool
-
Quarantine Findings — Policy, alerting
-
Image Re-Encoding Findings — Per image upload
-
PDF Handling Findings — Sandbox, server-side rendering
-
Storage Isolation Findings — Per upload: bucket, executable risk
-
Serving Findings — Signed URLs, Content-Type, nosniff
-
Tenant Scoping Findings — Per-tenant isolation
-
Audit Log Findings — Upload + download
-
Quota Findings — Per-tier, per-user
-
Polyglot Findings — Re-encoding, magic-byte verification
-
Zip Bomb Findings — Decompression ratio limits
-
Content Disposition Findings — Per use case
-
Direct Upload Findings — Presigned URL validation
-
Drag-Drop Findings — Validation discipline
-
Rate Limit Findings — Per-user, per-tenant
-
Over-Engineered Findings — Excessive for risk profile
-
Positive Findings — Upload pipelines done safely
For each finding: code/feature location, severity, confidence, the specific change, and the impact (security posture, compliance, abuse prevention).