#!/usr/bin/env bash # security-audit.sh # Security audit script for applications hosted on Ghaymah or any VPS/PaaS environment. # Checks: # 1. Open ports # 2. SSL certificate status # 3. Sensitive file permissions set -euo pipefail DOMAIN="${1:-}" PORT="${2:-443}" APP_DIR="${3:-.}" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' pass() { echo -e "${GREEN}[OK]${NC} $1" } warn() { echo -e "${YELLOW}[WARN]${NC} $1" } fail() { echo -e "${RED}[FAIL]${NC} $1" } echo "==================================================" echo " Automated Security Audit - $(date '+%Y-%m-%d %H:%M:%S')" echo "==================================================" # -------------------------------------------------- # 1. Open Ports Check # -------------------------------------------------- echo echo "---- Checking Open Ports ----" if command -v ss >/dev/null 2>&1; then OPEN_PORTS=$(ss -tuln | awk 'NR>1 {print $5}' | sed -E 's/.*:([0-9]+)$/\1/' | sort -un) elif command -v netstat >/dev/null 2>&1; then OPEN_PORTS=$(netstat -tuln | awk 'NR>2 {print $4}' | sed -E 's/.*:([0-9]+)$/\1/' | sort -un) else warn "Neither ss nor netstat is available. Skipping port check." OPEN_PORTS="" fi ALLOWED_PORTS="22 80 443" if [ -n "$OPEN_PORTS" ]; then echo "Open ports: $OPEN_PORTS" for port in $OPEN_PORTS; do if echo "$ALLOWED_PORTS" | grep -qw "$port"; then pass "Port $port is allowed" else warn "Port $port is open and not in the allowed list" fi done else warn "No ports detected" fi # -------------------------------------------------- # 2. SSL Certificate Check # -------------------------------------------------- echo echo "---- Checking SSL Certificate ----" if [ -z "$DOMAIN" ]; then warn "No domain provided. Skipping SSL check." else if command -v openssl >/dev/null 2>&1; then CERT_INFO=$(echo | timeout 10 openssl s_client \ -connect "${DOMAIN}:${PORT}" \ -servername "$DOMAIN" 2>/dev/null | \ openssl x509 -noout -dates -issuer -subject 2>/dev/null) || true if [ -z "$CERT_INFO" ]; then fail "Unable to retrieve SSL certificate" else echo "$CERT_INFO" EXPIRY_DATE=$(echo "$CERT_INFO" | grep "notAfter" | cut -d= -f2) if [ -n "$EXPIRY_DATE" ]; then EXPIRY_EPOCH=$(date -d "$EXPIRY_DATE" +%s 2>/dev/null || echo 0) CURRENT_EPOCH=$(date +%s) DAYS_LEFT=$(( (EXPIRY_EPOCH - CURRENT_EPOCH) / 86400 )) if [ "$DAYS_LEFT" -lt 0 ]; then fail "SSL certificate expired" elif [ "$DAYS_LEFT" -lt 30 ]; then warn "SSL certificate expires in $DAYS_LEFT days" else pass "SSL certificate valid for $DAYS_LEFT days" fi fi fi else warn "OpenSSL is not installed" fi fi # -------------------------------------------------- # 3. Sensitive File Permissions Check # -------------------------------------------------- echo echo "---- Checking Sensitive File Permissions ----" SENSITIVE_FILES=( ".env" "*.pem" "*.key" "id_rsa" "config/secrets*" ) for pattern in "${SENSITIVE_FILES[@]}"; do while IFS= read -r -d '' file; do PERMISSIONS=$(stat -c "%a" "$file" 2>/dev/null || stat -f "%A" "$file") if [ -n "$PERMISSIONS" ]; then LAST_DIGIT="${PERMISSIONS: -1}" if [ "$LAST_DIGIT" -ge 4 ] 2>/dev/null; then fail "$file has insecure permissions ($PERMISSIONS)" else pass "$file permissions are secure ($PERMISSIONS)" fi fi done < <(find "$APP_DIR" -type f -iname "$pattern" -print0 2>/dev/null) done echo echo "Checking world-writable files..." WORLD_WRITABLE=$(find "$APP_DIR" -type f -perm -o+w 2>/dev/null | grep -v "/.git/" || true) if [ -n "$WORLD_WRITABLE" ]; then fail "World-writable files found:" echo "$WORLD_WRITABLE" else pass "No world-writable files found." fi echo echo "==================================================" echo " Security Audit Completed" echo "=================================================="