""" Smart Contract Security Scanner Rule-based Solidity audit assistant with transparent findings and remediation notes. """ from pathlib import Path import re import pandas as pd import plotly.express as px import streamlit as st st.set_page_config(page_title="Smart Contract Security Scanner", page_icon="🔒", layout="wide") def load_shared_css() -> None: current_dir = Path(__file__).resolve().parent candidates = [ current_dir / "shared" / "styles.css", current_dir.parent / "shared" / "styles.css", ] css_path = next(path for path in candidates if path.exists()) st.markdown(f"", unsafe_allow_html=True) load_shared_css() SAMPLE_CONTRACT = """pragma solidity ^0.8.0; contract Vault { mapping(address => uint256) public balances; address public owner; function withdraw(uint256 amount) public { require(balances[msg.sender] >= amount); (bool ok, ) = msg.sender.call{value: amount}(""); require(ok); balances[msg.sender] -= amount; } function emergencyTransfer(address target, bytes memory data) public { require(tx.origin == owner); target.delegatecall(data); } } """ RULES = [ { "id": "reentrancy-call-before-state-update", "pattern": r"\.call\{value:\s*[^}]+\}\([^)]*\)", "severity": "High", "reason": "External value transfer can re-enter before state is updated.", "fix": "Apply checks-effects-interactions, update balances before the call, or use ReentrancyGuard.", }, { "id": "tx-origin-auth", "pattern": r"tx\.origin", "severity": "High", "reason": "tx.origin authentication can be phished through intermediary contracts.", "fix": "Use msg.sender and explicit role-based authorization.", }, { "id": "delegatecall", "pattern": r"\bdelegatecall\b", "severity": "Critical", "reason": "delegatecall executes target code in this contract storage context.", "fix": "Avoid delegatecall unless target code is immutable, audited, and tightly authorized.", }, { "id": "missing-events", "pattern": r"function\s+\w+[\s\S]{0,180}(balances\[|owner\s*=)", "severity": "Medium", "reason": "State-changing operations should emit events for monitoring and incident response.", "fix": "Emit events for withdrawals, ownership changes, and privileged actions.", }, { "id": "unchecked-low-level-call", "pattern": r"\.send\(|\.call\(", "severity": "Medium", "reason": "Low-level calls need explicit success handling and safe control flow.", "fix": "Check return values and prefer typed interfaces when possible.", }, ] SEVERITY_WEIGHT = {"Low": 1, "Medium": 2, "High": 4, "Critical": 6} def line_number(source: str, index: int) -> int: return source[:index].count("\n") + 1 def scan_contract(source: str) -> pd.DataFrame: findings = [] for rule in RULES: for match in re.finditer(rule["pattern"], source, re.IGNORECASE): findings.append({ "rule": rule["id"], "severity": rule["severity"], "line": line_number(source, match.start()), "evidence": source[match.start():match.end()].replace("\n", " ")[:120], "reason": rule["reason"], "fix": rule["fix"], }) return pd.DataFrame(findings) def risk_score(findings: pd.DataFrame) -> int: if findings.empty: return 0 raw = sum(SEVERITY_WEIGHT[item] for item in findings["severity"]) return min(100, int(raw / 18 * 100)) st.markdown("""
Inspect Solidity code for high-signal vulnerability patterns, explain the risk, and produce remediation notes.