AI-Powered Code Review with LLMs 2026: Automate Bug Detection and Security Audits

Sanjeev SharmaSanjeev Sharma
6 min read

Advertisement

AI Code Review 2026: Your Always-On Senior Engineer

The best code review is the one that happens instantly, every time. AI code reviewers catch bugs, security issues, and style problems before human reviewers ever see the PR.

Why AI Code Review Works

Traditional linters catch syntax errors. AI reviewers understand intent, context, and logic:

  • SQL injection vulnerabilities in dynamic queries
  • Race conditions in async code
  • Memory leaks in resource handling
  • Business logic bugs ("this returns wrong results for empty arrays")
  • Performance issues ("this is O(n²) — here's the O(n) version")

Core Review Engine

from openai import OpenAI
import ast
import re

client = OpenAI()

SYSTEM_PROMPT = """You are a senior software engineer performing code review.
Analyze the provided code diff and return a JSON array of review comments.

Each comment must have:
- line: line number (or null for general comments)
- severity: "critical" | "warning" | "suggestion" | "praise"
- category: "bug" | "security" | "performance" | "readability" | "logic"
- message: clear explanation of the issue
- suggestion: specific fix or improvement

Focus on:
1. CRITICAL: bugs, security vulnerabilities, data loss risks
2. WARNING: performance issues, error handling gaps, logic errors
3. SUGGESTION: improvements, better patterns, test coverage
4. PRAISE: well-written code worth acknowledging

Return ONLY valid JSON. No markdown, no explanation."""

def review_code(diff: str, filename: str, context: str = "") -> list[dict]:
    """Review a code diff and return structured feedback."""

    prompt = f"""File: {filename}

Context: {context or 'General code review'}

Code diff:
{diff}

Return JSON array of review comments."""

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": prompt},
        ],
        response_format={"type": "json_object"},
        temperature=0.2,
    )

    import json
    result = json.loads(response.choices[0].message.content)
    return result.get("comments", result) if isinstance(result, dict) else result

Security Vulnerability Scanner

SECURITY_PROMPT = """You are a security engineer specializing in code security audits.
Analyze the code for security vulnerabilities. Return JSON with:
- vulnerabilities: array of {type, severity, line, description, cwe_id, fix}
- risk_score: 0-10
- summary: brief security assessment

Check for: SQL injection, XSS, CSRF, path traversal, command injection,
hardcoded secrets, insecure deserialization, broken auth, sensitive data exposure."""

def security_scan(code: str, language: str = "python") -> dict:
    """Scan code for security vulnerabilities."""
    import json

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": SECURITY_PROMPT},
            {"role": "user", "content": f"Language: {language}\n\nCode:\n```{language}\n{code}\n```"},
        ],
        response_format={"type": "json_object"},
        temperature=0,
    )

    return json.loads(response.choices[0].message.content)

# Example vulnerable code
vulnerable_code = """
def get_user(user_id):
    query = f"SELECT * FROM users WHERE id = {user_id}"  # SQL injection!
    return db.execute(query)

def render_profile(name):
    return f"<h1>Welcome {name}</h1>"  # XSS!

API_KEY = "sk-abc123secretkey"  # Hardcoded secret!
"""

result = security_scan(vulnerable_code)
print(f"Risk score: {result['risk_score']}/10")
for vuln in result['vulnerabilities']:
    print(f"[{vuln['severity']}] {vuln['type']}: {vuln['description']}")

GitHub Actions Integration

# .github/workflows/ai-code-review.yml
name: AI Code Review

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  review:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
      contents: read

    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - name: Install dependencies
        run: pip install openai PyGithub

      - name: Run AI Code Review
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
          REPO: ${{ github.repository }}
        run: python .github/scripts/ai_review.py
# .github/scripts/ai_review.py
import os
import subprocess
import json
from openai import OpenAI
from github import Github

client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
gh = Github(os.environ["GITHUB_TOKEN"])

def get_pr_diff():
    result = subprocess.run(
        ["git", "diff", "origin/main...HEAD", "--unified=5"],
        capture_output=True, text=True
    )
    return result.stdout

