Przejdź do treści

🔒 Advanced Security and Sandboxing

Implement robust security measures and sandboxing techniques to protect shell scripts from malicious input, privilege escalation, and unauthorized access.

🧭 Security Fundamentals

Shell scripts face unique security challenges due to their system-level access and interpreted nature. Key threats include:

Attack Vectors

  1. Input Injection - Command, path, or code injection through user input
  2. Privilege Escalation - Exploiting elevated permissions
  3. Information Disclosure - Unauthorized access to sensitive data
  4. Denial of Service - Resource exhaustion attacks
  5. Side Channel Attacks - Timing or error-based information leakage

Security Principles

  1. Least Privilege - Run with minimal necessary permissions
  2. Input Validation - Sanitize all external data
  3. Defense in Depth - Multiple layers of protection
  4. Fail Secure - Default to safe failure modes
  5. Principle of Least Astonishment - Predictable, secure behavior

🧪 Input Sanitization and Validation

Secure Input Handling

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# Comprehensive input validation framework
validate_input() {
    local input_type="$1"
    local input_value="$2"

    case "$input_type" in
        filename)
            # Prevent path traversal and special characters
            if echo "$input_value" | grep -E '[/\\.][/.]|^\.\.?$|[*?[]' >/dev/null; then
                echo "Invalid filename: contains dangerous characters" >&2
                return 1
            fi

            # Limit length
            if [ ${#input_value} -gt 255 ]; then
                echo "Invalid filename: too long" >&2
                return 1
            fi

            # Check for allowed characters only
            if echo "$input_value" | grep -E '[^a-zA-Z0-9._-]' >/dev/null; then
                echo "Invalid filename: contains invalid characters" >&2
                return 1
            fi
            ;;

        filepath)
            # Validate absolute or relative paths
            if echo "$input_value" | grep -E '(\.\./)|(\.\.\\)' >/dev/null; then
                echo "Invalid filepath: path traversal attempt" >&2
                return 1
            fi

            # Check components
            IFS='/' read -ra components <<< "$input_value"
            for component in "${components[@]}"; do
                if [ -n "$component" ] && ! validate_input "filename" "$component"; then
                    return 1
                fi
            done
            ;;

        alphanumeric)
            if echo "$input_value" | grep -E '[^a-zA-Z0-9]' >/dev/null; then
                echo "Invalid input: non-alphanumeric characters" >&2
                return 1
            fi
            ;;

        numeric)
            if ! echo "$input_value" | grep -E '^[0-9]+$' >/dev/null; then
                echo "Invalid input: not a valid number" >&2
                return 1
            fi

            # Check range if specified
            local min="${3:-0}"
            local max="${4:-999999999}"
            if [ "$input_value" -lt "$min" ] || [ "$input_value" -gt "$max" ]; then
                echo "Invalid input: number out of range [$min-$max]" >&2
                return 1
            fi
            ;;

        url)
            # Basic URL validation
            if ! echo "$input_value" | grep -E '^https?://[a-zA-Z0-9.-]+(/[a-zA-Z0-9._-]*)*$' >/dev/null; then
                echo "Invalid input: malformed URL" >&2
                return 1
            fi
            ;;

        *)
            echo "Unknown input type: $input_type" >&2
            return 1
            ;;
    esac

    return 0
}

# Usage examples
# validate_input "filename" "config.txt" || exit 1
# validate_input "numeric" "42" 0 100 || exit 1

Safe Command Construction

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# Secure command building patterns

# ❌ Dangerous - direct variable interpolation
dangerous_command() {
    local filename="$1"
    rm -f /tmp/$filename  # Vulnerable to path traversal
}

# ✅ Safe - input validation and quoting
safe_command() {
    local filename="$1"

    # Validate input
    validate_input "filename" "$filename" || return 1

    # Use full path and quote properly
    local safe_path="/tmp/$filename"
    rm -f "$safe_path"
}

