Skip to content
security-first-2025 logo

Security-First Bash Scripting (2025)

security-first-2025

Security-first bash scripting patterns for 2025 (mandatory validation, zero-trust). PROACTIVELY activate for: (1) reviewing or writing security-sensitive bash scripts, (2) preventing command injection via input validation, (3) safely handling untrusted input (URLs, filenames, env vars), (4) prote...

SKILL.md

Full skill instructions

🚨 CRITICAL GUIDELINES

Windows File Path Requirements

MANDATORY: Always Use Backslashes on Windows for File Paths

When using Edit or Write tools on Windows, you MUST use backslashes (\) in file paths, NOT forward slashes (/).

Examples:

  • ❌ WRONG: D:/​repos/​project/​file.tsx
  • ✅ CORRECT: D:\repos\project\file.tsx

This applies to:

  • Edit tool file_path parameter
  • Write tool file_path parameter
  • All file operations on Windows systems

Documentation Guidelines

NEVER create new documentation files unless explicitly requested by the user.

  • Priority: Update existing README.md files rather than creating new documentation
  • Repository cleanliness: Keep repository root clean - only README.md unless user requests otherwise
  • Style: Documentation should be concise, direct, and professional - avoid AI-generated tone
  • User preference: Only create additional .md files when user specifically asks for documentation

Security-First Bash Scripting (2025)

Overview

2025 security assessments reveal 60%+ of exploited automation tools lacked adequate input sanitization. This skill provides mandatory security patterns.

Critical Security Patterns

1. Input Validation (Non-Negotiable)

Every input MUST be validated before use:

#!/​usr/​bin/​env bash
set -euo pipefail

