#!/bin/bash # Script to check a file against VirusTotal API # Requires: curl, jq # Environment variable: virustotal_apikey set -e # Configuration FILE_PATH="${VIRUS_TOTAL_FILE:-vision-start.zip}" API_KEY="${virustotal_apikey}" BASE_URL="https://www.virustotal.com/api/v3" # Check if API key is set if [ -z "$API_KEY" ]; then echo "Error: virustotal_apikey environment variable is not set" exit 1 fi # Check if file exists if [ ! -f "$FILE_PATH" ]; then echo "Error: File $FILE_PATH not found" exit 1 fi # Check if required tools are available if ! command -v curl &> /dev/null; then echo "Error: curl is required but not installed" exit 1 fi if ! command -v jq &> /dev/null; then echo "Error: jq is required but not installed" exit 1 fi echo "Uploading $FILE_PATH to VirusTotal for analysis..." # Upload file to VirusTotal UPLOAD_RESPONSE=$(curl -s -X POST \ -H "x-apikey: $API_KEY" \ -F "file=@$FILE_PATH" \ "$BASE_URL/files") # Extract scan_id from response SCAN_ID=$(echo "$UPLOAD_RESPONSE" | jq -r '.data.id') if [ "$SCAN_ID" == "null" ] || [ -z "$SCAN_ID" ]; then echo "Error: Failed to upload file or get scan ID" echo "Response: $UPLOAD_RESPONSE" exit 1 fi echo "File uploaded successfully. Scan ID: $SCAN_ID" echo "Waiting for analysis to complete..." # Wait for analysis to complete and get results MAX_ATTEMPTS=60 ATTEMPT=0 SLEEP_INTERVAL=10 while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do echo "Checking analysis status (attempt $((ATTEMPT + 1))/$MAX_ATTEMPTS)..." # Get scan report REPORT_RESPONSE=$(curl -s -X GET \ -H "x-apikey: $API_KEY" \ "$BASE_URL/analyses/$SCAN_ID") # Check if analysis is complete RESPONSE_CODE=$(echo "$REPORT_RESPONSE" | jq -r '.data.attributes.status') if [ "$RESPONSE_CODE" == "completed" ]; then # Analysis complete echo "Analysis completed!" # Extract results POSITIVES=$(echo "$REPORT_RESPONSE" | jq -r '.data.attributes.stats.malicious') SUSPICIOUS=$(echo "$REPORT_RESPONSE" | jq -r '.data.attributes.stats.suspicious') # The v3 analyses object has no 'total' field — compute it by summing all stat categories TOTAL=$(echo "$REPORT_RESPONSE" | jq '[.data.attributes.stats | to_entries[].value] | add') ANALYSIS_ID=$(echo "$REPORT_RESPONSE" | jq -r '.data.id') PERMALINK="https://www.virustotal.com/gui/file-analysis/${ANALYSIS_ID}" echo "Analysis URL: $PERMALINK" echo "Detection ratio: $POSITIVES/$TOTAL" # Check if file is safe if [ "$POSITIVES" -eq 0 ] && [ "$SUSPICIOUS" -eq 0 ]; then echo "✅ File is clean (no threats detected)" exit 0 else echo "❌ File flagged: $POSITIVES malicious, $SUSPICIOUS suspicious (out of $TOTAL scanners)" exit 1 fi elif [ "$RESPONSE_CODE" == "queued" ]; then echo "File still queued for analysis..." elif [ "$RESPONSE_CODE" == "in-progress" ]; then echo "Analysis still in progress..." else echo "Unexpected response code: $RESPONSE_CODE" echo "Response: $REPORT_RESPONSE" exit 1 fi ATTEMPT=$((ATTEMPT + 1)) if [ $ATTEMPT -lt $MAX_ATTEMPTS ]; then sleep $SLEEP_INTERVAL fi done echo "Timeout: Analysis did not complete within expected time" exit 1