--- name: security-audit description: "Detect common security vulnerabilities in code. Covers OWASP patterns, SQL injection, bare excepts, shell injection. Framework-agnostic." --- # Security Audit Skill Detect common security vulnerabilities during code review and development. Based on OWASP guidelines and common vulnerability patterns. ## Design Principle This skill is **framework-generic**. It provides universal security patterns: - Covers OWASP Top 10 and common CWEs - Works with Python, TypeScript, and other languages - Project-specific security requirements go in project-specific skills ## Variables | Variable | Default | Description | |----------|---------|-------------| | SEVERITY_THRESHOLD | medium | Minimum severity to report | | SCAN_DEPTH | 3 | Directory depth for scanning | | INCLUDE_TESTS | false | Include test files in scan | ## Instructions **MANDATORY** - Follow the Workflow steps below in order. 1. Identify security-sensitive code areas 2. Check for common vulnerability patterns 3. Report findings with severity 4. Suggest remediation ## Red Flags - STOP and Reconsider If you're about to: - Write SQL with string concatenation - Use bare `except:` blocks - Execute shell commands with user input - Store secrets in code - Disable security features "temporarily" **STOP** -> Use parameterized queries -> Add specific exception handling -> Then proceed ## Cookbook ### SQL Injection Prevention - IF: Writing database queries - THEN: Read and execute `./cookbook/sql-injection.md` ### Bare Except Handling - IF: Writing exception handlers - THEN: Read and execute `./cookbook/bare-except.md` ### Shell Injection Prevention - IF: Executing shell commands - THEN: Read and execute `./cookbook/shell-injection.md` ## Vulnerability Patterns ### SQL Injection (CWE-89) **BAD - String concatenation:** ```python # VULNERABLE query = f"SELECT * FROM users WHERE id = {user_id}" cursor.execute(query) query = "SELECT * FROM users WHERE name = '" + name + "'" ``` **GOOD - Parameterized queries:** ```python # SAFE cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)) # SQLAlchemy session.query(User).filter(User.id == user_id).first() # Prisma await prisma.user.findUnique({ where: { id: userId } }) ``` ### Bare Except (CWE-754) **BAD - Catches everything:** ```python # VULNERABLE - hides bugs, catches KeyboardInterrupt try: risky_operation() except: pass # VULNERABLE - too broad except Exception: log.error("Something failed") ``` **GOOD - Specific exceptions:** ```python # SAFE - specific exceptions try: risky_operation() except ValueError as e: log.warning(f"Invalid value: {e}") except ConnectionError as e: log.error(f"Connection failed: {e}") raise ``` ### Shell Injection (CWE-78) **BAD - User input in shell:** ```python # VULNERABLE os.system(f"grep {user_input} /var/log/app.log") import subprocess subprocess.run(f"ls {directory}", shell=True) ``` **GOOD - Avoid shell, use lists:** ```python # SAFE - no shell subprocess.run(["grep", user_input, "/var/log/app.log"]) # SAFE - validated input if not re.match(r'^[a-zA-Z0-9_-]+$', directory): raise ValueError("Invalid directory name") subprocess.run(["ls", directory]) ``` ### Path Traversal (CWE-22) **BAD - User input in paths:** ```python # VULNERABLE path = f"/uploads/{user_filename}" with open(path) as f: return f.read() ``` **GOOD - Validate and sanitize:** ```python # SAFE from pathlib import Path upload_dir = Path("/uploads").resolve() requested = (upload_dir / user_filename).resolve() if not requested.is_relative_to(upload_dir): raise ValueError("Path traversal attempt") with open(requested) as f: return f.read() ``` ### Hardcoded Secrets (CWE-798) **BAD - Secrets in code:** ```python # VULNERABLE API_KEY = "sk-1234567890abcdef" DB_PASSWORD = "super_secret_password" ``` **GOOD - Environment variables:** ```python # SAFE import os API_KEY = os.environ["API_KEY"] DB_PASSWORD = os.environ["DB_PASSWORD"] # Or with defaults for development API_KEY = os.getenv("API_KEY", "dev-key-only") ``` ### XSS (CWE-79) **BAD - Unsanitized output:** ```html