AI & CI/CD

AI Explanation Layer

The AI layer is an optional component that translates structured findings from the rule engine into plain-language developer guidance. It does not make security decisions.

Important: The AI explanation layer is completely optional. If you do not configure an API key, all findings will still be emitted with full rule metadata, severity, and suggestions — just without the AI narrative.

What the AI layer does

After the rule engine produces structured findings, the AI layer (if enabled) does the following for each finding:

  • Receives the rule ID, severity, code snippet, and rule suggestion
  • Constructs a focused prompt that describes the finding
  • Calls the configured language model
  • Returns a plain-language explanation of the issue and how to fix it
  • Populates the explanation field in the JSON output

What the AI layer does NOT do

  • It does not determine whether a finding is a real vulnerability
  • It does not add or remove findings
  • It does not modify severity levels
  • It does not have access to the full contract source (only the relevant snippet)
  • It cannot produce false positives from its own inference
Note: The boundary between the rule engine and the AI layer is intentional. It means AI-related failures (rate limits, model errors, bad keys) never affect the core security analysis.

Enabling AI explanations

Set your API key

auth
# Set via environment variable
$export OPENAI_API_KEY=sk-your-api-key-here

Run the explain command

optional
# Plain text output with AI explanations
$openaudit-ai explain ./contracts
# JSON output with explanation field populated
$openaudit-ai explain ./contracts --json

Example output

finding with explanationjson
{
  "ruleId": "reentrancy-guard",
  "severity": "CRITICAL",
  "file": "contracts/Token.sol",
  "line": 147,
  "message": "External call precedes state update",
  "explanation": "The withdraw() function sends ETH to msg.sender before zeroing the user's balance stored in balances[msg.sender]. A malicious contract can implement a receive() function that calls withdraw() again before the first call completes, since the balance has not been zeroed yet. This is a classic reentrancy attack and can drain all ETH from the contract.\n\nFix: Move balances[msg.sender] = 0 above the .call() invocation, or apply OpenZeppelin's ReentrancyGuard modifier to the function.",
  "suggestion": "Move all state updates before external calls."
}

Configuration

ConfigDefaultDescription
OPENAI_API_KEYRequired. OpenAI-compatible API key.
--modelgpt-4o-miniLanguage model to use for explanations.
OPENAUDIT_AI_TIMEOUT30sTimeout for AI explanation requests.