"I'll Just Scan Before Deployment" — That Mindset Is the Problem
Running security checks only right before deployment leads to:
- Discovering vulnerabilities at the last minute — skyrocketing fix costs
- Relying on humans to catch security issues during code review
- Skipping security scans for "quick fixes"
- Vulnerabilities getting merged into the main branch
Integrating security scans into CI/CD automatically detects vulnerabilities on every PR and blocks merges when critical issues are found.
Basic Setup: Slither on Every PR
Assumed Folder Structure
my-defi-project/
├── contracts/
│ ├── Token.sol
│ └── Vault.sol
├── hardhat.config.js
└── .github/
└── workflows/
└── security.yml
Basic Workflow
# .github/workflows/security.yml
name: Smart Contract Security Scan
on:
pull_request:
paths:
- 'contracts/**/*.sol' # Only run when Solidity files change
jobs:
slither:
name: Slither Analysis
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Slither
uses: crytic/slither-action@v0.4.0
id: slither
with:
target: contracts/
slither-args: '--filter-paths node_modules'
fail-on: high # Fail CI on high severity or above
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: ${{ steps.slither.outputs.sarif }}
This configuration:
- Runs automatically on every PR that changes files in contracts/
- Fails the check when HIGH severity or above vulnerabilities are found (can block merge)
- Automatically uploads results to the GitHub Security tab
Advanced Setup: Multi-Engine + PR Comments
ContractScan GitHub Action Integration
# .github/workflows/security-full.yml
name: Full Security Scan
on:
pull_request:
paths:
- 'contracts/**'
jobs:
security-scan:
name: ContractScan Analysis
runs-on: ubuntu-latest
permissions:
pull-requests: write # Permission to post PR comments
steps:
- uses: actions/checkout@v4
- name: Run ContractScan
id: scan
run: |
RESULT=$(curl -s -X POST https://contract-scanner.raccoonworld.xyz/ci/scan \
-F "file=@contracts/MyContract.sol" \
-H "X-Api-Key: ${{ secrets.CONTRACTSCAN_API_KEY }}")
echo "$RESULT" > scan-result.json
CRITICAL=$(echo "$RESULT" | jq '.severity_summary.Critical // 0')
echo "critical-count=$CRITICAL" >> $GITHUB_OUTPUT
- name: Security Gate
if: steps.scan.outputs.critical-count > 0
run: |
echo "❌ Critical vulnerabilities found. Blocking merge."
exit 1
Example automated PR comment:
## ContractScan Security Report
🔴 **1 Critical** | 🟠 **2 High** | 🟡 **3 Medium**
### Critical Issues
**[SWC-107] Reentrancy in Vault.withdraw()**
- File: `contracts/Vault.sol:45`
- The contract state is changed after an external call.
- Fix: Apply Checks-Effects-Interactions pattern
---
Full report: [View on ContractScan](https://contract-scanner.raccoonworld.xyz/report/...)
Branch Protection Rules
In GitHub Settings → Branches → Branch protection rules:
- Select
main/masterbranch - Enable Require status checks to pass before merging
- Add
Slither AnalysisorContractScan Analysischeck - Enable Require branches to be up to date
Now PRs cannot be merged unless the security scan passes.
Practical Severity Policies
Failing CI on every finding creates too many false positives and blocks development. Recommended policy:
# Apply different thresholds per environment
jobs:
security-scan:
strategy:
matrix:
include:
- branch: main
fail-on: high # main branch: block on high and above
- branch: develop
fail-on: critical # develop: block on critical only
Or allowlist specific issues:
- name: Run Slither
uses: crytic/slither-action@v0.4.0
with:
slither-args: >
--exclude-informational
--exclude-low
--filter-paths "node_modules,test"
Hardhat / Foundry Project Integration
Hardhat Projects
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- name: Compile contracts
run: npx hardhat compile
- name: Run Slither
uses: crytic/slither-action@v0.4.0
with:
node-version: '20'
hardhat: true
Foundry Projects
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
- name: Build
run: forge build
- name: Run Slither
uses: crytic/slither-action@v0.4.0
with:
foundry: true
Complete DevSecOps Pipeline
Developer commit
↓
[PR opened]
↓
GitHub Actions triggered
├── Slither static analysis (30s)
├── Semgrep pattern check (20s)
└── AI vulnerability analysis (60s)
↓
Results auto-posted as PR comment
↓
Severity gate evaluation
CRITICAL/HIGH → ❌ Merge blocked
MEDIUM/LOW → ⚠️ Warning only
↓
[Code review + fixes]
↓
Security scan passes
↓
[Final pre-deployment review]
↓
Mainnet deployment
Cost: Start Completely Free
- GitHub Actions: Free for public repos, 2,000 free minutes/month for private repos
- Slither: Open-source, free
- ContractScan free tier: 3 scans per session, no signup required
Consider paid plans as your team grows or scan volume increases. For now, you can build the entire pipeline at zero cost.
Conclusion: Automation Is the Answer to Security
Summary of what this series has covered:
- Introduction: Why smart contract security matters — immutability, direct asset control
- Reentrancy: From The DAO to Euler Finance, the CEI pattern and ReentrancyGuard
- Top 5 Vulnerabilities: Access control, overflow, oracle manipulation, flash loans, front-running
- Tool Comparison: Slither vs Mythril vs Semgrep — when to use what
- CI/CD Automation: This post — integrating security into your pipeline with GitHub Actions
Run a free scan at contract-scanner.raccoonworld.xyz before deploying a single line of code. Five minutes can save millions.