Chapter 27: Key Takeaways — Security-First Development

Summary Card

  1. AI-generated code is not inherently secure. AI models learn from training data that includes insecure patterns. Research shows AI code-generation tools produce security vulnerabilities 25-40% of the time in security-sensitive functions. Every piece of AI-generated code must be reviewed through a security lens before acceptance.

  2. Always prefer whitelist validation over blacklist validation. Define exactly what inputs are acceptable and reject everything else. Blacklists are inherently incomplete because attackers continuously discover new encodings and bypasses. Use Pydantic for schema-based validation of complex data structures.

  3. Never build SQL queries with string formatting. Always use parameterized queries (prepared statements) that separate SQL code from data. This rule has zero exceptions. When using ORMs, verify that any raw SQL fallbacks are also parameterized.

  4. Output encoding is the primary defense against XSS. Use template engines with auto-escaping enabled (the default in Jinja2/Flask). Reinforce this defense with Content Security Policy (CSP) headers, especially script-src 'self' to block inline script execution.

  5. Use slow, salted hash functions for passwords. Never use MD5, SHA-256, or other fast hash algorithms for password storage. Use bcrypt (work factor 12+), Argon2id, or scrypt. These algorithms are deliberately slow, making brute-force attacks impractical.

  6. Keep JWTs short-lived and validate them strictly. Access tokens should expire in 15-60 minutes. Always specify an explicit algorithm list to prevent algorithm confusion attacks. Validate expiration, issuer, and token type. Never include "none" in the allowed algorithms.

  7. Default to deny in all authorization decisions. If no rule explicitly grants access, the request must be rejected. Protect against IDOR by verifying that the authenticated user owns or has permission to access the specific resource, not just any resource of that type.

  8. Never hardcode secrets in source code. Use environment variables as the minimum standard for development and dedicated secret managers (AWS Secrets Manager, HashiCorp Vault) for production. Add pre-commit hooks with tools like gitleaks or detect-secrets to catch secrets before they enter version control.

  9. If a secret is exposed, rotate it immediately. Do not wait to fix the code or clean git history. Generate new credentials, revoke the old ones, audit access logs, then address the root cause. Every minute a compromised secret is active is a window for an attacker.

  10. Pin dependency versions and audit them regularly. Use exact version pinning in production requirements files. Run pip-audit and Safety regularly to detect known vulnerabilities. Configure Dependabot or Renovate for automated security update pull requests.

  11. Layer your defenses (defense in depth). No single security control should be your only protection. Combine input validation, parameterized queries, output encoding, CSP headers, authentication, authorization, and monitoring. If one layer fails, others catch the attack.

  12. Use AI as a security ally, not just a code generator. Prompt AI assistants to perform security-focused code reviews, generate security test cases, and plan penetration tests. Combine AI review with automated tools like Bandit and Semgrep for comprehensive coverage.

  13. Integrate security into CI/CD. Run Bandit (code security), pip-audit (dependency vulnerabilities), and secret scanners automatically on every commit. Make security checks blocking — a failed security scan should prevent deployment.

  14. Maintain a living security checklist. Customize the security checklist from Section 27.10 for your project. Cover input validation, database security, authentication, authorization, secrets management, HTTP headers, dependencies, and AI-specific concerns. Automate as many checks as possible.

  15. The three pillars guide every decision. Never trust, always verify. Least privilege. Defense in depth. Apply these principles to every function, every endpoint, and every AI-generated code snippet you accept into your codebase.