Skip to content

How to Build Secure Apps with AI-Generated Code: A Practical Security Guide

Problem

When I use AI coding assistants like Claude Code or ChatGPT to generate code, I get working solutions fast. But I kept wondering: is this code actually secure enough for production?

I tried deploying an AI-generated Flask app last month and nearly shipped a glaring SQL injection vulnerability. The code worked perfectly in my tests, but a security scan revealed the flaw before it reached production.

That close call made me realize something important: AI generates code that works, but it doesn’t guarantee code that’s secure.

What Happened?

I was building a simple user lookup feature and asked Claude to write the database query. Here’s what I got:

app.py
# AI-generated code - INSECURE
def get_user(user_id):
query = f"SELECT * FROM users WHERE id = {user_id}"
return db.execute(query)

The code ran fine in my tests. I passed integers, got back users. Everything worked. But when I ran a security scan, it flagged a critical SQL injection vulnerability.

If I had deployed this, an attacker could have passed 1 OR 1=1 as the user_id and dumped my entire user table.

The Real Problem with AI-Generated Code

I dug into this and found that security risks in AI-generated code aren’t random accidents. They follow predictable patterns:

Inconsistent Security Prompts

I tried asking different AI assistants to “write secure code” for the same feature. I got different security implementations each time. Sometimes parameterized queries, sometimes not. Sometimes input validation, sometimes forgotten.

The r/vibecoding community put it bluntly: “LLM security prompts are inconsistent.” You can’t rely on prompt engineering alone for security.

Training Data Vulnerabilities

AI models learn from public code repositories. They’ve seen millions of code examples, including insecure ones. When they generate code, they might reproduce patterns that were common in training data but are now considered vulnerable.

Context Blindness

My AI assistant doesn’t know about my application’s security context. It doesn’t know if this endpoint is public-facing or internal, if the data is sensitive or not, what authentication system I’m using.

Dependency Risks

When AI suggests packages, it doesn’t check for known CVEs. I’ve had AI suggest packages that were deprecated years ago for security reasons.

Common Vulnerabilities I’ve Found

Here are the patterns I now actively scan for:

Leaked Secrets

config.py
# AI often generates this - NEVER commit this
API_KEY = "sk-proj-xxxxx"
DATABASE_PASSWORD = "my_secret_password"

SQL Injection

queries.py
# AI may generate this
def search_users(name):
query = f"SELECT * FROM users WHERE name LIKE '%{name}%'"
return db.execute(query)

Command Injection

utils.py
# AI may generate this
def convert_file(filename):
os.system(f"convert {filename} output.png")

Path Traversal

files.py
# AI may generate this
def read_config(path):
with open(f"/app/configs/{path}") as f:
return f.read()

Missing CSRF Protection

app.py
# AI may generate this - missing CSRF token
@app.route("/delete/<id>", methods=["POST"])
def delete_item(id):
db.delete(id)
return "Deleted"

The Solution: A Multi-Layer Security Workflow

After my near-miss, I implemented a security-first workflow for all AI-generated code.

Layer 1: Local Security Scanning

I installed Stageclear.dev, a CLI tool specifically built for vibe coders:

terminal
# Install Stageclear
curl -sSL https://stageclear.dev/install | bash
# Scan my AI-generated code
stageclear scan ./my-project

The output immediately flagged my issues:

[CRITICAL] Leaked secret: API_KEY found in config.py:12
[HIGH] SQL injection vulnerability in queries.py:45
[MEDIUM] DEBUG=True in production settings.py
[INFO] Consider adding CSRF middleware

What I like about Stageclear is that it runs locally and uses “authentic security scanners” rather than relying on AI reasoning. It catches issues before they ever leave my machine.

Layer 2: Fix the Vulnerabilities

After the scan, I fixed each issue:

config.py
# SECURE - Use environment variables
import os
API_KEY = os.environ.get("API_KEY")
if not API_KEY:
raise ValueError("API_KEY environment variable not set")
queries.py
# SECURE - Parameterized queries
def get_user(user_id):
query = "SELECT * FROM users WHERE id = ?"
return db.execute(query, (user_id,))
def search_users(name):
query = "SELECT * FROM users WHERE name LIKE ?"
return db.execute(query, (f"%{name}%",))
utils.py
# SECURE - Use subprocess with list arguments
import subprocess
def convert_file(filename):
# Validate filename first
if not filename.isalnum():
raise ValueError("Invalid filename")
subprocess.run(["convert", filename, "output.png"], check=True)

Layer 3: Configuration Security

AI often generates insecure defaults for configuration:

settings.py
# AI may generate this (INSECURE)
DEBUG = True
ALLOWED_HOSTS = ["*"]
SECRET_KEY = "dev-secret-key"
CORS_ALLOW_ALL_ORIGINS = True

I changed these to:

settings.py
# SECURE configuration
import os
DEBUG = os.environ.get("DEBUG", "False").lower() == "true"
ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "localhost").split(",")
SECRET_KEY = os.environ.get("SECRET_KEY")
if not SECRET_KEY:
raise ValueError("SECRET_KEY environment variable not set")
CORS_ALLOWED_ORIGINS = os.environ.get("CORS_ORIGINS", "").split(",")

Layer 4: Static Analysis Tools

I added these to my CI/CD pipeline:

.github/workflows/security.yml
name: Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Bandit (Python security linter)
run: pip install bandit && bandit -r ./src
- name: Run Safety (check dependencies for CVEs)
run: pip install safety && safety check
- name: Run Semgrep
uses: returntocorp/semgrep-action@v1

Layer 5: Human Review Checklist

I never deploy AI code without reviewing these:

  • Authentication and authorization logic
  • Input validation on all user-provided data
  • No hardcoded credentials or secrets
  • Proper error handling (no stack traces to users)
  • Rate limiting on public endpoints
  • Security headers configured

Why Traditional Security Prompts Fail

I tried prompting for secure code:

Write secure Python code for user authentication with proper input validation, parameterized queries, and no hardcoded secrets.

The result? Better than unprompted code, but still had issues:

  • Missing rate limiting
  • Incomplete input validation
  • Weak password requirements
  • No CSRF tokens

The OWASP GenAI Security Project warns: “Neglecting to validate LLM outputs may lead to downstream security exploits, including code execution that compromises systems and exposes data.”

The problem is that prompt engineering is not a security control. AI assistants respond inconsistently, miss context, and can’t guarantee comprehensive security coverage.

Other Tools Worth Knowing

From the r/vibecoding community, I found these helpful:

Vibecheck.expert: Gives a “Vibe Score” (0-100) for code quality and security. Useful for quick production readiness checks.

Vibe.rehab: Analyzes broken AI-generated code and provides security audits. Good for learning what went wrong.

Traditional tools still matter:

  • ESLint security plugins for JavaScript
  • Bandit for Python
  • Semgrep for multiple languages
  • Snyk for dependency scanning

The Cost of Skipping Security

I calculated what my near-miss would have cost:

ScenarioCost
Security scan before deploy5 minutes
Fix vulnerability during development30 minutes
Fix vulnerability in production4+ hours + incident response
Data breach from SQL injectionReputation damage + potential legal fees

The OWASP community wisdom holds: fixing vulnerabilities pre-deployment is 10x cheaper than post-deployment.

Summary

In this post, I showed how I secured my AI-generated code before deploying to production. The key point is that AI assistants generate working code, but security must be verified through dedicated scanning tools and human review.

My workflow now:

  1. Generate code with AI
  2. Run Stageclear.dev locally before any commit
  3. Fix flagged issues immediately
  4. Run static analysis in CI/CD
  5. Human review for security-critical areas
  6. Deploy with environment variables and proper configuration

The future of development is AI-assisted, but security remains human-verified. Start with a security-first mindset, use the right tools, and ship with confidence.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments