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:
- Template-based — pattern-matching fix templates for known vulnerability types (high confidence, >0.8)
- 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:
- Add patterns to
src/domains/{name}/config/security.yamlunderautofix_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()"
- The
AutofixGeneratorautomatically loads these viaget_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)