Find Security Holes While You Code, Not After You Ship

Vibe Coder · 1.12 · Vibe Coding Fundamentals

Back to Vibe Coder

The Problem

You finish a feature. Code review passes. QA approves. Then security team finds three critical vulnerabilities. Now you're rewriting authentication logic on Friday at 6pm because fixing security was left to the end.

The traditional approach: Security is a gate at the end. You build, then check for vulnerabilities.

This is backwards. By the time security reviews your code, you've already made architectural decisions. Ripping out insecure patterns means rewriting features, not tweaking them.

The Core Insight

Shift security left: find vulnerabilities while coding, not after deployment. Picture the project as a timeline running left to right — moving the security work toward the start is why the practice is called shift-left.

The earlier you catch security issues, the cheaper they are to fix. A vulnerability caught during coding may be a small edit; the same bug found during review can mean rework, and the same bug found in production can mean incident response, customer communications, and regulatory exposure.

AI is useful as an immediate first-pass reviewer: it can review code for security issues in real time as you write. It does not replace a security expert or automated scanning; it gives you a faster way to catch obvious mistakes before they harden into architecture.

The Shift-Left Workflow

Layer 1: Pre-Coding Security

Before writing code, ask AI about security implications. The example below is a login system built on signed identity tokens — a format known as JWT — and one of the answers heads off attacker script running in your users' browsers, an attack known as XSS:

Prompt: "I'm building a user authentication system with JWT tokens.
What are the top 5 security considerations I should handle upfront?"

AI Response:
1. Store JWT secret in environment variables, not code
2. Set token expiration (24h recommended)
3. Use HTTP-only cookies, not localStorage (XSS prevention)
4. Implement refresh token rotation
5. Add rate limiting to login endpoint

Why this works: You design security in, not bolt it on later.

Layer 2: During Coding (Real-Time Review)

As AI generates code, immediately ask for security review.

Workflow:
1. Ask AI to generate feature
2. AI provides code
3. Before accepting: "Review this code for security vulnerabilities"
4. AI points out issues
5. Fix issues in same session
6. Accept hardened code

Time added: 2-3 minutes per feature
Result: obvious issues caught before they become review or production work

The Security Sandwich Pattern

Generate → Review → Fix → Accept. Never skip the review layer. This becomes muscle memory after 10 iterations.

Layer 3: Post-Coding (Automated Scanning)

Run automated security tools before committing.

Tell your AI assistant: "Run a dependency vulnerability scan, a security-focused lint, a static analysis pass, and a secrets scan on this project, and summarize anything they find." Better still, have it wire the checks into a script git runs for you right before each commit lands — known as a pre-commit hook (Setup 1, below) — so they run automatically on every commit — you don't have to remember to run anything.

AI Security Review Prompts

Prompt 1: General Security Audit

"Perform a security audit of this code. Check for:
1. Input validation gaps
2. SQL/NoSQL injection risks
3. XSS vulnerabilities
4. Authentication/authorization issues
5. Secrets hardcoded in source
6. Timing attacks
7. Resource exhaustion (DoS)
8. Insecure dependencies

Provide severity (Critical/High/Medium/Low) for each finding."

Prompt 2: OWASP Top 10 Review

The security field keeps a ranked list of the ten most common ways web apps actually get broken into, known as the OWASP Top 10. Ask for a review against it by name:

"Review this code against OWASP Top 10 2021:
A01 Broken Access Control
A02 Cryptographic Failures
A03 Injection
A04 Insecure Design
A05 Security Misconfiguration
A06 Vulnerable Components
A07 Identification and Authentication Failures
A08 Software and Data Integrity Failures
A09 Security Logging Failures
A10 Server-Side Request Forgery

List any violations found."

Prompt 3: Threat Modeling

One question below asks what happens when two requests touch the same data at the same moment — a bug known as a race condition:

"Given this authentication endpoint:
[paste code]

Perform threat modeling:
1. What are possible attack vectors?
2. What happens if an attacker controls each input?
3. What are the trust boundaries?
4. What can go wrong with race conditions?
5. How could an attacker bypass this?

Think like a penetration tester."

Prompt 4: Language-Specific Security

Each language has its own classic traps: typed input that gets executed as a database command — the attack known as SQL injection; rebuilding live objects from stored bytes, a step called deserialization that runs attacker code when the bytes are hostile; and regular expressions an attacker can jam with a pathological input, known as ReDoS:

# Python-specific
"Review this Python code for:
- Pickle deserialization vulnerabilities
- SQL injection via f-strings
- Command injection via os.system()
- Path traversal in file operations
- Timing attacks in comparisons"

# JavaScript-specific
"Review this Node.js code for:
- Prototype pollution
- ReDoS in regex
- XSS via innerHTML
- JWT secret exposure
- NoSQL injection in MongoDB queries"

The Walkthrough: Secure Feature Development

Task: Add password reset functionality.

Phase 1: Design Review (Before Coding)

Prompt: "I need to implement password reset via email.
What security measures are essential?"

AI Response:
1. Generate cryptographically random tokens (32+ bytes)
2. Hash tokens before storing in database
3. Set token expiration (15-30 minutes)
4. Invalidate token after single use
5. Rate limit reset requests (prevent email bombing)
6. Don't reveal if email exists (timing attack prevention)
7. Log all reset attempts (security monitoring)

Great, now I know what to build.

Phase 2: Implementation with Real-Time Review

Prompt: "Generate password reset endpoint following those security requirements"

AI generates code...

Prompt: "Review this for vulnerabilities before I accept it"

AI: "Found 2 issues:
1. Token is not cryptographically random (using Math.random)
2. No rate limiting implemented
Fix these before shipping."

I fix issues, re-review, then accept.

Phase 3: Automated Pre-Commit Checks

Tell your assistant: "Commit this with the message 'Add password reset.'" Because of the pre-commit hook from Setup 1 below, the commit doesn't go through blind — the security checks run first, and you'll see something like:

Only then does the commit land. If any line shows a failure instead of a checkmark, the commit is blocked until you fix it — that's the hook doing its job.

Result: Secure feature shipped in first iteration. No security team escalation needed.

Automated Security Workflows

Setup 1: Pre-Commit Hooks

Tell your assistant: "Install husky and set up a pre-commit hook that blocks the commit if npm audit finds a high-severity vulnerability or the security lint fails." This is a one-time setup — once it's in place, every future commit gets checked automatically, whether or not you remember to ask.

If you're comfortable in a terminal yourself, this is npm install --save-dev husky then npx husky add .husky/pre-commit "npm run security-check", with a security-check script in package.json that runs npm audit && eslint . --ext .js --config .eslintrc.security.js.

Setup 2: CI/CD Security Gates

The same checks can run on a build server every time code is pushed — the automated build-test-release pipeline known as CI/CD:

# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run Snyk
        uses: snyk/actions/node@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
      - name: Run Semgrep
        uses: returntocorp/semgrep-action@v1
      - name: Check secrets
        uses: trufflesecurity/trufflehog@main

Setup 3: IDE Integration

# VS Code: Install extensions
- SonarLint (real-time security feedback)
- Snyk (dependency scanning)
- GitLens (see who wrote vulnerable code)

# Configure real-time security linting
# .vscode/settings.json
{
  "sonarlint.rules": {
    "javascript:S3330": { "level": "on" },  // Detect cipher weaknesses
    "javascript:S2068": { "level": "on" },  // Hard-coded credentials
    "javascript:S2092": { "level": "on" }   // Insecure cookie
  }
}

Don't Trust AI Blindly

AI can miss vulnerabilities. Always combine AI review with automated tools (Snyk, Semgrep, npm audit). Use AI as first pass, tools as verification.

Failure Patterns

1. Security Review After Feature Complete

Symptom: You build entire feature, then discover fundamental security issues.

Fix: Review security during design phase, not after coding.

2. Only Automated Scanning

Symptom: Tools pass, but logic flaws exist (business logic bypasses).

Fix: Combine automated tools with AI threat modeling prompts.

3. Ignoring Low Severity Issues

Symptom: "It's just low severity, we'll fix later." Never gets fixed.

Fix: Fix ALL issues before merging. Low severity stacks up.

Measuring Shift-Left Success

Metrics to track:

Stage Cost to Fix Shift-Left Impact
During coding Small edit (minutes) ✓ Main target
Code review Rework (hours) ✓ Backup catch
QA testing Late-cycle rework (days) Rare if shift-left works
Production Incident response (days to weeks) Should never happen

Quick Reference

Shift-Left Security Checklist:

[ ] Before Coding:

[ ] During Coding:

[ ] Before Committing:

[ ] In CI/CD:

Quick AI Security Prompt:

"Security review this code for:
- Input validation
- SQL/XSS injection
- Auth bypasses
- Hardcoded secrets
- DoS vulnerabilities

Be critical. What could an attacker exploit?"

Tools to Install Today:

Key Takeaways

What To Remember

Related Guides

Shift-left works best when you know what you're shifting. The other two parts of the security trio: