I’ve been there: you let an LLM write a FastAPI endpoint, the app ships, and a security scan flags a handful of issues you never saw coming. The good news is you don’t have to chase down each problem manually. An ai generated code vulnerabilities report tells you exactly what to fix, and with the right tooling you can make that report part of every pull request. Below I walk through why AI-generated snippets are prone to bugs, how to set up static analysis tools, automate scans in CI/CD, read the report, and apply best-practice mitigations.
Why does AI-generated code often contain security flaws?
The answer is simple: language models predict the next token, not the next safe token. They have seen millions of open-source projects, many of which contain outdated patterns, hard-coded secrets, or insecure defaults. When you ask a model to “write a login route with JWT”, it will often:
- Use a static secret key (
SECRET = "mysecret"). - Skip input validation (
username = request.json["user"]). - Trust user-provided data for file paths.
Those patterns compile and run, but they open the door to injection, credential leakage, and privilege escalation. In production I saw a bot-generated CSV import that used os.system on the supplied filename – a classic command injection that slipped through code review because the snippet was only a few lines.
Static analysis tools shine here because they look for the effect of the code, not the intent behind it. They can flag hard-coded secrets, unsafe deserialization, missing CSRF protection, and more. The key is to treat the output of the LLM as any other third-party dependency: run it through a scanner before it touches your codebase.
How do I set up static analysis tools for AI-generated snippets?
I use a mix of Bandit, Semgrep, and SonarQube. Bandit is quick for Python-specific issues, Semgrep lets me write custom rules that target the patterns LLMs love, and SonarQube provides a dashboard for the whole team.
1. Install Bandit
pip install bandit
Create a simple wrapper that runs Bandit only on the generated/ folder where you store AI-produced files:
# run_bandit.sh
#!/usr/bin/env bash
set -e
bandit -r generated/ -lll -f json -o bandit_report.json
The -lll flag treats low-severity findings as failures, which is useful when you want a clean bill of health before merging.
2. Add Semgrep with custom rules
First, install Semgrep:
pip install semgrep
Then create a rule file semgrep_rules.yml that catches common LLM pitfalls:
rules:
- id: hardcoded-secret
patterns:
- pattern: $VAR = "$SECRET"
message: "Avoid hard‑coded secrets in generated code."
severity: HIGH
languages: [python]
- id: unsafe-os-system
pattern: os.system(...)
message: "os.system can lead to command injection."
severity: HIGH
languages: [python]
Run it with:
semgrep --config semgrep_rules.yml generated/ --json > semgrep_report.json
3. Hook SonarQube into the mix
If you already have SonarQube for the rest of the repo, just add the generated/ directory to the analysis scope in sonar-project.properties:
sonar.sources=app,generated
sonar.exclusions=tests/**
When you trigger a SonarQube scan, the UI will aggregate findings from both your hand-written code and the AI-generated snippets, giving you a single ai generated code vulnerabilities report.
How can I automate vulnerability scanning in my CI/CD pipeline?
Automation is the only way to keep the feedback loop short. Below is a GitHub Actions workflow that runs Bandit, Semgrep, and SonarQube on every PR. Adjust the steps if you use GitLab or CircleCI – the concepts are the same.
name: Scan AI‑Generated Code
on:
pull_request:
paths:
- 'generated/**'
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# Set up Python
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
# Install tools
- name: Install scanners
run: |
pip install bandit semgrep
# SonarScanner CLI
curl -sSLo sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-5.0.1.3009-linux.zip
unzip sonar-scanner.zip -d $HOME
echo "$HOME/sonar-scanner-5.0.1.3009-linux/bin" >> $GITHUB_PATH
# Run Bandit
- name: Run Bandit
run: ./run_bandit.sh
# Run Semgrep
- name: Run Semgrep
run: semgrep --config semgrep_rules.yml generated/ --json > semgrep_report.json
# Run SonarQube
- name: SonarQube Scan
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
sonar-scanner \
-Dsonar.projectKey=my-fastapi-app \
-Dsonar.sources=app,generated \
-Dsonar.host.url=https://sonar.mycompany.com \
-Dsonar.login=$SONAR_TOKEN
# Upload reports as artifacts
- name: Upload reports
uses: actions/upload-artifact@v3
with:
name: security-reports
path: |
bandit_report.json
semgrep_report.json
The workflow fails the PR if any scanner produces a HIGH severity finding. That way the ai generated code vulnerabilities report becomes a gate, not an after-the-fact checklist.
How do I interpret and triage the generated vulnerability report?
When the pipeline finishes you’ll have three JSON files. Here’s a quick way to turn them into a readable markdown table that you can paste into the PR comment.
import json
from pathlib import Path
def load(path):
return json.load(Path(path).open())
bandit = load('bandit_report.json')
semgrep = load('semgrep_report.json')
# SonarQube API can be queried for issues; for brevity we assume a local JSON export
sonar = load('sonarqube_issues.json')
def format_issue(issue, source):
return f"| {source} | {issue['filename']} | {issue.get('line_number', '-') } | {issue['severity']} | {issue['issue_text']} |"
rows = []
for i in bandit['results']:
rows.append(format_issue(i, 'Bandit'))
for i in semgrep:
rows.append(format_issue(i, 'Semgrep'))
for i in sonar['issues']:
rows.append(format_issue(i, 'SonarQube'))
markdown = "\n".join([
"## AI Generated Code Vulnerabilities Report",
"| Tool | File | Line | Severity | Description |",
"|------|------|------|----------|-------------|",
*rows
])
Path('vuln_report.md').write_text(markdown)
print("Report written to vuln_report.md")
A few triage tips:
- Prioritize HIGH severity – they usually map to credential exposure or remote code execution.
- Group by file – if a single generated file has three issues, consider rewriting it manually.
- Check for duplicates – Bandit and SonarQube may flag the same hard-coded secret; keep only the highest severity entry.
-
Add remediation notes – in the PR comment, suggest concrete fixes (e.g., “replace static key with
os.getenv('JWT_SECRET')”).
When you see the same pattern across many snippets, it’s a signal to adjust your prompt or post-process step. For example, after spotting repeated os.system usage, I added a prompt clause: “Never use os.system; use subprocess.run with a list of arguments”.
What best practices can I follow to mitigate risks in AI-generated code?
- Never merge raw AI output – always run it through a linter and a scanner first.
- Store generated code in a dedicated directory – makes scoping easier and keeps human-written code separate.
-
Enforce secret management – replace any literal that looks like a key or password with an environment variable lookup. Tools like
python-dotenvhelp keep defaults empty. - Add unit tests immediately – a failing test catches logic errors that static analysis may miss. I usually generate a skeleton test with the same LLM, then flesh it out manually.
- Version-control the prompts – if a specific prompt leads to insecure code, lock it down or add a comment that warns future users.
-
Run dependency-checkers – AI may suggest outdated libraries. Use
pip-auditorsafetyto verify that the generatedrequirements.txtis safe. - Consider a “review bot” – a small FastAPI endpoint that receives generated files, runs the scanners, and returns the JSON report. See my post on AI agent python ollama: Build, Test, Deploy with FastAPI for a pattern you can adapt.
When you combine these practices with the automated pipeline above, the ai generated code vulnerabilities report becomes a routine health check rather than a surprise after a production incident.
FAQ
What if the scanners miss a vulnerability?
Static analysis is not a silver bullet. Complement it with runtime monitoring (e.g., Snyk IaC scans, OWASP ZAP for endpoints) and regular pen-testing.
Can I rely on Bandit alone?
Bandit is great for common Python pitfalls, but it doesn’t understand templating or configuration files. Adding Semgrep or SonarQube covers those gaps.
Is it safe to use AI for security-critical code?
Only if you treat the output as untrusted. Run it through the same review, testing, and scanning pipeline you would any third-party library.
How much does this add to CI time?
In my experience the three scanners together add ~30 seconds per PR. The cost is negligible compared to a production breach.
Key Takeaways
- AI-generated code often repeats insecure patterns; treat it as third-party code.
- Set up Bandit, Semgrep, and SonarQube to create a comprehensive ai generated code vulnerabilities report.
- Automate the scans in CI/CD so every pull request is gated by security checks.
- Use a small script to turn JSON findings into a readable markdown table for quick triage.
- Apply best practices: separate directories, secret management, immediate unit tests, and prompt versioning.
- When you need a hand setting this up for your FastAPI service, feel free to reach out at /hire/. I’m happy to help you tighten the loop between AI generation and production security.
Top comments (0)