def post_review_comments(repo_name, pr_number, comments):
    repo = gh.get_repo(repo_name)
    pr = repo.get_pull(int(pr_number))

    # Post summary comment
    critical = [c for c in comments if c.get("severity") == "critical"]
    warnings = [c for c in comments if c.get("severity") == "warning"]

    summary = f"""## 🤖 AI Code Review

**{len(critical)} critical issues** | **{len(warnings)} warnings** | **{len(comments)} total comments**

"""
    for comment in comments:
        icon = {"critical": "🔴", "warning": "🟡", "suggestion": "💡", "praise": "✅"}.get(comment["severity"], "📝")
        summary += f"{icon} **[{comment['category']}]** {comment['message']}\n"
        if comment.get("suggestion"):
            summary += f"   > 💡 {comment['suggestion']}\n\n"

    pr.create_issue_comment(summary)
    print(f"Posted review with {len(comments)} comments")

diff = get_pr_diff()
if len(diff) > 100:
    comments = review_code(diff[:8000], "PR diff")
    post_review_comments(
        os.environ["REPO"],
        os.environ["PR_NUMBER"],
        comments
    )

Multi-Language Support

LANGUAGE_CONTEXTS = {
    "python": "Focus on: type hints, exception handling, resource management (context managers), list comprehensions vs loops",
    "javascript": "Focus on: async/await patterns, null checks, prototype pollution, XSS in DOM manipulation",
    "typescript": "Focus on: strict null checks, type assertions, generic constraints, discriminated unions",
    "go": "Focus on: error handling patterns, goroutine leaks, interface satisfaction, defer usage",
    "rust": "Focus on: ownership, borrowing, lifetime annotations, unwrap() usage",
    "sql": "Focus on: query performance, indexes, N+1 patterns, injection vulnerabilities",
}

def review_with_language_context(code: str, language: str) -> list[dict]:
    context = LANGUAGE_CONTEXTS.get(language.lower(), "General best practices")
    return review_code(code, f"code.{language}", context)

Custom Review Rules

CUSTOM_RULES = """
Additional rules for this codebase:
1. All database queries must use parameterized queries — never string formatting
2. All user inputs must be validated with Pydantic models
3. Async functions must have timeout handling
4. All new endpoints must include rate limiting
5. Secrets must come from environment variables, never hardcoded
6. All public functions must have docstrings
"""

def review_with_custom_rules(diff: str) -> list[dict]:
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT + "\n\n" + CUSTOM_RULES},
            {"role": "user", "content": f"Review this diff:\n{diff}"},
        ],
        response_format={"type": "json_object"},
        temperature=0.1,
    )
    import json
    result = json.loads(response.choices[0].message.content)
    return result.get("comments", [])

Performance Analysis

PERF_PROMPT = """Analyze this code for performance issues. Return JSON:
{
  "issues": [{"description", "impact": "high/med/low", "line", "optimization"}],
  "complexity": {"time": "O(?)", "space": "O(?)"},
  "score": 1-10,
  "quick_wins": ["specific optimizations with expected speedup"]
}"""

def analyze_performance(code: str, language: str = "python") -> dict:
    import json
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": PERF_PROMPT},
            {"role": "user", "content": f"```{language}\n{code}\n```"},
        ],
        response_format={"type": "json_object"},
        temperature=0,
    )
    return json.loads(response.choices[0].message.content)

Pre-commit Hook

#!/usr/bin/env python3
# .git/hooks/pre-commit (chmod +x)
import subprocess
import sys
import os
from openai import OpenAI

def main():
    # Get staged changes
    result = subprocess.run(
        ["git", "diff", "--cached", "--unified=3"],
        capture_output=True, text=True
    )
    diff = result.stdout

    if len(diff) < 50:
        sys.exit(0)  # Nothing to review

    print("🤖 Running AI code review...")
    client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))

    response = client.chat.completions.create(
        model="gpt-4o-mini",  # Fast + cheap for pre-commit
        messages=[{
            "role": "user",
            "content": f"""Quick review this diff. Only flag CRITICAL issues (bugs, security).
            Be concise. Format: ISSUE: [description] on line [N]

            {diff[:3000]}"""
        }],
        max_tokens=500,
        temperature=0,
    )

    review = response.choices[0].message.content
    if "ISSUE:" in review:
        print("\n⚠️  AI Review found issues:\n")
        print(review)
        answer = input("\nCommit anyway? [y/N]: ")
        if answer.lower() != "y":
            sys.exit(1)

    print("✅ AI review passed")

if __name__ == "__main__":
    main()

Cost Optimization

ApproachModelCost/1K linesSpeed
Full reviewgpt-4o~$0.153-5s
Pre-commit checkgpt-4o-mini~$0.011-2s
Security scan onlygpt-4o~$0.102-3s
Batch nightlygpt-4o~$0.05async

AI code review pays for itself by catching one production bug per month. At $0.15 per PR, it's cheaper than 30 seconds of a senior engineer's time.

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro