Look, AI is writing half your codebase now. That's fine. It's fast, it gets the boilerplate out of the way. But let's stop pretending it knows what a secure architecture looks like. When you let an LLM vomit out a bunch of Node or Python and just YOLO it into prod, you're building a bomb. You want a breach? Keep blindly trusting the autocomplete.
This isn't theory. I've audited enough AI-generated slop this year to know exactly what it gets wrong. It hardcodes secrets. It invents APIs that don't exist. It completely ignores SSRF protections. Bottom line: if you don't verify what the bot wrote, you're the one on the hook when the ransomware hits.
Here is the ultimate AI code security checklist. 25 things you absolutely must check before that pull request gets merged.
Authentication & Authorization (The Front Door)
The AI loves to build custom auth. Never let it.
1. Hardcoded Credentials
AI will just drop API keys in plain text. Nuke it.
# Bad
api_key = "sk-live-12345"
# Good
import os
api_key = os.environ.get("API_KEY")2. Broken JWT Validation
It skips signature verification because it's lazy.
// Bad
const payload = jwt.decode(token);
// Good
const payload = jwt.verify(token, process.env.JWT_SECRET, { algorithms: ['HS256'] });3. Missing Role-Based Access Control
AI endpoints default to anyone with a token.
# Bad
@app.route('/admin/delete')
def delete_user():
# Good
@app.route('/admin/delete')
@require_role('ADMIN')
def delete_user():4. Weak Password Hashing
MD5 is dead. Tell the AI to stop using it.
# Bad
hash = hashlib.md5(password).hexdigest()
# Good
hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt())5. Insecure Direct Object Reference (IDOR)
Just because they know the ID doesn't mean they own the record.
// Bad
db.users.find({ id: req.params.id })
// Good
db.users.find({ id: req.params.id, owner_id: req.user.id })Input Validation (Trust Nothing)
Look, I've seen this a hundred times. LLMs assume users are nice. Users are not nice.
6. SQL Injection
Yes, AI still writes raw SQL strings in 2026.
// Bad
db.execute(`SELECT * FROM users WHERE name = '${req.body.name}'`);
// Good
db.execute('SELECT * FROM users WHERE name = ?', [req.body.name]);7. Cross-Site Scripting (XSS)
React usually saves you, but dangerouslySetInnerHTML is the AI's favorite footgun.
// Bad
<div dangerouslySetInnerHTML={{ __html: userInput }} />
// Good
import DOMPurify from 'dompurify';
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userInput) }} />8. Command Injection
Don't let user input touch a shell.
# Bad
os.system(f"ping {user_ip}")
# Good
subprocess.run(["ping", "-c", "4", user_ip], check=True)9. Server-Side Request Forgery (SSRF)
AI will just fetch whatever URL the user gives it.
# Bad
requests.get(user_provided_url)
# Good
if is_safe_url(user_provided_url):
requests.get(user_provided_url, timeout=5)10. Path Traversal
Stop letting them read /etc/passwd.
// Bad
fs.readFile(path.join(__dirname, req.query.file));
// Good
const safePath = path.resolve(__dirname, 'public', path.basename(req.query.file));Data Protection (Stop Leaking)
11. Plaintext PII
Encrypt social security numbers, emails, whatever.
# Bad
db.save({"ssn": user_ssn})
# Good
db.save({"ssn": encrypt_kms(user_ssn)})12. Verbose Error Messages
Don't spit stack traces to the frontend.
// Bad
res.status(500).send(err.stack);
// Good
res.status(500).send("Internal Server Error");13. Logging Secrets
AI loves console.log(req.body).
// Bad
console.log("User config:", config);
// Good
const safeConfig = omit(config, ['password', 'token']);
console.log("User config:", safeConfig);14. Insecure Randomness
Math.random() is not for crypto.
// Bad
const resetToken = Math.random().toString(36);
// Good
const resetToken = crypto.randomBytes(32).toString('hex');15. Missing Security Headers
Add HSTS, CSP, the works.
// Bad
app.use(cors());
// Good
const helmet = require('helmet');
app.use(helmet());API & Network Security (Close the Holes)
16. No Rate Limiting
APIs without rate limits are just DDoS targets.
// Bad
app.post('/login', loginHandler);
// Good
const limiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 100 });
app.post('/login', limiter, loginHandler);17. Unsafe Deserialization
Pickle and YAML are loaded weapons.
# Bad
data = yaml.load(user_input)
# Good
data = yaml.safe_load(user_input)18. Permissive CORS
* is not an acceptable origin.
// Bad
app.use(cors({ origin: '*' }));
// Good
app.use(cors({ origin: 'https://myapp.com' }));19. Cleartext Protocols
Force TLS everywhere.
# Bad
url = "http://api.internal.svc"
# Good
url = "https://api.internal.svc"20. GraphQL Introspection
Turn it off in prod or get scraped.
// Bad
const server = new ApolloServer({ typeDefs, resolvers });
// Good
const server = new ApolloServer({ typeDefs, resolvers, introspection: false });Infrastructure & Deployment (Lock It Down)
21. Overprivileged Containers
Root in Docker is a bad joke.
# Bad
USER root
# Good
USER appuser22. Outdated Base Images
Stop pulling node:latest.
# Bad
FROM python:3
# Good
FROM python:3.11-slim@sha256:abcd...23. Hardcoded Cloud Perms
AI will write Action: "*" in IAM policies.
// Bad
{"Effect": "Allow", "Action": "s3:*", "Resource": "*"}
// Good
{"Effect": "Allow", "Action": ["s3:GetObject"], "Resource": "arn:aws:s3:::my-bucket/*"}24. Exposed Debug Ports
Don't bind debugging to 0.0.0.0.
// Bad
"start": "node --inspect=0.0.0.0 index.js"
// Good
"start": "node index.js"25. Missing Dependency Pins
Yarn or NPM, pin the exact versions.
// Bad
"express": "^4.0.0"
// Good
"express": "4.18.2"Stop Doing This By Hand
Look, you can run through this AI code security checklist manually for every PR, but that's a waste of engineering hours. Bryxe automates all 25 of these checks directly in your CI pipeline. It scans the LLM output, flags the janky code, and enforces actual DevSecOps standards before anything gets shipped to prod. Stop trusting the bot and start verifying the bits.
![The Ultimate AI Code Security Checklist: 25 Things to Verify Before Shipping AI-Generated Code [2026] [Audit]](/_next/image?url=%2Fblog%2Ftest-mockup.jpg&w=3840&q=75&dpl=dpl_9wjFGoCwx1HVyawLu6p7BBQYdgG6)