TL;DR: AI code assistants — Cursor, Claude Code, Windsurf, Copilot — are
reshaping how software gets built. But research shows 24–45% of AI-generated
code contains security vulnerabilities. This post breaks down the most common
patterns, why they happen, and exactly how to catch them before they hit production.
The Vibe Coding Revolution Has a Blind Spot
The way software gets built is shifting underneath us.
A developer who would have spent two weeks on a full-stack app can now ship it in
an afternoon. Prompting has become a core skill. Vibe coding — describing what
you want and letting AI write the implementation — is producing real, functional
products at a pace nobody predicted.
But there's a pattern emerging that deserves attention.
In early 2025, researchers at Stanford found that developers using AI assistants
produced code with more security vulnerabilities than those writing manually —
and were more confident their code was secure. A separate study from the University
of Montreal found that roughly 45% of LLM-generated code contains vulnerabilities.
This isn't theoretical. AI-built projects are going to production every day — some
handling payments, some storing health data, some managing auth for thousands of users.
The AI that wrote the code doesn't audit the code. That gap is where things break.
The 7 Most Common Vulnerability Patterns in AI-Generated Code
After analyzing scan results from AI-built projects across multiple languages and
frameworks, these are the patterns that show up repeatedly.
1. 🔑 Hardcoded Secrets and API Keys
The single most common finding. AI assistants generate configuration examples with
placeholder values that developers replace with real credentials — and forget to
move to environment variables.
// ❌ AI-generated — don't ship this
const db = new Client({
host: 'db.example.com',
user: 'admin',
password: 'sk_live_abc123actualkey', // CWE-798
database: 'production'
});
Why AI does this: LLMs learn from codebases that include config examples. The
model doesn't distinguish between a placeholder and a real secret — it generates
the pattern it's seen most often.
Fix it:
// ✅ Always use environment variables
const db = new Client({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME
});
Run a secrets scanner before every commit using a pre-commit hook:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
Tools like SafeWeave detect hardcoded secrets as part
of a full SAST scan — directly inside your AI coding session via MCP.
2. 💉 SQL Injection via String Concatenation
AI frequently generates SQL using template literals instead of parameterized queries
— especially for simple CRUD operations.
# ❌ Injectable — never do this
@app.route('/search')
def search():
query = request.args.get('q')
results = db.execute(f"SELECT * FROM products WHERE name LIKE '%{query}%'")
return jsonify(results)
Why AI does this: String interpolation is more concise. LLMs optimize for
readable, compact code. Parameterized queries require more boilerplate the model
skips unless you explicitly ask for security.
Fix it:
# ✅ Parameterized query
@app.route('/search')
def search():
query = request.args.get('q')
results = db.execute(
"SELECT * FROM products WHERE name LIKE %s",
(f"%{query}%",)
)
return jsonify(results)
Rule of thumb: If you see a variable interpolated directly into a SQL string
across any language or ORM — it's injectable.
3. 🔓 Missing Authentication on Sensitive Endpoints
When you prompt AI to "build a REST API for managing users," it generates the CRUD
routes. What it frequently skips: auth middleware, authorization checks, and RBAC.
// ❌ No auth — any request can delete any user
router.delete('/api/users/:id', async (req, res) => {
await db.query('DELETE FROM users WHERE id = $1', [req.params.id]);
res.json({ deleted: true });
});
Why AI does this: The prompt said "build a user management API." It didn't say
"with authentication." LLMs are literal — they build exactly what you ask for.
Fix it:
// ✅ Explicit auth + role check on every destructive route
router.delete('/api/users/:id', requireAuth, requireRole('admin'), async (req, res) => {
await db.query('DELETE FROM users WHERE id = $1', [req.params.id]);
res.json({ deleted: true });
});
Audit rule: Every endpoint that reads, writes, or deletes data needs explicit
auth checks. No exceptions.
4. 📁 Path Traversal in File Operations
AI-generated file handlers frequently trust user-supplied filenames without sanitization.
// ❌ Path traversal — ?file=../../../etc/passwd reads any file
app.get('/download', (req, res) => {
const filename = req.query.file;
res.sendFile(path.join(__dirname, 'uploads', filename)); // CWE-22
});
Why AI does this: The model generates the "happy path." File operations work
correctly with normal input — it doesn't reason about adversarial inputs unless prompted.
Fix it:
// ✅ Strip traversal + verify resolved path
app.get('/download', (req, res) => {
const filename = path.basename(req.query.file);
const filePath = path.join(__dirname, 'uploads', filename);
if (!filePath.startsWith(path.resolve(__dirname, 'uploads'))) {
return res.status(403).json({ error: 'Access denied' });
}
res.sendFile(filePath);
});
5. 🕸️ Cross-Site Scripting (XSS) via Unsanitized Output
AI frequently renders user input directly into HTML without escaping — common in
server-side rendering and API responses feeding frontend templates.
# ❌ Reflected XSS — CWE-79
@app.route('/profile/<username>')
def profile(username):
user = get_user(username)
return f"<h1>Welcome, {user.display_name}</h1>"
If display_name contains a <script> tag — it executes in the browser.
Fix it:
# ✅ Escape user input before rendering
from markupsafe import escape
@app.route('/profile/<username>')
def profile(username):
user = get_user(username)
return f"<h1>Welcome, {escape(user.display_name)}</h1>"
Better yet — use templating engines (Jinja2, EJS, Handlebars) that auto-escape by
default.
6. 📦 Vulnerable Dependencies
When AI suggests npm install <package>, it recommends the version it was trained
on — potentially months or years old, with known CVEs.
{
"dependencies": {
"lodash": "4.17.20",
"jsonwebtoken": "8.5.1",
"axios": "0.21.1"
}
}
All three of these have known vulnerabilities:
| Package | Version | Vulnerability |
|---|---|---|
lodash |
4.17.20 | Prototype pollution (CVE-2021-23337) |
jsonwebtoken |
8.5.1 | Algorithm confusion attacks |
axios |
0.21.1 | SSRF vulnerability |
Why AI does this: The model has a training cutoff. It recommends whatever version
was most prevalent in the training corpus — it can't check a CVE database at generation
time.
Fix it:
# Run after every AI-suggested package install
npm audit
pip audit
cargo audit
7. 🐳 Insecure Infrastructure Defaults
AI-generated Dockerfiles, Terraform configs, and Kubernetes manifests produce
minimal configurations that work — but lack security hardening.
# ❌ Insecure defaults
FROM node:18
WORKDIR /app
COPY . .
RUN npm install
EXPOSE 3000
CMD ["node", "server.js"]
Problems with this:
- Runs as
root(noUSERdirective) - Copies everything including
.env,.git,node_modules - Uses full
node:18image (larger attack surface) - No health check defined
Fix it:
# ✅ Hardened multi-stage build
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM node:18-alpine
RUN addgroup -S app && adduser -S app -G app
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
USER app
EXPOSE 3000
HEALTHCHECK CMD wget -q --spider http://localhost:3000/health || exit 1
CMD ["node", "server.js"]
The same applies to Terraform (S3 buckets with public access on by default),
Kubernetes (containers running as privileged), and CloudFormation templates.
SafeWeave scans IaC configs alongside your application
code — catching misconfigurations before they reach your cloud environment.
Why Traditional Security Tools Miss This Workflow
The standard AppSec toolchain was built for a different era:
| Problem | Impact |
|---|---|
| CI/CD-only scanners | By the time you see the report, you've moved on. The cognitive distance between writing code and fixing it is huge. |
| Dashboard-heavy tools | Log in → navigate → find the finding → understand context → switch back to editor → find the line → fix it. Kills solo-dev momentum. |
| Enterprise pricing | $25–35/dev/month for a solo developer building a SaaS is the wrong model. |
| Manual review | Doesn't scale when AI generates 500 lines from a single prompt. |
The gap is real-time, in-editor security scanning that fits the AI-assisted coding
workflow. Tools that plug into the same MCP interface AI assistants use — so
scanning happens inside the conversation, not in a separate window.
SafeWeave is built specifically for this workflow: MCP-native
security scanning that runs SAST, secrets detection, dependency analysis, and IaC
checks directly inside Cursor, Claude Code, or Windsurf — without ever leaving
your editor.
A Practical Security Checklist for AI-Built Projects
Run this before every production deploy.
✅ Authentication & Authorization
- [ ] Every API endpoint has explicit auth middleware
- [ ] Admin routes require role-based access control
- [ ] JWT secrets are stored in environment variables, not code
- [ ] Session tokens have expiration dates
- [ ] Password reset tokens are single-use and time-limited
✅ Input Validation
- [ ] All SQL queries use parameterized statements
- [ ] File paths are sanitized against directory traversal
- [ ] User input is escaped before rendering in HTML
- [ ] Request body size limits are configured
- [ ] File upload types and sizes are restricted
✅ Secrets Management
- [ ] No API keys, passwords, or tokens in source code
- [ ]
.envfiles are in.gitignore - [ ] No secrets in
Dockerfile ENVorARGinstructions - [ ] No secrets in client-side JavaScript bundles
- [ ] Git history doesn't contain previously committed secrets
✅ Dependencies
- [ ]
npm audit/pip audit/cargo auditruns clean - [ ] No dependencies with known critical CVEs
- [ ] Lock files are committed and up to date
- [ ] No unnecessary AI-suggested packages
✅ Infrastructure
- [ ] Containers don't run as root
- [ ]
.dockerignoreexcludes.env,.git,node_modules - [ ] HTTPS enforced — no HTTP fallback in production
- [ ] CORS configured to allow only specific origins
- [ ] Rate limiting on authentication endpoints
- [ ] Security headers set: CSP, HSTS, X-Frame-Options
✅ Data Protection
- [ ] Sensitive data encrypted at rest
- [ ] Database connections use TLS
- [ ] Logging doesn't include passwords, tokens, or PII
- [ ] Error messages don't expose stack traces to users
Automating Security in the AI Coding Workflow
The most effective approach integrates scanning at three layers:
Layer 1: In-Editor (Real-Time)
↓ catches ~80% of issues immediately
Layer 2: Pre-Commit Hooks
↓ catches secrets before they enter git history
Layer 3: CI Pipeline
↓ catches anything that slipped through
Layer 1 — In-Editor, Real-Time
MCP-compatible security scanners run inside AI code editors. When you prompt your
assistant to scan a project, it runs SAST, secrets detection, and dependency analysis
right in the conversation — findings appear immediately, and you fix them in the same
session.
SafeWeave was designed for exactly this layer — an MCP
server that connects to Cursor, Claude Code, and Windsurf so security becomes part
of the coding conversation, not an afterthought.
Layer 2 — Pre-Commit Hooks
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
Once a secret is committed, it lives in git history forever — even if you delete
it in a later commit.
Layer 3 — CI Pipeline
# GitHub Actions
- name: Security Scan
run: |
npm audit --audit-level=high
npx semgrep --config auto .
The three layers create defense in depth. Most vulnerabilities get caught at Layer 1
before they're even committed.
Compliance Considerations
AI-generated code doesn't get a compliance pass:
| Standard | Requirement |
|---|---|
| SOC 2 | Evidence of vulnerability testing — scan reports serve as audit artifacts |
| PCI-DSS v4.0 | Static and dynamic SAST required for any system handling payment data |
| HIPAA | Security risk analysis required for systems handling PHI — that includes code-level vulns |
| GDPR | "Appropriate technical measures" for data protection — SQL injection in a user endpoint is the opposite |
Security scanners that map findings directly to compliance controls (OWASP Top 10,
SOC 2, PCI-DSS, HIPAA, NIST 800-53) make audits significantly easier — you produce
a report showing findings mapped to specific controls, not a generic vulnerability list.
The Economics: Security Is Cheaper Than a Breach
| Scenario | Cost |
|---|---|
| Average small business data breach | $120,000–$150,000 |
| Fixing a bug in development vs. production | 6x cheaper in dev (IBM research) |
| Finding a SQL injection in your editor | ~5 minutes |
| Finding it after exploitation | The weekend — plus your users' data |
| Running a full security scan | 10–15 seconds |
Open source scanners (Semgrep, Gitleaks, npm audit, Trivy, Checkov) are free.
MCP-integrated tools like SafeWeave offer free tiers for
individual developers. Enterprise-grade security no longer requires enterprise budgets.
Conclusion
AI-assisted coding is the future. The productivity gains are real. But productivity
without security produces technical debt that compounds with interest.
The good news: securing AI-generated code doesn't require a dedicated security team
or a six-figure tooling budget. It requires:
- Awareness of the vulnerability patterns AI consistently produces
- Automated scanning integrated into your existing workflow
- A checklist mentality — verify before you deploy
The tools exist. The patterns are well-documented.
The only question is whether you scan before your users do.
Top comments (0)