Automated evidence collection & timeline generation for verifying contest submissions
Build evidence-based timelines to verify contest submissions using public, reproducible data sources.
This toolkit collects and analyzes data from multiple authoritative sources (GH Archive, GitHub API, CT logs, urlscan, Wayback Machine, DNS history) to create a comprehensive timeline comparing deadline vs. actual behavior, helping you challenge contest results with facts.
- π Multi-Source Data Collection: Automatically gathers evidence from 6+ public sources
- β° Dual-Timezone Display: Shows all timestamps in both UTC and your local timezone
- β Deadline Verification: Automatically flags late submissions with β markers
- π Tamper-Proof Evidence: All source files include SHA256 checksums
- π Comprehensive Logging: Every operation is logged for audit trails
- π Fully Automated: One command to collect, analyze, and generate reports
- πΎ CLI-Only: No GUI required, perfect for automation and CI/CD
- Bash 4.0+ (Git Bash on Windows)
- curl (HTTP requests)
- jq (JSON processing)
- yq (YAML parsing) - Install guide
- Python 3.9+ (3.10+ recommended)
- PyYAML (
pip install PyYAML)
- GitHub Personal Access Token (avoid rate limits)
- urlscan.io API key (web scanning history)
- SecurityTrails API key (DNS history)
Quick check: Run bash scripts/check_dependencies.sh to verify all dependencies.
Auto-install: Run bash scripts/install_dependencies.sh to install missing dependencies automatically.
bash quick-start.shThis interactive script will:
- Detect your OS and install dependencies automatically
- Or set up Docker if available
- Create necessary directories
- Verify installation
Prerequisites: Docker and Docker Compose installed
# Build and run with Docker
docker-compose build
docker-compose run --rm run-case
# Or interactive shell
docker-compose run --rm forensics-toolkit
bash scripts/run_case.sh cases/sample_case.yamlAdvantages:
- β No dependency installation needed
- β Consistent environment across all platforms
- β Isolated from host system
- β Production-ready
See INSTALLATION.md for detailed platform-specific instructions.
Automatic Installation (all platforms):
bash scripts/install_dependencies.shManual Installation:
Click to expand manual installation instructions
Linux (Ubuntu/Debian):
sudo apt install bash curl jq python3 python3-pip
sudo wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq
sudo chmod +x /usr/bin/yq
pip3 install -r requirements.txtmacOS:
brew install bash curl jq yq python3
pip3 install -r requirements.txtWindows:
- Install Git for Windows (includes Git Bash)
- Install jq and yq (via Chocolatey:
choco install jq yq) - Install Python 3.9+ from python.org
- Run
pip install -r requirements.txt
bash scripts/check_dependencies.sh# Copy sample config
cp .env.sample .env
# Edit with your settings
nano .envMinimal .env configuration:
GITHUB_TOKEN=your_token_here # Get from: https://github.com/settings/tokens
LOCAL_TZ=Asia/Taipei # Your timezone# Copy sample case
cp cases/sample_case.yaml cases/my_case.yaml
# Edit with your case details
nano cases/my_case.yamlExample case file:
case_slug: my_contest_case
rules_url: https://example.org/contest/rules
deadline_local: 2025-10-06T00:00:00+08:00 # Include timezone!
targets:
date_window_utc:
start: 2025-10-01 # A few days before deadline
end: 2025-10-07 # A few days after deadline
repos:
- owner: username
name: repository-name
commits:
- abc1234567890abcdef1234567890abcdef1234 # Full commit SHA
websites:
- url: https://example.com/
domain: example.com# Using Makefile
make case CASE=cases/my_case.yaml
# Or directly
bash scripts/run_case.sh cases/my_case.yaml# View timeline report
cat outputs/my_contest_case/timeline.md
# Check all collected evidence
ls -la outputs/my_contest_case/
# Verify checksums
cat outputs/my_contest_case/sources_manifest.txt| Source | Purpose | Auth Required | Reliability |
|---|---|---|---|
| GH Archive | GitHub PushEvent server-side timestamps | No | βββββ Most reliable |
| GitHub API | Commit author/committer timestamps | Recommended | ββββ (can be manipulated) |
| Certificate Transparency | SSL certificate issuance dates | No | βββββ Append-only logs |
| urlscan.io | Historical website scans | Optional | βββ Third-party observations |
| Wayback Machine | Website snapshots | No | ββββ Timestamped archives |
| SecurityTrails | DNS history | Yes | βββ Supplementary data |
After running a case, you'll find:
outputs/<case_slug>/
βββ timeline.md # π Main report (dual-timezone, with β markers)
βββ sources_manifest.txt # π SHA256 checksums of all evidence
βββ LOG.md # π Execution log (timestamps + operations)
βββ gharchive_push_events.jsonl # Raw GH Archive data
βββ gharchive_push_events.tsv # Formatted push events
βββ github_commit_*.json # GitHub API responses
βββ ct_*.json # Certificate Transparency logs
βββ urlscan_*.json # urlscan.io results
βββ dns_*.json # DNS history (if available)
βββ wayback_*.json # Wayback Machine metadata
βββ http_probe.txt # HTTP response headers
- INSTALLATION.md - Detailed installation instructions for all platforms
- TROUBLESHOOTING.md - Common issues and solutions
- CLAUDE.md - Automation guidelines for AI assistants
- schemas/case.schema.yaml - Case file format specification
for case in cases/*.yaml; do
bash scripts/run_case.sh "$case"
doneAdjust date_window_utc in your case file to narrow or expand the search:
targets:
date_window_utc:
start: 2025-10-05 # Narrow to specific dates
end: 2025-10-06Run individual collectors:
# GH Archive only
bash scripts/gharchive_pull.sh OWNER REPO START_DATE END_DATE CASE_SLUG
# GitHub API only
bash scripts/github_commit_time.sh OWNER REPO COMMIT_SHA CASE_SLUG
# CT logs only
bash scripts/ct_lookup.sh DOMAIN CASE_SLUGMost Reliable β Least Reliable:
- βββββ GH Archive PushEvent
created_at(server-side, tamper-proof) - βββββ Certificate Transparency logs (append-only)
- ββββ Wayback Machine snapshots (timestamped by IA)
- ββββ GitHub API
committer.date(can be manipulated by client) - βββ urlscan.io (third-party observations)
- βββ GitHub API
author.date(easily manipulated)
Always use multiple sources for verification!
- GitHub without token: 60 requests/hour
- GitHub with token: 5,000 requests/hour
- urlscan.io free tier: 50 scans/day, 100 searches/day
β οΈ Always use Git Bash, not PowerShell or CMD- PowerShell's
curlis an alias forInvoke-WebRequestand won't work - Make sure yq.exe and jq.exe are in your PATH
Common Issues:
- "yq: command not found" β See INSTALLATION.md
- Python zoneinfo errors β
pip install tzdata backports.zoneinfo - GitHub rate limit β Add
GITHUB_TOKENto.env - Empty timeline β Check
LOG.md, verify date range and repo details - Permission denied β
chmod +x scripts/*.shor usebash scripts/...
For detailed solutions, see TROUBLESHOOTING.md.
Contributions welcome! Areas for improvement:
- Additional data sources (Internet Archive CDX API, etc.)
- Better error handling and retry logic
- Parallel downloads for GH Archive
- Support for more evidence types (Docker Hub, npm registry, etc.)
- Web UI for report viewing
This project is licensed under the MIT License - see the LICENSE file for details.
- GH Archive - GitHub event archive
- GitHub - Git hosting and API
- crt.sh - Certificate Transparency search
- urlscan.io - URL scanning service
- Internet Archive - Wayback Machine
- SecurityTrails - DNS history
- Issues: For bugs or feature requests, open an issue
- Documentation: Check INSTALLATION.md and TROUBLESHOOTING.md
- Dependencies: Run
bash scripts/check_dependencies.shfor diagnostics
Made with β€οΈ for fair competition and evidence-based verification.