project_name: "my-upload-service" version: "2.0" upload: max_file_size: 10737418240 # 10GB allowed_mime_types: - image/jpeg - image/png - application/pdf - video/mp4 chunk_size: 5242880 # 5MB chunks temp_storage: "/tmp/gunner_uploads" final_storage: type: "s3" bucket: "gunner-files" endpoint: "https://s3.amazonaws.com"
npx gunner-cli project new --type fileupload --name my-upload-service Or if using the Go-based Gunner: fileupload gunner project new
Uploaded filenames can contain path traversal sequences ( ../../../etc/passwd ). Use Gunner's built-in sanitizer: project_name: "my-upload-service" version: "2
const safeName = gunner.sanitizeFilename(originalName); // Returns: "safe_file.txt" Set a hard deadline per upload in upload.yaml : Unlike standard rate limiters that use fixed windows,
fileupload gunner project new --with-scan --scan-threshold strict Every uploaded file is scanned in a separate Goroutine/Worker without blocking the upload acknowledgment. Infected files are moved to a quarantine bucket, and the original uploader receives a 451 HTTP status code (Unavailable For Legal Reasons). Unlike standard rate limiters that use fixed windows, Gunner implements a token bucket with leaky bucket fallback , adapting to current system load. Configure it in gunner.workers.yaml :
| Error Message | Likely Cause | Solution | |---------------|--------------|----------| | ETIMEDOUT: chunk write failed | Network instability | Increase chunk_timeout in upload.yaml to 60s | | disk full: /tmp/gunner_uploads | Temp storage exhausted | Mount a larger volume or enable streaming mode | | invalid project structure: missing gunner.workers.yaml | Incomplete initialization | Re-run fileupload gunner project new --force | | MIME mismatch: application/octet-stream | Strict whitelist blocking | Add application/octet-stream or improve client Content-Type header | | redis: CLUSTERDOWN | Redis cluster misconfiguration | Use a single Redis node for development, or fix cluster slots | Enable verbose logging: