Security Audit: Autofix

Security Audit: Autofix

Automated fix generation for security vulnerabilities detected by taint analysis.

Overview

CodeGraph’s autofix engine takes detected vulnerabilities (taint paths from untrusted sources to dangerous sinks) and generates concrete code patches. Two strategies are used:

  1. Template-based — pattern-matching fix templates for known vulnerability types (high confidence, >0.8)
  2. LLM-powered — fallback to LLM generation when no template matches (lower confidence, <=0.59)

All fixes are presented as unified diffs. In read-only / dry-run mode (default), no files are modified.

Quick Start

CLI

# Run security audit with autofix suggestions
python -m src.cli audit --db data/projects/postgres.duckdb --autofix

# Non-interactive CI mode
python -m src.cli exec --prompt "Fix all SQL injection findings" \
    --sandbox read-only --output-file results.json

TUI

/scenario security "Find SQL injection" --autofix

REST API

curl -X POST http://localhost:8000/api/v1/security/autofix \
  -H "Content-Type: application/json" \
  -d '{"method_name": "process_query"}'

MCP (AI Assistant)

codegraph_autofix(method_name="process_query", cwe="CWE-89")

How It Works

TaintPath
    |
    v
AutofixEngine
    |
    +---> Parse sink_location -> (file_path, line_number)
    |
    +---> Read source code window (configurable context lines)
    |
    +---> Infer vulnerability_type from sink_category
    |
    +---> Try template-based fix (AutofixGenerator)
    |         |
    |         +---> Match? Return FixSuggestion (strategy="template")
    |         |
    |         +---> No match? Fall through to LLM
    |
    +---> LLM fallback (PromptBuilder + LLM provider)
    |         |
    |         +---> Build structured prompt with taint flow context
    |         +---> Call configured LLM provider
    |         +---> Parse code from response
    |         +---> Return FixSuggestion (strategy="llm")
    |
    +---> DiffValidator
    |         |
    |         +---> Verify original code exists in file
    |         +---> Check change ratio is minimal
    |         +---> Generate unified diff
    |
    v
AutofixResult (diff, confidence, strategy, validated)

Supported Vulnerability Types

Vulnerability CWE Languages Templates
SQL Injection CWE-89 C, Python, Go sprintf->snprintf, %-format->params, fstring->params, concat->params, Sprintf->$1
Buffer Overflow CWE-120 C, Python, Go strcpy->strncpy, sprintf->snprintf, ctypes size limit, CGO strncpy
Command Injection CWE-78 C, Python, Go system->execv, shell=True->shlex, bash -c->direct
Null Dereference CWE-476 C NULL check if, NULL check Assert
Use-After-Free CWE-416 C NULL after free
Info Disclosure CWE-200 C Sanitize error messages

Confidence Scoring

Strategy Confidence Range Meaning
Template (simple pattern) 0.8 - 1.0 High confidence, safe to apply
Template (complex transform) 0.6 - 0.8 Good confidence, review recommended
LLM-generated <= 0.59 Lower confidence, manual review required
Failed validation 0.0 Diff does not apply cleanly

Confidence calculation: - Base: autofix_base (default 0.7) - Simple patterns boost: +autofix_pattern_boost (default +0.2) - Complex transforms penalty: +autofix_complexity_penalty (default -0.1) - Short code bonus: +autofix_context_boost (default +0.1)

Configuration Reference

In config.yaml:

autofix:
  enabled: true                    # Enable autofix engine
  context_lines_before: 5          # Lines of context before target line
  context_lines_after: 5           # Lines of context after target line
  llm_max_confidence: 0.6          # Max confidence for LLM fixes
  llm_temperature: 0.1             # LLM temperature (low for deterministic)
  llm_max_tokens: 2048             # Max tokens for LLM response
  max_fixes_per_run: 10            # Limit fixes per invocation
  require_approval: true           # Require approval before applying

Confidence tuning in config.yaml under workflows.handlers.confidence_settings:

confidence_settings:
  autofix_base: 0.7
  autofix_pattern_boost: 0.2
  autofix_complexity_penalty: -0.1
  autofix_context_boost: 0.1

Approval Flow

When require_approval: true (default), fixes are never applied silently:

  • Interactive mode (TUI/CLI): Each fix is presented with its diff for accept/decline
  • CI mode (exec): Fixes are returned as structured JSON without applying
  • MCP server: Always read-only, returns diffs only

Approval decisions: - accept — apply this fix - acceptForSession — auto-approve similar fixes (same CWE class) - decline — skip this fix - cancel — abort entire autofix run

Extending with Domain Templates

Domain-specific autofix patterns are loaded from the active domain plugin’s YAML config. To add templates for a new domain:

  1. Add patterns to src/domains/{name}/config/security.yaml under autofix_patterns:
autofix_patterns:
  sql_injection:
    - pattern_name: "domain_specific_fix"
      pattern_regex: "dangerous_func\\((.+?)\\)"
      replacement_template: "safe_func({param})"
      explanation: "Use safe_func() instead of dangerous_func()"
  1. The AutofixGenerator automatically loads these via get_autofix_patterns_from_plugin().

Examples

SQL Injection Fix (C)

Before:

sprintf(query, "SELECT * FROM t WHERE id = %s", user_input);

After:

snprintf(query, sizeof(query), "SELECT * FROM t WHERE id = %s", user_input);

Buffer Overflow Fix (C)

Before:

strcpy(dest, src);

After:

strncpy(dest, src, sizeof(dest) - 1); dest[sizeof(dest) - 1] = '\0';

SQL Injection Fix (Python)

Before:

cursor.execute("SELECT * FROM users WHERE id = %s" % user_id)

After:

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

SQL Injection Fix (Go)

Before:

db.Query(fmt.Sprintf("SELECT * FROM users WHERE id = %s", id))

After:

db.Query("SELECT * FROM users WHERE id = $1", id)