Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions .github/workflows/security-audit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: EVM Security Audit

on:
pull_request:
paths:
- ".github/workflows/security-audit.yml"
- "contracts/evm/**"
- "scripts/security/**"
- "docs/security-audit.md"
push:
branches:
- main
- dev
paths:
- ".github/workflows/security-audit.yml"
- "contracts/evm/**"
- "scripts/security/**"
- "docs/security-audit.md"
workflow_dispatch:
inputs:
severity_threshold:
description: "Fail on new unsuppressed findings at or above this severity"
required: false
default: "medium"
mythril_timeout:
description: "Per-contract Mythril timeout in seconds"
required: false
default: "900"
Comment on lines +25 to +28

permissions:
contents: read

jobs:
evm-security-audit:
name: Slither and Mythril
runs-on: ubuntu-latest
timeout-minutes: 45

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
cache: "pip"

- name: Install analysis tools
run: |
python -m pip install --upgrade pip
python -m pip install slither-analyzer mythril

- name: Run Slither and Mythril
env:
SEVERITY_THRESHOLD: ${{ inputs.severity_threshold || 'medium' }}
MYTHRIL_TIMEOUT: ${{ inputs.mythril_timeout || '900' }}
Comment on lines +56 to +57
run: |
python scripts/security/run_evm_audit.py \
--contracts-dir contracts/evm \
--out-dir security-reports/evm \
--baseline contracts/evm/security-baseline.json \
--suppressions contracts/evm/security-suppressions.json \
--severity-threshold "$SEVERITY_THRESHOLD" \
--timeout "$MYTHRIL_TIMEOUT"

- name: Publish audit summary
if: always()
run: |
if [ -f security-reports/evm/summary.md ]; then
cat security-reports/evm/summary.md >> "$GITHUB_STEP_SUMMARY"
fi

- name: Upload audit reports
if: always()
uses: actions/upload-artifact@v4
with:
name: evm-security-audit
path: security-reports/evm
if-no-files-found: warn
23 changes: 23 additions & 0 deletions contracts/evm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# EVM Security Audit Configuration

This directory is the reserved home for Solidity/EVM contracts and their security audit configuration. The CI pipeline in `.github/workflows/security-audit.yml` scans every `.sol` file under this directory with Slither and Mythril.

## Files

- `slither.config.json` configures Slither without excluding detectors.
- `security-suppressions.json` records reviewed false positives.
- `security-baseline.json` tracks accepted historical findings so CI can gate on new medium-or-higher severity findings.

## Local Run

```bash
python -m pip install slither-analyzer mythril
python scripts/security/run_evm_audit.py \
--contracts-dir contracts/evm \
--out-dir security-reports/evm \
--baseline contracts/evm/security-baseline.json \
--suppressions contracts/evm/security-suppressions.json \
--severity-threshold medium
```

The runner exits with a non-zero status when it finds a new, unsuppressed finding at or above the configured severity threshold.
5 changes: 5 additions & 0 deletions contracts/evm/security-baseline.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"version": 1,
"description": "Historical Slither/Mythril findings accepted by maintainers. Add normalized finding ids only after review.",
"findings": []
}
5 changes: 5 additions & 0 deletions contracts/evm/security-suppressions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"version": 1,
"description": "Reviewed false positives for the EVM security audit pipeline. Prefer narrow matches and include an expiry when possible.",
"suppressions": []
}
6 changes: 6 additions & 0 deletions contracts/evm/slither.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"exclude_dependencies": true,
"filter_paths": "node_modules|lib|script|test|mock|mocks",
"detectors_to_exclude": "",
"fail_on": "none"
}
43 changes: 43 additions & 0 deletions docs/security-audit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# EVM Security Audit Pipeline

The EVM security audit workflow runs Slither and Mythril against Solidity contracts in `contracts/evm`. It is designed to keep scans deterministic enough for pull requests while still preserving full raw tool output as CI artifacts.

## What The Pipeline Checks

- Slither runs with all detectors enabled and emits raw JSON output.
- Mythril runs symbolic execution for each Solidity source file with a bounded timeout.
- Findings are normalized into `security-reports/evm/findings.json`.
- The workflow fails on new, unsuppressed findings at `medium` severity or higher.
- Raw reports, normalized findings, logs, and a Markdown summary are uploaded as artifacts.

## Severity Gate

Severity is normalized to one of `informational`, `low`, `medium`, `high`, or `critical`. The default gate is `medium`, which means any new unsuppressed `medium`, `high`, or `critical` finding fails CI.

The threshold can be changed for manual runs through the `severity_threshold` workflow input.

## Historical Tracking

Reviewed historical findings live in `contracts/evm/security-baseline.json`. A finding in the baseline is still reported, but it does not fail CI. New findings are identified by stable normalized ids built from the tool, detector/SWC id, source location, and description.

## False Positive Suppression

Use `contracts/evm/security-suppressions.json` for narrow suppressions when a finding has been reviewed and confirmed as a false positive. Suppressions can match by exact `id` or by fields such as `tool`, `check`, `source`, and `severity`.

Keep suppressions specific, include a reason, and prefer adding an `expires` date for temporary cases.

Example:

```json
{
"tool": "slither",
"check": "reentrancy-eth",
"source": "contracts/evm/Vault.sol:120",
"reason": "State update happens before the external call through a guarded adapter.",
"expires": "2026-12-31"
}
```

## No EVM Contracts Yet

If no `.sol` files exist under `contracts/evm`, the runner writes an empty report and exits successfully. This keeps CI green until EVM contracts are added while preserving the audit gate for future Solidity code.
Loading