# ✅ Even safer - whitelist approach
whitelist_command() {
    local allowed_files="file1.txt file2.log config.ini"
    local requested_file="$1"

    # Check against whitelist
    if ! echo " $allowed_files " | grep -F " $requested_file " >/dev/null; then
        echo "File not in whitelist: $requested_file" >&2
        return 1
    fi

    rm -f "/tmp/$requested_file"
}

🧠 Privilege Management

Dropping Privileges

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# Secure privilege dropping pattern
drop_privileges() {
    local target_user="${1:-nobody}"
    local target_group="${2:-nogroup}"

    # Only drop if running as root
    if [ "$(id -u)" -ne 0 ]; then
        echo "Not running as root, skipping privilege drop" >&2
        return 0
    fi

    # Validate target user/group exist
    if ! getent passwd "$target_user" >/dev/null 2>&1; then
        echo "Target user does not exist: $target_user" >&2
        return 1
    fi

    if ! getent group "$target_group" >/dev/null 2>&1; then
        echo "Target group does not exist: $target_group" >&2
        return 1
    fi

    # Drop privileges
    echo "Dropping privileges to $target_user:$target_group" >&2

    # Change directory to avoid permission issues
    cd / || return 1

    # Drop group first, then user
    if ! exec sg "$target_group" -c "exec su -s /bin/sh '$target_user' -c 'exec \"$0\" \"\$@\"'" -- "$@"; then
        echo "Failed to drop privileges" >&2
        return 1
    fi
}

# Usage at script start
# if [ "$(id -u)" -eq 0 ]; then
#     drop_privileges "appuser" "appgroup"
# fi

Capability-Based Access Control

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# Fine-grained capability management
capability_manager() {
    # Define required capabilities
    local required_caps=""

    # Check available capabilities
    check_capabilities() {
        if command -v capsh >/dev/null 2>&1; then
            capsh --print | grep -E 'Current:|Bounding set:'
        else
            echo "Capability checking not available" >&2
        fi
    }

    # Request specific capabilities
    request_capability() {
        local cap="$1"
        local purpose="$2"

        echo "Requesting capability: $cap ($purpose)" >&2

        # Implementation depends on system (Linux capabilities, etc.)
        case "$cap" in
            net_bind_service)
                # Check if we can bind to privileged ports
                if [ "$(id -u)" -ne 0 ] && [ "${PORT:-8080}" -lt 1024 ]; then
                    echo "Need root privileges to bind to port ${PORT:-80}" >&2
                    return 1
                fi
                ;;
            dac_override)
                # Check file access permissions
                if [ ! -w "/etc" ]; then
                    echo "Insufficient file permissions" >&2
                    return 1
                fi
                ;;
        esac
    }
}

🧪 Secure File Operations

Atomic File Operations

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# Secure atomic file writing
atomic_write() {
    local target_file="$1"
    local content="$2"
    local temp_file
    local target_dir

    # Validate target directory
    target_dir=$(dirname "$target_file")
    if [ ! -d "$target_dir" ] || [ ! -w "$target_dir" ]; then
        echo "Cannot write to directory: $target_dir" >&2
        return 1
    fi

    # Create temporary file in same directory
    temp_file=$(mktemp "${target_file}_XXXXXX" 2>/dev/null)
    if [ -z "$temp_file" ]; then
        echo "Failed to create temporary file" >&2
        return 1
    fi

    # Write content to temporary file
    echo "$content" > "$temp_file" || {
        rm -f "$temp_file"
        echo "Failed to write to temporary file" >&2
        return 1
    }

    # Atomically move to target location
    if ! mv "$temp_file" "$target_file"; then
        rm -f "$temp_file"
        echo "Failed to move temporary file to target" >&2
        return 1
    fi

    echo "Successfully wrote to $target_file" >&2
    return 0
}

