# Vulnerability Remediation Guide Security remediation patterns organized by vulnerability category. ## Table of Contents - [SQL Injection](#sql-injection) - [Cross-Site Scripting (XSS)](#cross-site-scripting-xss) - [Command Injection](#command-injection) - [Path Traversal](#path-traversal) - [Insecure Deserialization](#insecure-deserialization) - [Weak Cryptography](#weak-cryptography) - [Authentication & Session Management](#authentication--session-management) - [CSRF](#csrf) - [SSRF](#ssrf) - [XXE](#xxe) ## SQL Injection ### Vulnerability Pattern ```python # VULNERABLE query = f"SELECT * FROM users WHERE id = {user_id}" cursor.execute(query) ``` ### Secure Remediation ```python # SECURE: Use parameterized queries query = "SELECT * FROM users WHERE id = %s" cursor.execute(query, (user_id,)) # Or use ORM user = User.objects.get(id=user_id) ``` ### Framework-Specific Solutions **Django:** ```python # Use Django ORM (safe by default) User.objects.filter(email=user_email) # For raw SQL, use parameterized queries User.objects.raw('SELECT * FROM myapp_user WHERE email = %s', [user_email]) ``` **Node.js (Sequelize):** ```javascript // Use parameterized queries User.findAll({ where: { email: userEmail } }); // Or use replacements sequelize.query( 'SELECT * FROM users WHERE email = :email', { replacements: { email: userEmail } } ); ``` **Java (JDBC):** ```java // Use PreparedStatement String query = "SELECT * FROM users WHERE id = ?"; PreparedStatement stmt = conn.prepareStatement(query); stmt.setInt(1, userId); ResultSet rs = stmt.executeQuery(); ``` ## Cross-Site Scripting (XSS) ### Vulnerability Pattern ```javascript // VULNERABLE element.innerHTML = userInput; document.write(userInput); ``` ### Secure Remediation ```javascript // SECURE: Use textContent for text element.textContent = userInput; // Or properly escape HTML element.innerHTML = escapeHtml(userInput); function escapeHtml(unsafe) { return unsafe .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } ``` ### Framework-Specific Solutions **React:** ```javascript // React auto-escapes by default
{userInput}
// For HTML content, sanitize first import DOMPurify from 'dompurify';
``` **Flask/Jinja2:** ```python # Templates auto-escape by default {{ user_input }} # For HTML content, sanitize from markupsafe import Markup import bleach {{ Markup(bleach.clean(user_input)) }} ``` **Django:** ```django {# Auto-escaped by default #} {{ user_input }} {# Mark as safe only after sanitization #} {{ user_input|safe }} ``` ## Command Injection ### Vulnerability Pattern ```python # VULNERABLE os.system(f"ping {user_host}") subprocess.call(f"ls {user_directory}", shell=True) ``` ### Secure Remediation ```python # SECURE: Use subprocess with list arguments import subprocess subprocess.run(['ping', '-c', '1', user_host], capture_output=True, check=True) # Validate input against allowlist import shlex if not re.match(r'^[a-zA-Z0-9.-]+$', user_host): raise ValueError("Invalid hostname") subprocess.run(['ping', '-c', '1', user_host]) ``` **Node.js:** ```javascript // VULNERABLE exec(`ls ${userDir}`); // SECURE const { execFile } = require('child_process'); execFile('ls', [userDir], (error, stdout) => { // Handle output }); ``` ## Path Traversal ### Vulnerability Pattern ```python # VULNERABLE file_path = os.path.join('/uploads', user_filename) with open(file_path) as f: return f.read() ``` ### Secure Remediation ```python # SECURE: Validate and normalize path import os from pathlib import Path def safe_join(directory, user_path): # Normalize and resolve path base_dir = Path(directory).resolve() file_path = (base_dir / user_path).resolve() # Ensure it's within base directory if not str(file_path).startswith(str(base_dir)): raise ValueError("Path traversal detected") return file_path try: safe_path = safe_join('/uploads', user_filename) with open(safe_path) as f: return f.read() except ValueError: return "Invalid filename" ``` ## Insecure Deserialization ### Vulnerability Pattern ```python # VULNERABLE import pickle data = pickle.loads(user_data) ``` ### Secure Remediation ```python # SECURE: Use safe formats like JSON import json data = json.loads(user_data) # If you must deserialize, validate and restrict import yaml data = yaml.safe_load(user_data) # Use safe_load, not load ``` **Node.js:** ```javascript // VULNERABLE const data = eval(userInput); const obj = Function(userInput)(); // SECURE const data = JSON.parse(userInput); // For complex objects, use schema validation const Joi = require('joi'); const schema = Joi.object({ name: Joi.string().required(), email: Joi.string().email().required() }); const { value, error } = schema.validate(JSON.parse(userInput)); ``` ## Weak Cryptography ### Vulnerability Pattern ```python # VULNERABLE import hashlib password_hash = hashlib.md5(password.encode()).hexdigest() ``` ### Secure Remediation ```python # SECURE: Use bcrypt or argon2 import bcrypt # Hashing password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt()) # Verification if bcrypt.checkpw(password.encode(), stored_hash): print("Password correct") # Or use argon2 from argon2 import PasswordHasher ph = PasswordHasher() hash = ph.hash(password) ph.verify(hash, password) ``` **Encryption:** ```python # VULNERABLE from Crypto.Cipher import DES cipher = DES.new(key, DES.MODE_ECB) # SECURE: Use AES-GCM from cryptography.hazmat.primitives.ciphers.aead import AESGCM import os key = AESGCM.generate_key(bit_length=256) aesgcm = AESGCM(key) nonce = os.urandom(12) ciphertext = aesgcm.encrypt(nonce, plaintext, associated_data) ``` ## Authentication & Session Management ### Vulnerability Pattern ```javascript // VULNERABLE app.use(session({ secret: 'weak-secret', cookie: { secure: false } })); ``` ### Secure Remediation ```javascript // SECURE const session = require('express-session'); app.use(session({ secret: process.env.SESSION_SECRET, // Strong random secret resave: false, saveUninitialized: false, cookie: { secure: true, // HTTPS only httpOnly: true, // No JavaScript access sameSite: 'strict', // CSRF protection maxAge: 3600000 // 1 hour } })); ``` **Password Requirements:** ```python # Implement strong password policy import re def validate_password(password): if len(password) < 12: return False if not re.search(r'[A-Z]', password): return False if not re.search(r'[a-z]', password): return False if not re.search(r'[0-9]', password): return False if not re.search(r'[!@#$%^&*(),.?":{}|<>]', password): return False return True ``` ## CSRF ### Vulnerability Pattern ```python # VULNERABLE: No CSRF protection @app.route('/transfer', methods=['POST']) def transfer(): amount = request.form['amount'] to_account = request.form['to'] # Process transfer ``` ### Secure Remediation ```python # SECURE: Use CSRF tokens from flask_wtf.csrf import CSRFProtect csrf = CSRFProtect(app) @app.route('/transfer', methods=['POST']) @csrf.exempt # Only if using custom CSRF def transfer(): # CSRF token automatically validated amount = request.form['amount'] to_account = request.form['to'] ``` **Express.js:** ```javascript const csrf = require('csurf'); const csrfProtection = csrf({ cookie: true }); app.post('/transfer', csrfProtection, (req, res) => { // CSRF token validated const { amount, to } = req.body; }); ``` ## SSRF ### Vulnerability Pattern ```python # VULNERABLE import requests url = request.args.get('url') response = requests.get(url) ``` ### Secure Remediation ```python # SECURE: Validate URLs and use allowlist import requests from urllib.parse import urlparse ALLOWED_DOMAINS = ['api.example.com', 'cdn.example.com'] def safe_fetch(url): parsed = urlparse(url) # Check protocol if parsed.scheme not in ['http', 'https']: raise ValueError("Invalid protocol") # Check domain against allowlist if parsed.netloc not in ALLOWED_DOMAINS: raise ValueError("Domain not allowed") # Block internal IPs import ipaddress try: ip = ipaddress.ip_address(parsed.hostname) if ip.is_private: raise ValueError("Private IP not allowed") except ValueError: pass # Not an IP, continue return requests.get(url, timeout=5) ``` ## XXE ### Vulnerability Pattern ```python # VULNERABLE from lxml import etree tree = etree.parse(user_xml) ``` ### Secure Remediation ```python # SECURE: Disable external entities from lxml import etree parser = etree.XMLParser( resolve_entities=False, no_network=True, dtd_validation=False ) tree = etree.parse(user_xml, parser) # Or use defusedxml from defusedxml import ElementTree tree = ElementTree.parse(user_xml) ``` **Node.js:** ```javascript // Use secure XML parser const libxmljs = require('libxmljs'); const xml = libxmljs.parseXml(userXml, { noent: false, // Disable entity expansion dtdload: false, dtdvalid: false }); ``` ## General Security Principles 1. **Input Validation**: Validate all user input against expected format 2. **Output Encoding**: Encode output based on context (HTML, URL, SQL, etc.) 3. **Least Privilege**: Grant minimum necessary permissions 4. **Defense in Depth**: Use multiple layers of security controls 5. **Fail Securely**: Ensure failures don't expose sensitive data 6. **Secure Defaults**: Use secure configuration by default 7. **Keep Dependencies Updated**: Regularly update libraries and frameworks ## Testing Remediation After applying fixes: 1. **Verify with Semgrep**: Re-scan to ensure vulnerability is resolved ```bash semgrep --config fixed_file.py ``` 2. **Manual Testing**: Attempt to exploit the vulnerability 3. **Code Review**: Have peer review the fix 4. **Integration Tests**: Add tests to prevent regression ## References - [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/) - [CWE Mitigations](https://cwe.mitre.org/) - [Semgrep Autofix](https://semgrep.dev/docs/writing-rules/autofix/)