AI Code Review Checklist: What to Check Before Merging AI-Generated Code
A practical checklist for reviewing AI-generated code before it hits production. Covers security, correctness, and maintainability.
AI coding assistants can write a lot of code quickly. But speed means nothing if that code introduces security vulnerabilities, logic errors, or maintenance nightmares.
Hereβs a practical checklist for reviewing AI-generated code before it reaches production.
Security Checks
These are non-negotiable. AI models sometimes include patterns from their training data that are insecure or outdated.
1. Hardcoded Secrets
Look for API keys, passwords, tokens, or credentials embedded in the code:
// π¨ BAD: AI sometimes generates placeholder secrets
const apiKey = "sk-1234567890abcdef";
const password = "admin123";
// β
GOOD: Use environment variables
const apiKey = process.env.API_KEY;
Search the diff for patterns like:
api_key,apiKey,API_KEYsecret,password,tokensk-,pk_,Bearer- Base64 strings that look like credentials
2. SQL Injection
AI often generates string concatenation for SQL, which is vulnerable:
// π¨ BAD: SQL injection vulnerability
const query = `SELECT * FROM users WHERE id = ${userId}`;
// β
GOOD: Parameterized queries
const query = `SELECT * FROM users WHERE id = $1`;
await db.query(query, [userId]);
3. XSS Vulnerabilities
Check that user input is properly escaped before rendering:
// π¨ BAD: XSS vulnerability
element.innerHTML = userInput;
// β
GOOD: Use textContent or sanitize
element.textContent = userInput;
4. Insecure Defaults
AI sometimes uses permissive defaults:
// π¨ BAD: CORS wide open
cors({ origin: "*" })
// β
GOOD: Specific origins
cors({ origin: ["https://myapp.com"] })
// π¨ BAD: Weak crypto
crypto.createHash("md5")
// β
GOOD: Strong crypto
crypto.createHash("sha256")
Logic & Correctness
AI can write code that looks right but has subtle bugs.
5. Edge Cases
Does the code handle:
- Empty arrays/objects?
- Null/undefined values?
- Negative numbers where only positive make sense?
- Very large inputs?
// π¨ Missing null check
function getFirstItem(items) {
return items[0].name; // Crashes if items is empty
}
// β
With null check
function getFirstItem(items) {
return items?.[0]?.name ?? null;
}
6. Error Handling
AI often generates the happy path without proper error handling:
// π¨ No error handling
const data = await fetch(url);
const json = await data.json();
return json.result;
// β
With error handling
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
return data.result;
} catch (error) {
console.error("Fetch failed:", error);
throw error;
}
7. Off-by-One Errors
Classic bug that AI reproduces:
// π¨ Off-by-one: skips last element
for (let i = 0; i < items.length - 1; i++)
// β
Correct
for (let i = 0; i < items.length; i++)
8. Async/Await Issues
AI sometimes forgets await or mishandles promises:
// π¨ Missing await
function saveUser(user) {
db.save(user); // Returns immediately, save may fail silently
return { success: true };
}
// β
With await
async function saveUser(user) {
await db.save(user);
return { success: true };
}
Maintainability
Code that works today but is unmaintainable is a liability.
9. Naming & Clarity
AI sometimes uses generic names:
// π¨ Unclear naming
const data = await getData();
const result = processData(data);
const x = transform(result);
// β
Clear naming
const users = await fetchActiveUsers();
const validatedUsers = validateUserData(users);
const userDTOs = mapToResponseFormat(validatedUsers);
10. Unnecessary Complexity
AI can over-engineer simple problems:
// π¨ Over-engineered
class UserValidatorFactory {
createValidator(type) {
return new UserValidator(new ValidationStrategy(type));
}
}
// β
Just a function
function validateUser(user) {
return user.email && user.name;
}
11. Dead Code
AI sometimes generates code thatβs never used:
// π¨ Unused function
function helperThatNothingCalls() {
// ...
}
// Delete it or ask: why did AI generate this?
12. Matches Project Conventions
Does the AI code match your existing patterns?
- Import style (named vs default)
- Error handling patterns
- Logging approach
- File/folder structure
Quick Checklist
Copy this for your PR reviews:
## AI Code Review Checklist
### Security
- [ ] No hardcoded secrets/API keys
- [ ] No SQL injection (parameterized queries used)
- [ ] No XSS (user input escaped)
- [ ] Secure defaults (CORS, crypto, etc.)
### Correctness
- [ ] Edge cases handled (null, empty, bounds)
- [ ] Proper error handling
- [ ] No off-by-one errors
- [ ] Async/await used correctly
### Maintainability
- [ ] Clear naming
- [ ] No unnecessary complexity
- [ ] No dead code
- [ ] Matches project conventions
Automate What You Can
Manual review catches a lot, but automated tools catch more consistently.
Static analysis tools like ESLint with security plugins can flag common issues. Security scanners like Snyk or npm audit catch known vulnerabilities.
mrq runs automatic security audits on every code change, flagging hardcoded secrets, SQL injection patterns, and other issues before you even start reviewing. Itβs like having a security-focused first pass on every diff.
The Bottom Line
AI-generated code is like code from a very fast junior developer: often correct, sometimes subtly wrong, occasionally a security risk.
Review it the same way youβd review any code: trust but verify. Use this checklist, automate what you can, and always check security-sensitive areas carefully.
Related Reading
- The Hidden Security Risk of AI Coding - Why AI code needs extra scrutiny
- How to Secure Your Codebase When Using AI - Broader security strategies
- Security Audits in mrq - Automated security scanning
mrq automatically audits AI-generated code for security issues. Every snapshot is scanned for hardcoded secrets, injection vulnerabilities, and more.
Written by mrq team