In February 2026, a social network for AI agents called Moltbook became briefly famous — autonomous bots posting, forming cults, ranting about humans. Fascinating experiment. Then Wiz published their findings: 1.5 million API keys and 35,000 user email addresses sitting in a publicly accessible Supabase database. The founder had built the entire platform using vibe coding. He said publicly he had written zero lines of code himself. The misconfigured database wasn't a sophisticated attack. The AI scaffolded it with permissive defaults during development. Nobody reviewed the infrastructure code. It shipped as-is.
That's the story of vibe coding security in 2026. Not theoretical. Not edge cases. A pattern that's showing up across every platform, every tool, every team that's shipping AI-generated code without building a security system around it.
This post covers what the data actually shows — not vendor reports trying to sell you something, but Georgia Tech research, Veracode's LLM testing, and documented incidents. Then it gets into the policy-as-code layer: what you can enforce in CI/CD pipelines, what OPA can gate, and what Semgrep rules catch the vulnerability classes AI generates most consistently.
In this post
- What vibe coding actually is (and isn't)
- The data: what AI-generated code gets wrong
- Three real incidents that show the pattern
- The six vulnerability classes AI generates consistently
- Why SAST alone doesn't solve this
- Policy-as-code defenses: CI/CD gates, OPA, Semgrep
- The actual problem nobody wants to say out loud
What vibe coding actually is (and isn't)
Andrej Karpathy coined the term in February 2025. His framing was specific: "fully give in to the vibes, embrace exponentials, and forget that the code even exists." That last part matters. It's not AI-assisted coding — senior engineers carefully reviewing every diff, understanding the logic, treating the LLM as a fast typist. Vibe coding, as originally defined, is the opposite: describe what you want, accept what comes out, move on. Collins English Dictionary named it Word of the Year for 2025, which tells you something about how fast the concept spread beyond technical circles.
By Q1 2026, Gartner was forecasting 60% of all new code would be AI-generated by year end. Y Combinator's Winter 2025 cohort had 25% of startups with codebases that were 95% AI-generated. GitHub reports 46% of new code on its platform is already AI-assisted. The speed benefits are real — teams report two to five times faster feature delivery. That part of the promise delivered.
What didn't deliver: security. "It works" and "it's safe" are different standards. AI code generation optimizes hard for the first one.
The data: what AI-generated code gets wrong
Several independent research efforts have now converged on similar findings. Worth going through them rather than cherry-picking the scariest number.
Veracode tested over 100 large language models across 80 coding tasks in Java, Python, C#, and JavaScript. The tasks focused on four vulnerability categories: SQL injection, XSS, log injection, and insecure cryptographic algorithms. Overall, 45% of AI-generated code samples failed security tests. Java performed worst at 72%. Cross-site scripting failures hit 86% — meaning 86 out of 100 generated samples left XSS vectors open. Log injection was 88%. These aren't edge-case attack classes. They're OWASP Top 10 staples that have been understood for decades. And the March 2026 update, headlined "Despite Claims, AI Models Are Still Failing Security," found the pass rate unchanged from the previous cycle despite significant improvements in functional coding benchmarks.
CodeRabbit analyzed 470 open-source GitHub pull requests and found AI-co-authored code contains security vulnerabilities at 2.74 times the rate of human-written code. Misconfigurations were 75% more frequent. Logic errors more common throughout. A separate Q1 2026 assessment of 200+ vibe-coded applications found 91.5% had at least one vulnerability traceable to AI hallucination.
Georgia Tech's Systems Software and Security Lab launched the Vibe Security Radar in May 2025 specifically to track CVEs attributable to AI-generated code. Their methodology: pull from CVE.org, NVD, GitHub Advisory Database, and OSV; trace each CVE's fixing commit back through git history; determine whether an AI coding tool introduced the vulnerable code. The trend line is not subtle. January 2026: 6 CVEs. February: 15. March: 35. Researchers estimate the actual count is 5 to 10 times higher across the broader ecosystem because most AI-introduced vulnerabilities never get a CVE at all — they're quietly fixed or never found.
One more number that deserves attention
A 2025 IEEE-ISTAS controlled experiment measured what happens when you iterate on AI-generated code. After just five rounds of AI-assisted refinement, critical vulnerabilities increased by 37.6%. Iterating on AI output does not self-correct security flaws. It compounds them. This is the thing that makes vibe coding different from a standard bug class — the workflow itself makes the underlying problem worse over time.
Three real incidents that show the pattern
The statistics above are accurate but abstract. The incidents are where it becomes concrete.
Moltbook — 1.5 million API keys, February 2026
Already mentioned in the intro, but worth the technical detail. The founder built a social network for autonomous AI agents — genuinely novel concept — entirely through vibe coding. The AI scaffolded a Supabase database with public read and write access during development. Development defaults, not production configuration. The founder, having not reviewed the infrastructure code because the whole point was not reviewing infrastructure code, deployed it as-is. Wiz discovered the exposure: 1.5 million API keys and 35,000 user email addresses. The database was publicly readable and writable. The root cause wasn't a sophisticated attack technique. It was a default that a human developer with database experience would have caught on first review.
Lovable — BOLA vulnerability, 48 days open
Lovable is a vibe coding platform valued at $6.6 billion with eight million users. In early 2026 they had three documented security incidents over a two-month period, collectively exposing source code, database credentials, AI chat histories, and personal data across thousands of projects. The most damaging was a Broken Object Level Authorization (BOLA) vulnerability — a security researcher reported it through HackerOne. The report was closed without escalation because HackerOne partners determined that "seeing public projects' chats was the intended behaviour." The vulnerability stayed open for 48 days after initial report. When it finally got addressed, the patch applied to new users but not existing projects. The company's public response involved, in sequence: denying a breach occurred, blaming unclear documentation, blaming HackerOne, then a partial apology. The security researcher's write-up got more traffic than the apology.
The pickle module problem — not an incident, a pattern
This one's different because it wasn't a breach — it was caught in review. A team asked Claude Code to build a multiplayer snake game. The AI-generated network layer used Python's pickle module to serialize and deserialize game objects. The app ran correctly. Looked fine. The vulnerability was invisible to anyone who didn't already know that pickle deserialization from untrusted sources enables arbitrary remote code execution — a well-documented class that's been in security literature for years. The fix was trivial: switch from pickle to JSON. But only once someone in the review caught it. The point isn't that AI chose wrong — it's that the AI chose an approach that optimized for "makes the game work" and the security implication was invisible in the output.
The six vulnerability classes AI generates consistently
These aren't random. Research across multiple studies shows AI coding tools produce the same vulnerability patterns repeatedly, because they're optimizing for the same things: make the feature work, follow the patterns most common in training data, minimize friction for the user's stated goal. Security is a non-functional requirement the models treat as secondary.
Hardcoded credentials
AI-assisted commits introduce secrets at 3.2% versus a 1.5% baseline for human-only code — a 2x increase. Invicti analyzed 20,000 vibe-coded applications and found that the string supersecretkey appeared in 1,182 of them. A predictable JWT secret lets an attacker forge admin tokens. That's a complete authentication bypass. Not a CVSS 4 information disclosure. GitGuardian counted 28.65 million hardcoded secrets in public GitHub in 2025, a 34% year-over-year increase. AI services alone contributed 1,275,105 leaked keys — up 81%.
Broken access control / missing auth checks
AI generates routes that work. Whether those routes should require authentication is an architectural decision the model treats as implicit. The result: endpoints that expose data or perform actions without checking who's asking. A Base44 platform flaw allowed any user to access private applications using only a publicly visible app ID — no authentication required. The AI didn't decide to skip auth maliciously. It just generated the shortest path to a working feature. Auth was a non-functional requirement the prompt didn't mention.
SSRF (Server-Side Request Forgery)
Tenzai's December 2025 study built 15 identical web applications using five AI coding agents: Claude Code, OpenAI Codex, Cursor, Replit, and Devin. All 15 apps included a URL preview feature. Every single one — five out of five tools, 100% — introduced an SSRF vulnerability in that feature. The AI-generated code accepted arbitrary URLs and had the server fetch them without validation. That's a direct path to http://169.254.169.254/latest/meta-data/ — the AWS metadata endpoint your cloud credentials are sitting behind. Not one tool got this right without additional security prompting.
Slopsquatting — hallucinated package names
Around 20% of AI-generated code samples reference packages that don't exist. Spracklen et al. studied 16 popular models and found that at least 5.2% of packages suggested by commercial models were fabricated, and 43% of those hallucinated names appeared consistently across repeated runs. Consistency is what makes this dangerous. Attackers can predict which package names AI tools will hallucinate, register them on PyPI and npm, and fill them with malware. Developers install them without realizing the package didn't exist yesterday. Supply chain attack at scale, enabled by LLM hallucination patterns.
Insecure deserialization
The pickle example above is the pattern. AI tools reach for familiar serialization approaches from training data without flagging the security implications. Pickle, Java's ObjectInputStream, PHP's unserialize — these appear in training data constantly, so they appear in generated code constantly. The security context — "never deserialize untrusted data with this" — doesn't make it into the output.
Dependency confusion and outdated packages
AI models suggest library versions they were trained on. If the training data shows a particular version of a library used frequently, the model suggests it — even if that version has known CVEs. It doesn't check current vulnerability databases. It returns the most statistically likely response. Combined with the hallucinated package problem, you end up with codebases importing a mix of real-but-outdated and fabricated-but-malicious dependencies.
Why SAST alone doesn't solve this
The instinctive response to AI-generated vulnerability risk is: add more scanning. Reasonable instinct. Structurally incomplete for five specific reasons worth understanding before you build your defense stack.
SAST uses signature-based pattern matching. It asks: does this line of code match a known bad pattern? AI introduces a different class of flaw — semantic errors that are syntactically valid. A missing authorization check on a route that exists, compiles, and runs cleanly. An insecure parsing assumption that makes sense given the function's stated purpose. Unsafe defaults that were correct in development and wrong in production. A 2026 benchmark found 78% of confirmed vulnerabilities in AI-generated code were detected by only one of five tested SAST tools. They're not catching the same things.
The slopsquatting problem is invisible to SAST entirely — the package name looks legitimate, the import looks correct, the code using it looks fine. The malware is in the package itself, not in the code SAST is analyzing.
There's also an architectural drift problem specific to AI code. The model makes subtle design changes that break security assumptions without violating syntax. Your SAST scan comes back clean. The authentication bypass exists because the AI restructured how the middleware chain works and a check that used to apply no longer does. Pattern matching doesn't catch that.
None of this means don't use SAST. It means SAST is one layer, not a solution.
🛡️ Policy-as-code defenses: CI/CD gates, OPA, Semgrep
The goal is building a system where vibe-coded code has to pass through enforceable, automated security checks before it touches production. Not manual review at the end — automated gates at every commit, every PR, every deployment. Here's the layered approach.
Layer 1: Pre-commit — catch secrets before they hit the repo
The window between "developer includes API key in prompt" and "scanner catches it in repo" is where the damage happens. Git history is permanent without extreme effort. Pre-commit hooks close that window.
Pre-commit secret scanning with Gitleaks
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.4
hooks:
- id: gitleaks
name: Detect hardcoded secrets
description: Blocks commits containing API keys, tokens, passwords
entry: gitleaks protect --staged --redact --config .gitleaks.toml
language: golang
pass_filenames: false
# Also scan for hallucinated/suspicious package names
- repo: local
hooks:
- id: check-package-integrity
name: Verify packages exist and aren't suspicious
language: system
entry: bash -c 'npm audit --audit-level=high 2>&1 | grep -E "critical|high" && exit 1 || exit 0'
files: package\.json$
# .gitleaks.toml - extend defaults with vibe-coding specific patterns
[extend]
useDefault = true
[[rules]]
id = "vibe-coding-common-secrets"
description = "Common AI-generated placeholder secrets that look real"
regex = '''(?i)(supersecretkey|your[_-]?secret|changeme|placeholder|example[_-]?key|test[_-]?secret)'''
tags = ["ai-generated", "placeholder"]
severity = "HIGH" Layer 2: PR gate — SAST on every AI-generated diff
Run SAST on the diff, not just the full codebase. AI generates in chunks — you want to catch vulnerable patterns at the point of introduction, not discover them in a full repo scan three sprints later when the pattern has been copied across ten files.
GitHub Actions: Security gate for AI-generated PRs
# .github/workflows/vibe-coding-security-gate.yml
name: AI Code Security Gate
on:
pull_request:
branches: [main, develop]
jobs:
sast-scan:
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read
steps:
- uses: actions/checkout@v4
# Semgrep — catches OWASP Top 10, secrets, insecure patterns
# Particularly good at the vulnerability classes AI generates consistently
- name: Run Semgrep
uses: semgrep/semgrep-action@v1
with:
config: >-
p/owasp-top-ten
p/security-audit
p/secrets
p/python
p/javascript
p/typescript
generateSarif: true
env:
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: semgrep.sarif
# Dependency scanning — catches slopsquatting and outdated packages
- name: Run dependency audit
run: |
npm audit --audit-level=high
# Check for packages published in last 7 days (new malicious packages)
node -e "
const pkg = require('./package.json');
const deps = {...pkg.dependencies, ...pkg.devDependencies};
console.log('Checking', Object.keys(deps).length, 'dependencies');
"
# Block merge on high/critical findings
- name: Enforce security gate
if: failure()
run: |
echo "::error::Security gate failed. Fix findings before merge."
echo "::error::AI-generated code requires security review on every PR."
exit 1
# Separate job: check for SSRF patterns — AI generates these constantly
ssrf-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check for SSRF-prone patterns
run: |
# Detect URL fetch patterns without validation
# Every AI coding tool generates SSRF in URL preview/fetch features
if grep -rn \
--include="*.js" --include="*.ts" --include="*.py" \
-E "fetch\(|requests\.get\(|urllib\.request\|axios\.get\(" . \
| grep -v "test\|spec\|mock" \
| grep -v "allowedHosts\|validateUrl\|isPrivateIp\|whitelist"; then
echo "::warning::Potential SSRF: URL fetch without apparent validation found"
echo "::warning::AI tools introduce SSRF in 100% of URL preview features (Tenzai 2025)"
echo "::warning::Review these patterns manually before merge"
fi Layer 3: OPA policy — enforce deployment governance
SAST catches code patterns. OPA catches deployment configuration — the Moltbook class of failure, where the code works but the infrastructure around it is misconfigured. This is the layer most teams building with vibe coding skip entirely.
OPA/Rego: Block vibe-coded apps with unsafe infrastructure defaults
# vibe-coding-deployment-policy.rego
package vibecoding.deployment
import rego.v1
default result := "fail"
# Block deployments where database is publicly accessible
# This is the Moltbook pattern — Supabase/Firebase with public read/write
result := "pass" {
currentConfiguration := input.resource.properties
db_config := object.get(currentConfiguration, "databaseConfig", {})
# Supabase: anon key should not have write access in production
not object.get(db_config, "publicWrite", false)
not object.get(db_config, "anonKeyWrite", false)
# RLS (Row Level Security) must be enabled
object.get(db_config, "rowLevelSecurity", false) == true
}
expectedConfiguration := {
"databaseConfig": {
"publicWrite": false,
"anonKeyWrite": false,
"rowLevelSecurity": true
}
}
# Block containers without explicit non-root user
# AI scaffolded containers frequently run as root
result := "pass" {
container := input.resource.properties.containers[_]
security_context := object.get(container, "securityContext", {})
object.get(security_context, "runAsNonRoot", false) == true
object.get(security_context, "runAsUser", 0) > 0
}
# Block deployments where environment variables contain obvious placeholder secrets
# Catches the supersecretkey class of AI-generated credentials
result := "pass" {
container := input.resource.properties.containers[_]
env_vars := object.get(container, "env", [])
# Check no env var value matches common AI placeholder patterns
not any_placeholder_secrets(env_vars)
}
any_placeholder_secrets(env_vars) {
env_var := env_vars[_]
val := lower(object.get(env_var, "value", ""))
placeholder_patterns := {
"supersecretkey", "changeme", "your_secret",
"placeholder", "example_key", "test_secret",
"password123", "admin123", "secret123"
}
val in placeholder_patterns
} Layer 4: Semgrep custom rules for AI-specific patterns
The built-in Semgrep rulesets catch generic OWASP patterns well. For AI-generated code specifically, you want custom rules targeting the patterns LLMs produce most consistently. The pickle problem is the template.
Semgrep rules targeting AI-generated vulnerability classes
# .semgrep/ai-code-rules.yaml
rules:
# Rule 1: Catch pickle deserialization (AI loves pickle)
# AI generates pickle for serialization constantly — enables RCE from untrusted input
- id: ai-generated-pickle-deserialization
patterns:
- pattern: pickle.loads(...)
- pattern: pickle.load(...)
message: >
Insecure deserialization via pickle. AI coding tools frequently generate
pickle for serialization — it enables arbitrary code execution from
untrusted input. Replace with json.loads() or msgpack for untrusted data.
languages: [python]
severity: ERROR
metadata:
category: security
ai-generated-pattern: true
cwe: CWE-502
# Rule 2: URL fetch without host validation (SSRF — 100% rate in Tenzai study)
- id: ssrf-missing-host-validation
patterns:
- pattern: |
requests.get($URL, ...)
- pattern-not: |
requests.get($URL, ...)
...
validate_url($URL)
- pattern-not: |
if is_safe_url($URL):
requests.get($URL, ...)
message: >
Potential SSRF: URL fetched without host validation. AI coding tools
introduce SSRF in 100% of URL preview features (Tenzai, Dec 2025).
Validate the host against an allowlist before fetching.
languages: [python]
severity: ERROR
metadata:
category: security
ai-generated-pattern: true
cwe: CWE-918
# Rule 3: JWT with hardcoded/weak secrets
# AI generates supersecretkey and variants constantly
- id: ai-generated-weak-jwt-secret
patterns:
- pattern: jwt.encode($PAYLOAD, "$SECRET", ...)
- metavariable-regex:
metavariable: $SECRET
regex: >-
(?i)(secret|key|password|supersecret|changeme|
placeholder|example|test|your_secret|jwt_secret)
message: >
Weak or placeholder JWT secret detected. AI tools generate predictable
secrets — 'supersecretkey' appeared in 1,182 of 20,000 analyzed
vibe-coded apps (Invicti 2025). Use a cryptographically random secret
from environment variables.
languages: [python]
severity: ERROR
metadata:
category: security
ai-generated-pattern: true
cwe: CWE-798
# Rule 4: Missing auth on route definition (AI skips this constantly)
- id: unauthenticated-route-definition
patterns:
- pattern: |
@app.route("$PATH", methods=["$METHOD"])
def $FUNC():
...
- pattern-not: |
@app.route("$PATH", methods=["$METHOD"])
@login_required
def $FUNC():
...
- pattern-not: |
@app.route("$PATH", methods=["$METHOD"])
@require_auth
def $FUNC():
...
message: >
Route defined without authentication decorator. AI code generators
optimize for making features work — auth decorators are non-functional
requirements that get skipped unless explicitly specified in the prompt.
Review whether this route requires authentication.
languages: [python]
severity: WARNING
metadata:
category: security
ai-generated-pattern: true
cwe: CWE-306 Layer 5: Infrastructure-level containment
When all else fails — when a vulnerability makes it past every layer above — infrastructure controls limit the blast radius. This is the "assume breach" layer applied to vibe-coded applications specifically.
Terraform: Least-privilege IAM for vibe-coded Lambda functions
# The Moltbook incident was a database misconfiguration.
# The SSRF incidents reached cloud metadata because the running process
# had network access to 169.254.169.254.
# Both are containable at the infrastructure layer.
resource "aws_iam_role" "vibe_coded_app" {
name = "vibe-coded-app-restricted"
# Assume role policy — application runtime only
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "lambda.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
tags = {
ai-generated = "true"
security-tier = "restricted"
# Tag AI-generated infrastructure for audit trail
# "An AI built it" is not an acceptable audit response in regulated environments
}
}
resource "aws_iam_role_policy" "vibe_coded_app_policy" {
name = "vibe-coded-app-minimal"
role = aws_iam_role.vibe_coded_app.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
# Only what this function actually needs — not a wildcard
Effect = "Allow"
Action = ["dynamodb:GetItem", "dynamodb:PutItem"]
Resource = aws_dynamodb_table.app_data.arn
},
{
# Explicitly deny metadata service access
# Stops SSRF-based credential theft even if SSRF exists in the code
Effect = "Deny"
Action = "*"
Resource = "*"
Condition = {
StringEquals = {
"aws:RequestedRegion" = "us-east-1"
}
# Block IMDSv1 via VPC endpoint policy — belt and suspenders
}
}
]
})
}
# IMDSv2 only — blocks the metadata SSRF attack vector at the instance level
resource "aws_instance" "app_server" {
# ... other config ...
metadata_options {
http_endpoint = "enabled"
http_tokens = "required" # IMDSv2 required — blocks SSRF to metadata
http_put_response_hop_limit = 1 # Prevents container escape to metadata
}
tags = {
ai-generated-code = "true"
}
} The actual problem nobody wants to say out loud
The tooling above works. SAST gates, OPA policies, pre-commit hooks, IMDSv2 enforcement — these catch real vulnerabilities and limit real blast radius. Build that stack.
But the tooling addresses symptoms of a structural problem that the industry is being collectively polite about: vibe coding, as originally defined, is not compatible with production security. Not because AI can't write secure code — it can, with the right prompting, with review, with security context baked into the generation workflow. Because the core premise of the workflow — forget that the code even exists — is incompatible with understanding what you're shipping.
IBM's 2025 Cost of a Data Breach Report found that 97% of organizations reported an AI-related security incident. The Moltbook founder deployed a database with public write access because he hadn't reviewed the infrastructure code. The Lovable BOLA vulnerability stayed open for 48 days because the platform's own bug bounty partners assumed exposed data was intentional. These aren't tool failures. They're accountability gaps. When there's no author, there's no one to ask "why did you do it this way?"
Simon Willison put it clearly: "If an LLM wrote every line of your code, but you've reviewed, tested, and understood it all, that's not vibe coding in my book—that's using an LLM as a typing assistant." That distinction matters. The productivity benefits are real with the second approach. The security disaster risk is concentrated in the first.
The policy defenses in this post are not a substitute for that understanding. They're a safety net for when the understanding is incomplete — which, for any team shipping AI-generated code at scale, it will be. Build the net. But also build the review process.
Immediate action items
- Add Gitleaks pre-commit hook to every repo using AI coding tools — blocks the single most common AI-generated vulnerability class before it touches version history
- Enable Semgrep on every PR with the
p/owasp-top-tenandp/secretsrulesets — free tier covers this - Enforce IMDSv2 on all EC2 instances and containers — eliminates the SSRF-to-metadata-credential-theft chain at the infrastructure layer
- Add the custom Semgrep rules above for pickle, SSRF, and JWT patterns — these are the three AI generates most consistently
- Audit your current vibe-coded applications against the six vulnerability classes: hardcoded secrets, missing auth, SSRF, slopsquatting, insecure deserialization, outdated dependencies
- Tag AI-generated infrastructure resources — "an AI built it" is not an acceptable audit response, but a tagged audit trail demonstrating security review is