# Secure configuration file update
update_config_secure() {
    local config_file="$1"
    local new_setting="$2"

    # Backup existing config
    local backup_file="${config_file}.backup.$(date +%s)"
    if [ -f "$config_file" ]; then
        cp "$config_file" "$backup_file" || {
            echo "Failed to create backup" >&2
            return 1
        }
    fi

    # Update configuration atomically
    if ! atomic_write "$config_file" "$new_setting"; then
        # Restore backup on failure
        if [ -f "$backup_file" ]; then
            mv "$backup_file" "$config_file"
        fi
        return 1
    fi

    # Remove backup on success
    rm -f "$backup_file"
    return 0
}

Secure Temporary Files

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# Secure temporary file management
secure_temp_manager() {
    # Create secure temporary directory
    create_secure_temp_dir() {
        local base_dir="${TMPDIR:-/tmp}"
        local temp_dir

        temp_dir=$(mktemp -d "${base_dir}/XXXXXXXX" 2>/dev/null)
        if [ -z "$temp_dir" ]; then
            echo "Failed to create temporary directory" >&2
            return 1
        fi

        # Set restrictive permissions
        chmod 700 "$temp_dir" || {
            rm -rf "$temp_dir"
            echo "Failed to set permissions on temporary directory" >&2
            return 1
        }

        echo "$temp_dir"
        return 0
    }

    # Secure temporary file creation
    create_secure_temp_file() {
        local suffix="${1:-}"
        local temp_file

        temp_file=$(mktemp "${TMPDIR:-/tmp}/XXXXXXXX${suffix}" 2>/dev/null)
        if [ -z "$temp_file" ]; then
            echo "Failed to create temporary file" >&2
            return 1
        fi

        # Set restrictive permissions
        chmod 600 "$temp_file" || {
            rm -f "$temp_file"
            echo "Failed to set permissions on temporary file" >&2
            return 1
        }

        echo "$temp_file"
        return 0
    }

    # Cleanup function
    cleanup_temp() {
        local temp_path="$1"
        if [ -n "$temp_path" ] && [ -e "$temp_path" ]; then
            rm -rf "$temp_path"
        fi
    }
}

🧠 Sandboxing Techniques

Namespace Isolation (Linux)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# Linux namespace-based sandboxing
linux_sandbox() {
    # Check if running in container/namespace
    is_sandboxed() {
        if [ -f /.dockerenv ] || [ -f /run/.containerenv ]; then
            return 0
        fi

        # Check cgroup
        if [ -f /proc/1/cgroup ]; then
            if ! grep -q ':/docker/' /proc/1/cgroup 2>/dev/null; then
                return 1
            fi
        fi

        return 0
    }

    # Create network namespace
    create_network_sandbox() {
        if ! command -v unshare >/dev/null 2>&1; then
            echo "unshare command not available" >&2
            return 1
        fi

        # Create isolated network namespace
        unshare -n -- sh -c '
            # Bring up loopback interface
            ip link set lo up 2>/dev/null || true

            # Execute sandboxed command
            exec "$@"
        ' -- "$@"
    }

    # Create mount namespace
    create_mount_sandbox() {
        unshare -m -- sh -c '
            # Make mount point private
            mount --make-rprivate /

            # Create temporary overlay
            local temp_dir=$(mktemp -d)
            mkdir -p "$temp_dir/upper" "$temp_dir/work" "$temp_dir/merged"

            # Mount overlayfs (if available)
            if mount -t overlay overlay \
                -o lowerdir=/,upperdir="$temp_dir/upper",workdir="$temp_dir/work" \
                "$temp_dir/merged" 2>/dev/null; then

                # Change root to overlay
                cd "$temp_dir/merged"
                pivot_root . old_root
                exec chroot . "$@"
            else
                # Fallback: just run in separate mount namespace
                exec "$@"
            fi
        ' -- "$@"
    }
}

Chroot Sandboxing

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# Chroot-based sandboxing
chroot_sandbox() {
    # Create minimal chroot environment
    create_chroot_env() {
        local chroot_dir="$1"
        local required_bins="/bin/sh /bin/ls /usr/bin/id /bin/cat"

        # Create directory structure
        mkdir -p "$chroot_dir"/{bin,usr/bin,lib,lib64,etc,tmp,proc,dev}

        # Copy required binaries and their dependencies
        for bin in $required_bins; do
            if [ -f "$bin" ]; then
                # Copy binary
                cp "$bin" "$chroot_dir$bin"

                # Copy dependencies (simplified - real implementation needs ldd)
                ldd "$bin" 2>/dev/null | grep -o '/[^ ]*' | while read -r lib; do
                    if [ -f "$lib" ]; then
                        local lib_dir
                        lib_dir=$(dirname "$lib")
                        mkdir -p "$chroot_dir$lib_dir"
                        cp "$lib" "$chroot_dir$lib"
                    fi
                done
            fi
        done

        # Create basic config files
        echo "root:x:0:0:root:/root:/bin/sh" > "$chroot_dir/etc/passwd"
        echo "root:x:0:" > "$chroot_dir/etc/group"

        echo "Chroot environment created at $chroot_dir" >&2
    }

    # Execute in chroot
    run_in_chroot() {
        local chroot_dir="$1"
        shift

        # Validate chroot directory
        if [ ! -d "$chroot_dir" ]; then
            echo "Chroot directory does not exist: $chroot_dir" >&2
            return 1
        fi

        # Execute in chroot
        chroot "$chroot_dir" "$@"
    }
}

🧪 Secure Communication

Encrypted Data Handling

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# Secure data encryption/decryption
secure_crypto() {
    # Encrypt file with GPG
    encrypt_file() {
        local input_file="$1"
        local output_file="${2:-$input_file.gpg}"
        local recipient="$3"

        # Validate inputs
        if [ ! -f "$input_file" ]; then
            echo "Input file not found: $input_file" >&2
            return 1
        fi

        if [ -z "$recipient" ]; then
            echo "Recipient not specified" >&2
            return 1
        fi

        # Encrypt
        if ! gpg --encrypt --recipient "$recipient" --output "$output_file" "$input_file"; then
            echo "Encryption failed" >&2
            return 1
        fi

        echo "File encrypted: $output_file" >&2
        return 0
    }

    # Decrypt file with GPG
    decrypt_file() {
        local input_file="$1"
        local output_file="${2:-${input_file%.gpg}}"

        # Validate input
        if [ ! -f "$input_file" ]; then
            echo "Input file not found: $input_file" >&2
            return 1
        fi

        # Decrypt
        if ! gpg --decrypt --output "$output_file" "$input_file"; then
            echo "Decryption failed" >&2
            return 1
        fi

        echo "File decrypted: $output_file" >&2
        return 0
    }

    # Secure password handling
    get_secure_password() {
        local prompt="${1:-Enter password:}"

        # Use system password prompt if available
        if command -v dialog >/dev/null 2>&1; then
            dialog --passwordbox "$prompt" 8 40 2>/dev/null
        elif command -v whiptail >/dev/null 2>&1; then
            whiptail --passwordbox "$prompt" 8 40 3>&1 1>&2 2>&3
        else
            # Fallback to read with echo disabled
            local password
            trap 'stty echo' EXIT
            stty -echo
            printf "%s" "$prompt" >&2
            read -r password
            stty echo
            echo >&2
            echo "$password"
        fi
    }
}

Secure Network Operations

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# Secure network communication
secure_network() {
    # Download file with integrity verification
    secure_download() {
        local url="$1"
        local output_file="$2"
        local expected_hash="${3:-}"

        # Validate URL
        if ! echo "$url" | grep -E '^https://' >/dev/null; then
            echo "Only HTTPS URLs are allowed" >&2
            return 1
        fi

        # Download with curl
        if ! curl -sfL --retry 3 --retry-delay 2 "$url" -o "$output_file"; then
            echo "Download failed" >&2
            return 1
        fi

        # Verify hash if provided
        if [ -n "$expected_hash" ]; then
            local actual_hash
            actual_hash=$(sha256sum "$output_file" | cut -d' ' -f1)

            if [ "$actual_hash" != "$expected_hash" ]; then
                echo "Hash verification failed" >&2
                echo "Expected: $expected_hash" >&2
                echo "Actual:   $actual_hash" >&2
                rm -f "$output_file"
                return 1
            fi
        fi

        echo "Download completed successfully" >&2
        return 0
    }

    # Secure API call with authentication
    secure_api_call() {
        local url="$1"
        local api_key="$2"
        local method="${3:-GET}"

        # Validate inputs
        if ! echo "$url" | grep -E '^https://' >/dev/null; then
            echo "Only HTTPS URLs are allowed" >&2
            return 1
        fi

        if [ -z "$api_key" ]; then
            echo "API key required" >&2
            return 1
        fi

        # Make API call
        local response
        response=$(curl -sf -X "$method" \
            -H "Authorization: Bearer $api_key" \
            -H "User-Agent: SecureClient/1.0" \
            "$url")

        local exit_code=$?

        if [ $exit_code -ne 0 ]; then
            echo "API call failed with code: $exit_code" >&2
            return $exit_code
        fi

        echo "$response"
        return 0
    }
}

🧠 Security Auditing and Monitoring

Runtime Security Monitoring

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# Security monitoring framework
security_monitor() {
    # Monitor file access
    monitor_file_access() {
        local target_dir="$1"

        # Use inotify if available
        if command -v inotifywait >/dev/null 2>&1; then
            inotifywait -m -r -e access,modify,create,delete "$target_dir" 2>/dev/null | while read -r path action file; do
                echo "SECURITY ALERT: $action on $path$file at $(date)" >&2
                # Log to security log
                logger -t "SECURITY" "File access: $action on $path$file"
            done
        else
            echo "inotifywait not available for monitoring" >&2
        fi
    }

    # Monitor process creation
    monitor_processes() {
        # Simple process monitoring
        local baseline_pids
        baseline_pids=$(pgrep -f "$$")

        while true; do
            local current_pids
            current_pids=$(pgrep -f "$$")

            # Check for new processes
            for pid in $current_pids; do
                if ! echo " $baseline_pids " | grep -F " $pid " >/dev/null; then
                    echo "SECURITY ALERT: New process created: $pid ($(ps -p $pid -o comm= 2>/dev/null))" >&2
                    logger -t "SECURITY" "New process: $pid"
                fi
            done

            sleep 5
        done
    }

    # Integrity checking
    integrity_check() {
        local target_file="$1"
        local hash_file="${target_file}.hash"

        # Create hash if it doesn't exist
        if [ ! -f "$hash_file" ]; then
            if [ -f "$target_file" ]; then
                sha256sum "$target_file" > "$hash_file"
                echo "Created integrity hash for $target_file" >&2
            fi
            return 0
        fi

        # Verify integrity
        if [ -f "$target_file" ]; then
            local current_hash
            current_hash=$(sha256sum "$target_file" | cut -d' ' -f1)
            local expected_hash
            expected_hash=$(cut -d' ' -f1 "$hash_file")

            if [ "$current_hash" != "$expected_hash" ]; then
                echo "SECURITY ALERT: File integrity compromised: $target_file" >&2
                logger -t "SECURITY" "Integrity violation: $target_file"
                return 1
            fi
        fi

        return 0
    }
}

Security Logging

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# Secure logging system
secure_logging() {
    # Structured security logging
    security_log() {
        local level="$1"
        local message="$2"
        shift 2

        local timestamp
        timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

        local log_entry
        log_entry="{\"timestamp\":\"$timestamp\",\"level\":\"$level\",\"message\":\"$message\",\"pid\":$$,\"user\":\"$(whoami)\",\"host\":\"$(hostname)\"}"

        # Log to secure facility
        logger -p auth.notice -t "SECURITY" "$log_entry"

        # Also log to stderr in development
        if [ "${SECURITY_DEBUG:-false}" = true ]; then
            echo "[SECURITY] $level: $message" >&2
        fi
    }

    # Alert functions
    security_alert() {
        security_log "ALERT" "$@"
    }

    security_warning() {
        security_log "WARNING" "$@"
    }

    security_info() {
        security_log "INFO" "$@"
    }

    # Emergency response
    security_emergency() {
        local message="$1"

        security_log "EMERGENCY" "$message"

        # Send alert to administrators
        if [ -n "${SECURITY_ALERT_EMAIL:-}" ]; then
            echo "SECURITY EMERGENCY: $message" | mail -s "Security Alert" "$SECURITY_ALERT_EMAIL"
        fi

        # Execute emergency response script if defined
        if [ -n "${SECURITY_EMERGENCY_SCRIPT:-}" ] && [ -x "$SECURITY_EMERGENCY_SCRIPT" ]; then
            "$SECURITY_EMERGENCY_SCRIPT" "$message"
        fi
    }
}

🧾 Security Best Practices

Security Checklist

  1. Input Validation
  2. [ ] All external input is validated
  3. [ ] Path traversal prevented
  4. [ ] Command injection protected
  5. [ ] SQL injection prevented

  6. Privilege Management

  7. [ ] Run with least privileges
  8. [ ] Drop privileges when possible
  9. [ ] Validate user permissions
  10. [ ] Use capability-based access

  11. File Security

  12. [ ] Secure temporary file creation
  13. [ ] Atomic file operations
  14. [ ] Proper file permissions
  15. [ ] Secure configuration handling

  16. Communication Security

  17. [ ] Use HTTPS for network calls
  18. [ ] Validate SSL certificates
  19. [ ] Encrypt sensitive data
  20. [ ] Secure credential storage

  21. Monitoring and Auditing

  22. [ ] Log security events
  23. [ ] Monitor file access
  24. [ ] Verify file integrity
  25. [ ] Alert on suspicious activity

Security Tools Integration

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Security scanning integration
security_scan() {
    local target_dir="${1:-.}"

    # ShellCheck for security issues
    if command -v shellcheck >/dev/null 2>&1; then
        echo "Running ShellCheck security scan..." >&2
        shellcheck -x -f gcc "$target_dir"/*.sh
    fi

    # Bandit-like scanning for shell scripts
    echo "Scanning for common security issues..." >&2
    find "$target_dir" -name "*.sh" -type f | while read -r script; do
        # Check for dangerous patterns
        if grep -n "eval\|exec\|system" "$script"; then
            echo "WARNING: Potentially dangerous functions in $script" >&2
        fi

        # Check for hardcoded credentials
        if grep -n -i "password\|secret\|key" "$script" | grep -v "#.*\(password\|secret\|key\)"; then
            echo "WARNING: Possible hardcoded credentials in $script" >&2
        fi
    done
}

🧾 Summary

Key Security Principles

  1. Defense in Depth - Multiple layers of protection
  2. Least Privilege - Minimal necessary permissions
  3. Fail Secure - Default to safe failure modes
  4. Input Sanitization - Validate all external data
  5. Secure Defaults - Safe configuration out of the box

Advanced Security Techniques

  • Input validation frameworks - Comprehensive sanitization
  • Privilege dropping - Reduce attack surface
  • Atomic operations - Prevent partial updates
  • Sandboxing - Isolate potentially dangerous code
  • Secure communication - Encryption and authentication
  • Runtime monitoring - Detect suspicious activity
  • Integrity checking - Verify file authenticity

Security Anti-Patterns to Avoid

  • Trusting external input without validation
  • Running with excessive privileges
  • Using weak or no authentication
  • Storing credentials in plain text
  • Ignoring security warnings
  • Not logging security events
  • Failing to monitor file access
  • Using deprecated or insecure protocols

Tools for Security Development

  • ShellCheck - Static analysis for security issues
  • Bandit - Security-oriented static analyzer
  • ClamAV - Malware detection
  • OpenSCAP - Security compliance checking
  • SELinux/AppArmor - Mandatory access control
  • Auditd - System call auditing
  • Fail2ban - Intrusion prevention
  • OSSEC - Host-based intrusion detection