-
Notifications
You must be signed in to change notification settings - Fork 202
Add Python security audit script, remove invalid demo metadata #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: megaeth-mainnet
Are you sure you want to change the base?
Changes from all commits
5e06c00
fe10f88
7090e90
9c2b707
68817ac
82fe47e
d3e75b2
4ea9100
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| name: Security Audit | ||
|
|
||
| on: | ||
| push: | ||
| paths: | ||
| - '_data/chains/**' | ||
| - 'scripts/security_audit.py' | ||
| pull_request: | ||
| paths: | ||
| - '_data/chains/**' | ||
| - 'scripts/security_audit.py' | ||
|
|
||
| jobs: | ||
| audit: | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v3 | ||
|
|
||
| - name: Set up Python | ||
| uses: actions/setup-python@v4 | ||
| with: | ||
| python-version: '3.12' | ||
|
|
||
| - name: Install dependencies | ||
| run: pip install requests | ||
|
|
||
| - name: Run security audit script | ||
| run: python scripts/security_audit.py |
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The GitHub username "Mrthang0597" has an uppercase "M", but GitHub usernames are case-insensitive and typically written in lowercase. For consistency, you might want to change "github": "Mrthang0597" to "github": "mrthang0597". The field "contribution": "metadata update or data contribution" is fine, but if possible, specify the exact type of contribution for clarity (e.g., "metadata update"). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| { | ||
| "name": "MrThang0597", | ||
| "github": "Mrthang0597", | ||
| "contribution": "metadata update or data contribution", | ||
| "date": "2025-10-12" | ||
| } |
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In is_valid_ipfs(cid), the regex assumes all CIDs are 46 alphanumeric chars. However, IPFS CIDs can be both v0 (Qm…) and v1 (bafy…). Consider using a more flexible CID validation or a library for robustness. In audit_chain(), the variable cid is used for both chainId and as an IPFS CID. Consider renaming one for clarity. The script loads icon metadata files as JSON but assumes they are lists. Consider catching exceptions for malformed files for robustness. Requests is imported but never used; you can remove import requests unless you plan to use it. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| import json | ||
| import os | ||
| import glob | ||
| import re | ||
| import requests | ||
| from urllib.parse import urlparse | ||
|
|
||
| CHAINS_DIR = "_data/chains" | ||
| WHITELIST_RPC_DOMAINS = ["infura.io", "alchemyapi.io", "ankr.com", "cloudflare-eth.com"] | ||
|
|
||
| def is_http_url_insecure(url): | ||
| return url.startswith("http://") | ||
|
|
||
| def domain_from_url(url): | ||
| try: | ||
| return urlparse(url).netloc.lower() | ||
| except Exception: | ||
| return None | ||
|
|
||
| def is_untrusted_domain(url): | ||
| domain = domain_from_url(url) | ||
| if domain: | ||
| return not any(d in domain for d in WHITELIST_RPC_DOMAINS) | ||
| return True | ||
|
|
||
| def is_valid_ipfs(cid): | ||
| return re.fullmatch(r"[A-Za-z0-9]{46}", cid) is not None | ||
|
|
||
| def audit_chain(chain, filename): | ||
| findings = [] | ||
| cid = chain.get("chainId") | ||
| name = chain.get("name") | ||
|
|
||
| if cid == 1 and name != "Ethereum Mainnet": | ||
| findings.append(f"[ERROR] {filename}: ChainId 1 must be Ethereum Mainnet") | ||
|
|
||
| for url in chain.get("rpc", []): | ||
| if is_http_url_insecure(url): | ||
| findings.append(f"[ERROR] {filename}: Insecure RPC URL: {url}") | ||
| if is_untrusted_domain(url): | ||
| findings.append(f"[WARNING] {filename}: RPC domain not in trusted list: {url}") | ||
|
|
||
| if "explorers" in chain: | ||
| for exp in chain["explorers"]: | ||
| url = exp.get("url") | ||
| if url and is_http_url_insecure(url): | ||
| findings.append(f"[WARNING] {filename}: Explorer URL not HTTPS: {url}") | ||
|
|
||
| if "icon" in chain: | ||
| icon_path = f"_data/icons/{chain['icon']}.json" | ||
| if os.path.exists(icon_path): | ||
| with open(icon_path, "r", encoding="utf-8") as f: | ||
| icon_data = json.load(f) | ||
| for icon_entry in icon_data: | ||
| url = icon_entry.get("url", "") | ||
| if url.startswith("ipfs://"): | ||
| cid = url.replace("ipfs://", "") | ||
| if not is_valid_ipfs(cid): | ||
| findings.append(f"[ERROR] {filename}: Invalid IPFS CID: {cid}") | ||
| elif is_http_url_insecure(url): | ||
| findings.append(f"[WARNING] {filename}: Insecure icon URL: {url}") | ||
| else: | ||
| findings.append(f"[ERROR] {filename}: Icon metadata not found: {icon_path}") | ||
|
|
||
| return findings | ||
|
|
||
| def run_audit(): | ||
| print("🔍 Running metadata security audit...") | ||
| files = glob.glob(os.path.join(CHAINS_DIR, "*.json")) | ||
| total_findings = 0 | ||
|
|
||
| for filepath in files: | ||
| with open(filepath, "r", encoding="utf-8") as f: | ||
| data = json.load(f) | ||
| findings = audit_chain(data, filepath) | ||
| for f in findings: | ||
| print(f) | ||
| total_findings += len(findings) | ||
|
|
||
| if total_findings == 0: | ||
| print("✅ No security issues found.") | ||
| else: | ||
| print(f"⚠️ Found {total_findings} security issues.") | ||
|
|
||
| if __name__ == "__main__": | ||
| run_audit() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The workflow should include a step to install all Python dependencies required by security_audit.py. If you add more dependencies in the future, using a requirements.txt file may be better for maintainability.
Add fail-fast: false under jobs if you plan to add more jobs in the future for better workflow management.
Optionally, add a step to check Python code formatting (e.g., with black or flake8) for code quality.