← Back to blog
2026-07-22 · VulnLedger

"Input Validation: The #1 Thing AI-Generated Code Gets Wrong"

AI coding assistants generate code that handles the happy path but skips input validation. SQL injection, XSS, and command injection are the result. Here's how to fix it.

Security Input Validation OWASP SQL Injection XSS AI Code

When Claude writes a login form, it handles valid credentials perfectly. When someone sends ' OR 1=1 -- as a username, it falls over. That's the input validation problem with AI-generated code.

AI optimizes for "does it work?" — not "is it safe?" The happy path gets beautiful code. The attack paths get nothing.

Why AI Skips Input Validation

AI coding assistants are trained on millions of code examples. Most of those examples:

- Handle the happy path (correct input)

- Skip error handling (incorrect input)

- Use string interpolation (injection risk)

- Trust environment variables (configuration risk)

When you ask Claude to "build a login form," it generates code that validates the email format and checks the password hash. But it doesn't:

- Sanitize against SQL injection

- Escape HTML output (XSS prevention)

- Validate input length (buffer overflow prevention)

- Check for command injection in shell calls

The 5 Most Common Input Validation Failures

1. SQL Injection

The vulnerability: User input goes directly into SQL queries.

# WRONG — AI often generates this
query = f"SELECT * FROM users WHERE email = '{email}'"

# RIGHT — use parameterized queries
query = "SELECT * FROM users WHERE email = %s"
cursor.execute(query, (email,))

How to catch it: Use bandit for Python security linting:

pip install bandit
bandit -r . --severity-level medium

2. Cross-Site Scripting (XSS)

The vulnerability: User input rendered as HTML without escaping.

# WRONG — AI often generates this
return f"<div>{user_input}</div>"

# RIGHT — escape HTML entities
from markupsafe import escape
return f"<div>{escape(user_input)}</div>"

How to catch it: Use template engines that auto-escape (Jinja2, Django templates) instead of f-strings for HTML.

3. Command Injection

The vulnerability: User input passed to shell commands.

# WRONG — AI often generates this
import os
os.system(f"ping {user_input}")

# RIGHT — use subprocess with list arguments
import subprocess
subprocess.run(["ping", user_input], capture_output=True)

4. Path Traversal

The vulnerability: User input used in file paths.

# WRONG — AI often generates this
with open(f"/uploads/{filename}") as f:
    content = f.read()

# RIGHT — validate and sanitize the path
import os
safe_path = os.path.join("/uploads", os.path.basename(filename))
if not safe_path.startswith("/uploads/"):
    raise ValueError("Invalid path")

5. No Input Length Limits

The vulnerability: Accepting unlimited input length.

# WRONG — AI often generates this
name = request.form["name"]

# RIGHT — validate length
name = request.form["name"]
if len(name) > 100:
    return "Name too long", 400

The AI-Specific Problem

AI-generated code has a unique input validation challenge: it looks correct but isn't.

Consider this example. You ask Claude to "build a search endpoint":

@app.route("/search")
def search():
    query = request.args.get("q")
    results = db.execute(f"SELECT * FROM items WHERE name LIKE '%{query}%'")
    return jsonify(results)

This code:

- ✅ Handles valid input correctly

- ✅ Returns JSON results

- ❌ Vulnerable to SQL injection (query goes directly into SQL)

- ❌ No input validation (no length limit, no character filtering)

- ❌ No error handling (crashes on bad input)

The AI made it "work" — but it's not secure.

How to Fix Input Validation in AI Code

Step 1: Run Security Linting

# Python
pip install bandit
bandit -r . --severity-level medium

# JavaScript
npm install eslint-plugin-security
npx eslint --plugin security .

Step 2: Add Parameterized Queries

Replace all string interpolation in SQL with parameterized queries:

# Before
db.execute(f"SELECT * FROM users WHERE id = {user_id}")

# After
db.execute("SELECT * FROM users WHERE id = %s", (user_id,))

Step 3: Add Input Validation

For every API endpoint, validate:

- Type (is it a string? number? email?)

- Length (max 100 chars for names, max 500 for text)

- Format (regex for emails, URLs, etc.)

- Range (is the number within acceptable bounds?)

from pydantic import BaseModel, EmailStr, constr

class CreateUser(BaseModel):
    email: EmailStr
    name: constr(min_length=1, max_length=100)
    age: int = Field(ge=0, le=150)

Step 4: Escape Output

Always escape user input before rendering in HTML:

# Jinja2 auto-escapes by default
return render_template("profile.html", name=user_input)

# For API responses, use JSON serialization
return jsonify({"name": user_input})  # JSON auto-escapes

Step 5: Add Rate Limiting

Prevent abuse by limiting request frequency:

from flask_limiter import Limiter
limiter = Limiter(app, default_limits=["100 per hour"])

@app.route("/search")
@limiter.limit("10 per minute")
def search():
    # ...

The Validation Checklist

For every API endpoint:

- [ ] Input type validated (string, int, email, URL)

- [ ] Input length limited (max 100 for names, 1000 for text)

- [ ] Input format validated (regex for emails, etc.)

- [ ] SQL queries use parameterized statements

- [ ] HTML output is escaped (or using auto-escaping templates)

- [ ] File paths are sanitized (os.path.basename only)

- [ ] Rate limiting is applied

- [ ] Error handling catches validation failures

How VulnLedger Helps

While input validation catches application-level bugs, dependency scanning catches the vulnerabilities in the libraries you use. A secure app needs both:

1. Your code is safe (input validation, parameterized queries)

2. Your dependencies are safe (VulnLedger scans for CVEs)

pip install vulnledger
vulnledger scan .

This catches the dependency side. You handle the input validation side. Together, they cover 90% of attack vectors.

Conclusion

AI-generated code looks clean but often skips the validation that prevents injection attacks. The fix is straightforward: run security linting, add parameterized queries, validate all input, escape all output. These 4 steps catch the majority of input validation vulnerabilities.

Next in this series: Dependency Security: How to Scan and Fix Vulnerable Packages

Previous: The Developer's Guide to Secure Coding in 2026

Try VulnLedger

Generate SBOMs and scan for vulnerabilities in one command.

Start Free