# ✅ REQUIRED: Validate all inputs
validate_input() {
    local input="$1"
    local pattern="$2"
    local max_length="${3:-255}"

    # Check empty
    if [[ -z "$input" ]]; then
        echo "Error: Input required" >&2
        return 1
    fi

    # Check pattern
    if [[ ! "$input" =~ $pattern ]]; then
        echo "Error: Invalid format" >&2
        return 1
    fi

    # Check length
    if [[ ${#input} -gt $max_length ]]; then
        echo "Error: Input too long (max $max_length)" >&2
        return 1
    fi

    return 0
}

# Usage
read -r user_input
if validate_input "$user_input" '^[a-zA-Z0-9_-]+$' 50; then
    process "$user_input"
else
    exit 1
fi

2. Command Injection Prevention

NEVER use eval or dynamic execution with user input:

# ❌ DANGEROUS - Command injection vulnerability
user_input="$(cat user_file.txt)"
eval "$user_input"  # NEVER DO THIS

# ❌ DANGEROUS - Indirect command injection
grep "$user_pattern" file.txt  # If pattern is "-e /​etc/​passwd"

# ✅ SAFE - Use -- separator
grep -- "$user_pattern" file.txt

# ✅ SAFE - Use arrays
grep_args=("$user_pattern" "file.txt")
grep "${grep_args[@]}"

# ✅ SAFE - Validate before use
if [[ "$user_pattern" =~ ^[a-zA-Z0-9]+$ ]]; then
    grep "$user_pattern" file.txt
fi

3. Path Traversal Prevention

Sanitize and validate ALL file paths:

#!/​usr/​bin/​env bash
set -euo pipefail

# Sanitize path components
sanitize_path() {
    local path="$1"

    # Remove dangerous patterns
    path="${path//..\/​}"     # Remove ../
    path="${path//\/​..\//}"  # Remove /​../
    path="${path#/​}"         # Remove leading /

    echo "$path"
}

# Validate path is within allowed directory
is_safe_path() {
    local file_path="$1"
    local base_dir="$2"

    # Resolve to absolute paths
    local real_path real_base
    real_path=$(readlink -f "$file_path" 2>/​dev/​null) || return 1
    real_base=$(readlink -f "$base_dir" 2>/​dev/​null) || return 1

    # Check path starts with base
    [[ "$real_path" == "$real_base"/​* ]]
}

# Usage
user_file=$(sanitize_path "$user_input")
if is_safe_path "/​var/​app/​uploads/​$user_file" "/​var/​app/​uploads"; then
    cat "/​var/​app/​uploads/​$user_file"
else
    echo "Error: Access denied" >&2
    exit 1
fi

4. Secure Temporary Files

Never use predictable temp file names:

# ❌ DANGEROUS - Race condition vulnerability
temp_file="/​tmp/​myapp.tmp"
echo "data" > "$temp_file"  # Can be symlinked by attacker

# ❌ DANGEROUS - Predictable name
temp_file="/​tmp/​myapp-$$.tmp"  # PID can be guessed

# ✅ SAFE - Use mktemp
temp_file=$(mktemp)
chmod 600 "$temp_file"  # Owner-only permissions
echo "data" > "$temp_file"

# ✅ SAFE - Automatic cleanup
readonly TEMP_FILE=$(mktemp)
trap 'rm -f "$TEMP_FILE"' EXIT INT TERM

# ✅ SAFE - Temp directory
readonly TEMP_DIR=$(mktemp -d)
trap 'rm -rf "$TEMP_DIR"' EXIT INT TERM
chmod 700 "$TEMP_DIR"

5. Secrets Management

NEVER hardcode secrets or expose them:

# ❌ DANGEROUS - Hardcoded secrets
DB_PASSWORD="supersecret123"

# ❌ DANGEROUS - Secrets in environment (visible in ps)
export DB_PASSWORD="supersecret123"

# ✅ SAFE - Read from secure file
if [[ -f /​run/​secrets/​db_password ]]; then
    DB_PASSWORD=$(< /​run/​secrets/​db_password)
    chmod 600 /​run/​secrets/​db_password
else
    echo "Error: Secret not found" >&2
    exit 1
fi

# ✅ SAFE - Use cloud secret managers
get_secret() {
    local secret_name="$1"

    # AWS Secrets Manager
    aws secretsmanager get-secret-value \
        --secret-id "$secret_name" \
        --query SecretString \
        --output text
}

DB_PASSWORD=$(get_secret "production/​database/​password")

# ✅ SAFE - Prompt for sensitive data (no echo)
read -rsp "Enter password: " password
echo  # Newline after password

6. Privilege Management

Follow least privilege principle:

#!/​usr/​bin/​env bash
set -euo pipefail

# Check not running as root
if [[ $EUID -eq 0 ]]; then
    echo "Error: Do not run as root" >&2
    exit 1
fi

# Drop privileges if started as root
drop_privileges() {
    local target_user="$1"

    if [[ $EUID -eq 0 ]]; then
        echo "Dropping privileges to $target_user" >&2
        exec sudo -u "$target_user" "$0" "$@"
    fi
}

# Run specific command with minimal privileges
run_privileged() {
    local command="$1"
    shift

    # Use sudo with minimal scope
    sudo --non-interactive \
         --reset-timestamp \
         "$command" "$@"
}

# Usage
drop_privileges "appuser"

7. Environment Variable Sanitization

Clean environment before executing:

#!/​usr/​bin/​env bash
set -euo pipefail

# Clean environment
clean_environment() {
    # Unset dangerous variables
    unset IFS
    unset CDPATH
    unset GLOBIGNORE

    # Set safe PATH (absolute paths only)
    export PATH="/​usr/​local/​bin:/​usr/​bin:/​bin"

    # Set safe IFS
    IFS=$'\n\t'
}

# Execute command in clean environment
exec_clean() {
    env -i \
        HOME="$HOME" \
        USER="$USER" \
        PATH="/​usr/​local/​bin:/​usr/​bin:/​bin" \
        "$@"
}

# Usage
clean_environment
exec_clean /​usr/​local/​bin/​myapp

8. Absolute Path Usage (2025 Best Practice)

Always use absolute paths to prevent PATH hijacking:

#!/​usr/​bin/​env bash
set -euo pipefail

# ❌ DANGEROUS - Vulnerable to PATH manipulation
curl https://example.com/​data
jq '.items[]' data.json

# ✅ SAFE - Absolute paths
/​usr/​bin/​curl https://example.com/​data
/​usr/​bin/​jq '.items[]' data.json

# ✅ SAFE - Verify command location
CURL=$(command -v curl) || { echo "curl not found" >&2; exit 1; }
"$CURL" https://example.com/​data

Why This Matters:

  • Prevents malicious binaries in user PATH
  • Standard practice in enterprise environments
  • Required for security-sensitive scripts

9. History File Protection (2025 Security)

Disable history for credential operations:

#!/​usr/​bin/​env bash
set -euo pipefail

# Disable history for this session
HISTFILE=/​dev/​null
export HISTFILE

# Or disable specific commands
HISTIGNORE="*password*:*secret*:*token*"
export HISTIGNORE

# Handle sensitive operations
read -rsp "Enter database password: " db_password
echo

# Use password (not logged to history)
/​usr/​bin/​mysql -p"$db_password" -e "SELECT 1"

# Clear variable
unset db_password

Security Checklist (2025)

Every script MUST pass these checks:

Input Validation

  • All user inputs validated with regex patterns
  • Maximum length enforced on all inputs
  • Empty/​null inputs rejected
  • Special characters escaped or rejected

Command Safety

  • No eval with user input
  • No dynamic variable names from user input
  • All command arguments use -- separator
  • Arrays used instead of string concatenation

File Operations

  • All paths validated against directory traversal
  • Temp files created with mktemp
  • File permissions set restrictively (600/​700)
  • Cleanup handlers registered (trap EXIT)

Secrets

  • No hardcoded passwords/​keys/​tokens
  • Secrets read from secure storage
  • Secrets never logged or printed
  • Secrets cleared from memory when done

Privileges

  • Runs with minimum required privileges
  • Root execution rejected unless necessary
  • Privilege drops implemented where needed
  • Sudo scope minimized

Error Handling

  • set -euo pipefail enabled
  • All errors logged to stderr
  • Sensitive data not exposed in errors
  • Exit codes meaningful

Automated Security Scanning

ShellCheck Integration

# .github/​workflows/​security.yml
name: Security Scan

on: [push, pull_request]

jobs:
  shellcheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/​checkout@v3

      - name: ShellCheck
        run: |
          # Fail on security issues
          find . -name "*.sh" -exec shellcheck \
            --severity=error \
            --enable=all \
            {} +

Custom Security Linting

#!/​usr/​bin/​env bash
# security-lint.sh - Check scripts for security issues

set -euo pipefail

lint_script() {
    local script="$1"
    local issues=0

    echo "Checking: $script"

    # Check for eval
    if grep -n "eval" "$script"; then
        echo "  ❌ Found eval (command injection risk)"
        ((issues++))
    fi

    # Check for hardcoded secrets
    if grep -nE "(password|secret|token|key)\s*=\s*['\"][^'\"]+['\"]" "$script"; then
        echo "  ❌ Found hardcoded secrets"
        ((issues++))
    fi

    # Check for predictable temp files
    if grep -n "/​tmp/[a-zA-Z0-9_-]*\\.tmp" "$script"; then
        echo "  ❌ Found predictable temp file"
        ((issues++))
    fi

    # Check for unquoted variables
    if grep -nE '\$[A-Z_]+[^"]' "$script"; then
        echo "  ⚠️  Found unquoted variables"
        ((issues++))
    fi

    if ((issues == 0)); then
        echo "  ✓ No security issues found"
    fi

    return "$issues"
}

# Scan all scripts
total_issues=0
while IFS= read -r -d '' script; do
    lint_script "$script" || ((total_issues++))
done < <(find . -name "*.sh" -type f -print0)

if ((total_issues > 0)); then
    echo "❌ Found security issues in $total_issues scripts"
    exit 1
else
    echo "✓ All scripts passed security checks"
fi

Real-World Secure Script Template

#!/​usr/​bin/​env bash
#
# Secure Script Template (2025)
#

set -euo pipefail
IFS=$'\n\t'

readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"

# Security: Reject root execution
if [[ $EUID -eq 0 ]]; then
    echo "Error: Do not run as root" >&2
    exit 1
fi

# Security: Clean environment
export PATH="/​usr/​local/​bin:/​usr/​bin:/​bin"
unset CDPATH GLOBIGNORE

# Security: Secure temp file
readonly TEMP_FILE=$(mktemp)
trap 'rm -f "$TEMP_FILE"; exit' EXIT INT TERM
chmod 600 "$TEMP_FILE"

# Validate input
validate_input() {
    local input="$1"

    if [[ -z "$input" ]]; then
        echo "Error: Input required" >&2
        return 1
    fi

    if [[ ! "$input" =~ ^[a-zA-Z0-9_/​-]+$ ]]; then
        echo "Error: Invalid characters in input" >&2
        return 1
    fi

    if [[ ${#input} -gt 255 ]]; then
        echo "Error: Input too long" >&2
        return 1
    fi

    return 0
}

# Sanitize file path
sanitize_path() {
    local path="$1"
    path="${path//..\/​}"
    path="${path#/​}"
    echo "$path"
}

# Main function
main() {
    local user_input="${1:-}"

    # Validate
    if ! validate_input "$user_input"; then
        exit 1
    fi

    # Sanitize
    local safe_path
    safe_path=$(sanitize_path "$user_input")

    # Process safely
    echo "Processing: $safe_path"
    # ... your logic here ...
}

main "$@"

Compliance Standards (2025)

CIS Benchmarks

  • Use ShellCheck for automated compliance
  • Implement input validation on all user data
  • Secure temporary file handling
  • Least privilege execution

NIST Guidelines

  • Strong input validation (NIST SP 800-53)
  • Secure coding practices
  • Logging and monitoring
  • Access control enforcement

OWASP Top 10

  • A03: Injection - Prevent command injection
  • A01: Broken Access Control - Path validation
  • A02: Cryptographic Failures - Secure secrets

Resources


Security-first development is non-negotiable in 2025. Every script must pass all security checks before deployment.

More skills from JosiahSiegel

docker-git-bash-guide logo
JosiahSiegel/claude-plugin-marketplace

docker-git-bash-guide

Docker on Windows with Git Bash / MINGW path conversion. PROACTIVELY activate for: (1) Docker commands failing on Windows Git Bash with path errors, (2) volume mount path conversion (-v $(pwd):/app), (3) MSYS_NO_PATHCONV and MSYS2_ARG_CONV_EXCL workarounds, (4) double-slash escapes (//c/foo) for ...

58 0
View
vitest-3-features logo
JosiahSiegel/claude-plugin-marketplace

vitest-3-features

Vitest 3 features and migration from Vitest 2 (2025). PROACTIVELY activate for: (1) Vitest 3 stable features, (2) workspace mode for monorepos, (3) test annotations and reporter API, (4) projects configuration, (5) browser mode in Vitest 3, (6) inline snapshots and toMatchInlineSnapshot, (7) type...

58 0
View
windows-git-bash-paths logo
JosiahSiegel/claude-plugin-marketplace

windows-git-bash-paths

Windows and Git Bash path handling for SSDT, SqlPackage, and DACPAC files. PROACTIVELY activate for: (1) SqlPackage failing on Git Bash with path errors, (2) DACPAC file path conversion (MSYS, MINGW), (3) shell detection (PowerShell vs Git Bash) for SSDT scripts, (4) MSYS_NO_PATHCONV usage, (5) W...

58 0
View
debugging-troubleshooting-2025 logo
JosiahSiegel/claude-plugin-marketplace

debugging-troubleshooting-2025

Comprehensive bash script debugging and troubleshooting techniques for 2025. PROACTIVELY activate for: (1) debugging a misbehaving bash script, (2) using set -x, set -e, set -u, set -o pipefail (strict mode), (3) customizing PS4 for richer trace output, (4) trap DEBUG, ERR, and EXIT for diagnosti...

58 0
View
tailwindcss-accessibility logo
JosiahSiegel/claude-plugin-marketplace

tailwindcss-accessibility

Tailwind CSS accessibility patterns including WCAG 2.2 compliance, touch targets, focus management, and ARIA. PROACTIVELY activate for: (1) building accessible UI with Tailwind, (2) WCAG 2.2 compliance (Level A, AA, AAA), (3) focus rings and focus-visible styling, (4) minimum touch-target sizes (...

58 0
View
git-2-49-features logo
JosiahSiegel/claude-plugin-marketplace

git-2-49-features

Git 2.49 specific features and performance improvements. PROACTIVELY activate for: (1) git-backfill command (new in 2.49) for partial clones, (2) path-walk API improvements, (3) zlib-ng integration for faster compression, (4) reftables backend stabilization, (5) revision-walk performance, (6) bun...

58 0
View
sql-server-2025 logo
JosiahSiegel/claude-plugin-marketplace

sql-server-2025

SQL Server 2025 and SqlPackage 170.2.70 (October 2025) — vector databases, AI integration, and modern features. PROACTIVELY activate for: (1) SQL Server 2025 features, (2) vector type and vector indexes for AI, (3) Vector functions (VECTOR_DISTANCE, etc.), (4) AI integration (Azure OpenAI, embedd...

58 0
View
docker-security-guide logo
JosiahSiegel/claude-plugin-marketplace

docker-security-guide

Comprehensive Docker security guidelines and threat mitigation. PROACTIVELY activate for: (1) container security review, (2) running as non-root user, (3) read-only root filesystems and tmpfs mounts, (4) capability dropping (--cap-drop ALL), (5) seccomp and AppArmor profiles, (6) image vulnerabil...

58 0
View
powershell-security logo
JosiahSiegel/claude-plugin-marketplace

powershell-security

Modern PowerShell security practices for 2025 — SecretManagement, JEA, WDAC, credential protection. PROACTIVELY activate for: (1) Microsoft.PowerShell.SecretManagement and SecretStore for credential storage, (2) Just Enough Administration (JEA) endpoints, (3) Windows Defender Application Control ...

58 0
View
nextjs-middleware logo
JosiahSiegel/claude-plugin-marketplace

nextjs-middleware

Complete Next.js Middleware system (Next.js 15.5/16). PROACTIVELY activate for: (1) Creating middleware.ts (Edge) or proxy.ts (Node.js), (2) Matcher configuration, (3) Authentication protection, (4) Role-based access control, (5) Redirects and rewrites, (6) Internationalization (i18n), (7) Securi...

58 0
View
nextjs-data-fetching logo
JosiahSiegel/claude-plugin-marketplace

nextjs-data-fetching

Complete Next.js data fetching system (Next.js 15.5/16). PROACTIVELY activate for: (1) Server Component data fetching, (2) Parallel and sequential fetching, (3) Streaming with Suspense, (4) Route Handlers (API routes), (5) Client-side fetching with SWR/TanStack Query, (6) generateStaticParams for...

58 0
View
advanced-features-2025 logo
JosiahSiegel/claude-plugin-marketplace

advanced-features-2025

Advanced Claude Code plugin features for hooks, MCP integration, team distribution, and progressive disclosure. PROACTIVELY activate for: (1) progressive disclosure design, (2) hook automation, (3) PreToolUse and PostToolUse hooks, (4) MCP server integration, (5) .mcp.json configuration, (6) team...

58 0
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View