#!/bin/bash # ═══════════════════════════════════════════════════════════════ # gist.sh — GitHub Gist 扫描模块 # 公开 Gist 是 API key 泄露重灾区,尤其是 Jupyter notebook dump # ═══════════════════════════════════════════════════════════════ set -euo pipefail TOKEN="" REPORT_DIR="./results" LIMIT=1000 CYAN='\033[0;36m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' log_info() { echo -e "${CYAN}[*]${NC} $1"; } log_found() { echo -e "${GREEN}[+]${NC} $1"; } log_warn() { echo -e "${YELLOW}[!]${NC} $1"; } while [[ $# -gt 0 ]]; do case "$1" in --token) TOKEN="$2"; shift 2 ;; --report) REPORT_DIR="$2"; shift 2 ;; --limit) LIMIT="$2"; shift 2 ;; *) shift ;; esac done mkdir -p "$REPORT_DIR" RESULTS_FILE="${REPORT_DIR}/gist_keys.txt" > "$RESULTS_FILE" # 正则模式 REGEX='(sk-[a-zA-Z0-9]{20,}|sk-proj-[a-zA-Z0-9_-]{20,}|sk-ant-[a-zA-Z0-9-]{20,}|AIza[0-9A-Za-z\-_]{35}|hf_[a-zA-Z0-9]{34}|gsk_[a-zA-Z0-9]{52}|r8_[a-zA-Z0-9]{37}|sk-or-[a-zA-Z0-9-]{20,}|pplx-[a-zA-Z0-9]{48,})' # ── 扫描公开 gist ──────────────────────────────────────── log_info "列出公开 Gist (limit: $LIMIT)..." # 用 gh 列出 gist GIST_IDS=$(gh gist list --public --limit "$LIMIT" 2>/dev/null | awk '{print $1}') if [[ -z "$GIST_IDS" ]]; then log_warn "未找到公开 gist,尝试用 API 搜索..." # 用 GitHub search API 搜 gist 中的 key for query in "sk-proj-" "sk-ant-" "OPENAI_API_KEY" "ANTHROPIC_API_KEY" "GROQ_API_KEY" "HUGGINGFACE"; do log_info "搜索 gist: $query" gh api "search/code?q=${query}+extension:ipynb" --jq '.items[].html_url' 2>/dev/null | while read -r url; do raw_url=$(echo "$url" | sed 's|github.com|raw.githubusercontent.com|;s|/blob/||') content=$(curl -sL --max-time 10 "$raw_url" 2>/dev/null) || continue [[ -z "$content" ]] && continue echo "$content" | grep -oE "$REGEX" 2>/dev/null | while read -r key; do echo "GistMatch|${key}|${url}|Gist leak" >> "$RESULTS_FILE" log_found "Gist key: $key" done done done else log_info "扫描 $(echo "$GIST_IDS" | wc -l | tr -d ' ') 个 gist..." while read -r gist_id; do [[ -z "$gist_id" ]] && continue content=$(gh gist view "$gist_id" 2>/dev/null) || continue [[ -z "$content" ]] && continue echo "$content" | grep -oE "$REGEX" 2>/dev/null | while read -r key; do echo "GistMatch|${key}|gist:${gist_id}|Gist leak" >> "$RESULTS_FILE" log_found "Gist key: $key (gist: $gist_id)" done done <<< "$GIST_IDS" fi # ── 搜索 GitHub Gist API ───────────────────────────────── log_info "通过 GitHub API 搜索 gist 中的 key 模式..." for pattern in "sk-proj-" "sk-ant-" "AIza" "hf_" "gsk_" "r8_"; do gh api "/gists/public" --paginate --jq '.[].id' 2>/dev/null | head -200 | while read -r gid; do [[ -z "$gid" ]] && continue content=$(gh gist view "$gid" 2>/dev/null) || continue echo "$content" | grep -oE "$REGEX" 2>/dev/null | while read -r key; do grep -q "${key}" "$RESULTS_FILE" 2>/dev/null || { echo "GistAPI|${key}|gist:${gid}|Gist API leak" >> "$RESULTS_FILE" log_found "Gist API key: $key" } done done done count=$(wc -l < "$RESULTS_FILE" | tr -d ' ') log_found "Gist 扫描完成: $count 个 key" log_info "结果保存至: $RESULTS_FILE"