Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/sync-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Skill sync check

# Claude-BugHunter is the canonical home for the two recon skills this repo
# re-exports (offensive-osint, osint-methodology). This guard fails if our copies
# drift from BugHunter's — either because someone edited them here (edit them in
# BugHunter instead) or because BugHunter advanced and we haven't re-synced.

on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
schedule:
- cron: '17 6 * * 1' # weekly Monday — catch upstream drift even without a PR
workflow_dispatch:

jobs:
drift:
name: Mirrored skills match Claude-BugHunter
runs-on: ubuntu-latest
steps:
- name: Checkout claude-osint
uses: actions/checkout@v4

- name: Checkout Claude-BugHunter (canonical source)
uses: actions/checkout@v4
with:
repository: elementalsouls/Claude-BugHunter
ref: main # pin to a release tag / SHA for reproducible releases
path: _bughunter

- name: Verify the 2 mirrored skills are in sync
run: bash scripts/sync-from-bughunter.sh --from "$GITHUB_WORKSPACE/_bughunter" --check
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,9 @@ node_modules/
# Local sync artifacts
*.local.md
*.synced

# Workspace layout: the sibling Claude-BugHunter repo lives here in this checkout.
# Never let `git add -A` sweep it (or stale self-nested skill dirs) into a commit.
/Bug Hunter/
skills/offensive-osint/offensive-osint/
skills/osint-methodology/osint-methodology/
33 changes: 20 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# claude-osint

> 2 paired Claude skills · **90+ recon modules** · 48 secret-regex patterns · 80+ dorks · 9 read-only credential validators · 27 attack-path templates · 4,600+ lines of structured tradecraft. Drop-in `SKILL.md` files that turn Claude into a god-mode external recon operator for authorized red-team and bug-bounty engagements.
> 2 paired Claude skills · **90+ recon modules** · 48 secret-regex patterns · 80+ dorks · 9 read-only credential validators · 27 attack-path templates · 6,000+ lines of structured tradecraft. Drop-in `SKILL.md` files that turn Claude into a god-mode external recon operator for authorized red-team and bug-bounty engagements.

Built by **[ElementalSoul](https://github.com/elementalsouls)** — GenAI Security Research.

Expand All @@ -28,7 +28,7 @@ Built by **[ElementalSoul](https://github.com/elementalsouls)** — GenAI Securi

Drop both into your Claude environment and it behaves like a senior recon analyst: it knows the techniques, the tooling, the edge cases, and the escalation paths — and it stays in scope.

~4,600 lines of structured tradecraft · 96.9% PASS on a 32-prompt self-evaluation · ~85–90% practitioner coverage for the recon phase of authorized engagements.
~6,000 lines of structured tradecraft · 96.9% PASS on a 32-prompt self-evaluation · ~85–90% practitioner coverage for the recon phase of authorized engagements.

---

Expand All @@ -37,11 +37,13 @@ Drop both into your Claude environment and it behaves like a senior recon analys
```
claude-osint/
├── skills/
│ ├── osint-methodology/SKILL.md # how to think (455 lines)
│ ├── osint-methodology/SKILL.md # how to think (~1,700 lines)
│ └── offensive-osint/
│ ├── SKILL.md # what to reach for (4,168 lines)
│ ├── scripts/secret_scan.py # stdlib-only secret scanner
│ └── scripts/h1_reference.py # HackerOne disclosed-reports reference agent
│ ├── SKILL.md # what to reach for (lean index, ~400 lines)
│ ├── references/ # 15 modular reference files (~3,900 lines)
│ ├── scripts/secret_scan.py # stdlib-only 48-pattern secret scanner
│ ├── scripts/h1_reference.py # HackerOne disclosed-reports reference agent
│ └── scripts/dashboard.py # local recon console (stdlib web UI)
├── docs/ # architecture · coverage · install · usage
├── examples/ # 4 end-to-end engagement walk-throughs
├── tests/smoke-test-prompts.md # 32-prompt self-evaluation
Expand All @@ -50,6 +52,8 @@ claude-osint/

Each skill directory is self-contained. Drop into `~/.claude/skills/` and Claude auto-triggers on relevant phrases.

> **Mirrored from [Claude-BugHunter](https://github.com/elementalsouls/Claude-BugHunter).** That repo is the canonical monorepo home for all skills; this repo re-exports the two recon skills. **Edit them in BugHunter, not here** — maintainers re-sync with `scripts/sync-from-bughunter.sh`, and a CI guard (`.github/workflows/sync-check.yml`) fails on drift.

---

## Skill Index
Expand Down Expand Up @@ -282,17 +286,20 @@ flowchart TD
### With Claude Code

```bash
# Install both skills (one-time, after clone)
git clone https://github.com/elementalsouls/Claude-OSINT.git
cd Claude-OSINT
chmod +x ./scripts/sync-skill-content.sh
./scripts/sync-skill-content.sh
mkdir -p ~/.claude/skills
cp -r skills/osint-methodology ~/.claude/skills/
cp -r skills/offensive-osint ~/.claude/skills/
ls ~/.claude/skills/
bash scripts/install.sh # copies both skills + records an install manifest
```

The installer is idempotent (skips a skill already present and identical) and writes
a manifest so you can later run `bash scripts/install.sh --uninstall` to remove exactly
this bundle's footprint. Prefer a plain copy? `cp -r skills/* ~/.claude/skills/` still works.

> **Safe alongside [Claude-BugHunter](https://github.com/elementalsouls/Claude-BugHunter).**
> These two recon skills are shared with that bundle (canonically maintained there). Both
> installers record a manifest, so installing both is idempotent and `--uninstall` keeps any
> skill the other bundle still owns — uninstalling one never breaks the other.

Then, in any Claude Code session, ask an OSINT question — both skills auto-load and trigger on relevant phrases (50+ trigger phrases each).

### With the Claude Skills System
Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ If you used these skills during an authorized engagement and found a vulnerabili
## Security best practices for users

- Pin the skill version (`v2.1`) in any production deployment.
- Run `scripts/sync-skill-content.sh` (or manual cp) only against this repo's bundled `docs/full-skills/` files; don't fetch from arbitrary sources.
- Install skills only by copying this repo's bundled `skills/*/` directories; don't fetch skill content from arbitrary sources.
- Verify SHA-256 of any binary helper scripts before execution.
- Don't commit your engagement-specific notes into a fork of this repo.
- Use sock-puppet GitHub accounts when contributing if your engagement persona shouldn't be linked to your contributor identity.
23 changes: 3 additions & 20 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@ Claude Code looks for skills in `~/.claude/skills/` by default.
git clone https://github.com/elementalsouls/Claude-OSINT.git
cd Claude-OSINT

# Optional: populate full SKILL.md content from bundled full-skills (one-time after clone)
./scripts/sync-skill-content.sh

# Copy both skills into your local Claude Code skills directory
# (skills/*/SKILL.md ship with full content — no populate step needed)
mkdir -p ~/.claude/skills
cp -r skills/osint-methodology ~/.claude/skills/
cp -r skills/offensive-osint ~/.claude/skills/
Expand All @@ -29,12 +27,9 @@ mkdir -p ~/.claude/skills

ln -sf ~/.local/share/Claude-OSINT/skills/osint-methodology ~/.claude/skills/osint-methodology
ln -sf ~/.local/share/Claude-OSINT/skills/offensive-osint ~/.claude/skills/offensive-osint

cd ~/.local/share/Claude-OSINT
./scripts/sync-skill-content.sh # one-time
```

Then `git -C ~/.local/share/Claude-OSINT pull && ./scripts/sync-skill-content.sh` periodically.
Then `git -C ~/.local/share/Claude-OSINT pull` periodically to stay current.

### Verify install

Expand Down Expand Up @@ -116,23 +111,11 @@ The skill's `triggers:` list controls auto-activation. If your prompt's wording
- Try rephrasing with a phrase from the SKILL.md `triggers:` list.
- If your phrasing is a common practitioner term, [open an issue](https://github.com/elementalsouls/Claude-OSINT/issues) to add it.

### "I get the structured-outline SKILL.md, not the full content"

By default we ship structured-outline SKILL.md files (small, fast to load). To get full inline content:

```bash
cd <repo>
./scripts/sync-skill-content.sh
```

This populates `skills/*/SKILL.md` with the full content from `docs/full-skills/*.SKILL.full.md`.

### "Skill is too large for my model's context"

Both skills together are ~5,500 lines / ~150 KB. This fits comfortably in modern Claude context windows (200K+). If you're using an older model with smaller context:

- Use the structured-outline SKILL.md files (don't run sync-skill-content.sh).
- Or attach only one skill at a time, depending on the task.
- Attach only one skill at a time, depending on the task.
- Or run a model with larger context (Claude Sonnet 4.6+, Opus 4.6+).

### "I want to filter the skill content"
Expand Down
26 changes: 26 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,29 @@ See [`../examples/`](../examples/) for end-to-end walkthroughs:
- `02-bug-bounty-workflow.md` — full HackerOne engagement
- `03-identity-fabric-mapping.md` — M365 deep enum
- `04-secret-hunting.md` — leaked-credential workflow

## Local dashboard (optional)

A zero-dependency (stdlib-only) localhost web UI ships alongside the skill at
[`../skills/offensive-osint/scripts/dashboard.py`](../skills/offensive-osint/scripts/dashboard.py).
It wraps the bundled helpers in a browser console — no Flask, no pip install.

```bash
python3 skills/offensive-osint/scripts/dashboard.py # http://127.0.0.1:8765
python3 skills/offensive-osint/scripts/dashboard.py --open # also open a browser tab
python3 skills/offensive-osint/scripts/dashboard.py --port 9000
```

Three tabs:

- **Secret Scan** — point it at a repo/file path; runs `secret_scan.py` recursively
(binaries, `.git`, `node_modules` skipped) and renders findings with severity/category
aggregation, live filtering, and JSON/CSV export.
- **Paste & Scan** — paste JS, configs, env dumps, or response bodies; scanned fully
**offline** against the 48-pattern catalog.
- **HackerOne Ref** — queries the public disclosed-report corpus via `h1_reference.py`
(this tab is the only one that makes outbound HTTPS requests).

**Safety:** binds to `127.0.0.1` only by default. The scan API reads local files the
operator points it at, so binding to a non-loopback address prints a warning — only do
that on a trusted, isolated host.
81 changes: 81 additions & 0 deletions scripts/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/usr/bin/env bash
# =====================================================================
# install.sh — install the claude-osint recon skills into ~/.claude/skills/
#
# Copies the two skills (osint-methodology, offensive-osint) and records an
# install manifest so they can be cleanly removed later. These two skills are
# shared with — and canonically maintained in — Claude-BugHunter. Both bundles
# record a manifest, so uninstalling EITHER keeps a skill the other still owns.
#
# bash scripts/install.sh install
# bash scripts/install.sh --uninstall remove (keeps skills BugHunter still owns)
# -h | --help show this help
# =====================================================================
set -e

REPO_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
SKILLS=(osint-methodology offensive-osint)
DEST="$HOME/.claude/skills"
BACKUP_DEST="$HOME/.claude/install-backups/$(date +%Y%m%d-%H%M%S)"
BUNDLE_NAME="claude-osint"
MANIFEST_DIR="$HOME/.claude/.skill-manifests"
MANIFEST="$MANIFEST_DIR/$BUNDLE_NAME.txt"

usage() { sed -n '2,/^# ===/p' "$0" | sed 's/^#\{0,1\} \{0,1\}//'; }

DO_UNINSTALL=0
while [ $# -gt 0 ]; do
case "$1" in
--uninstall) DO_UNINSTALL=1 ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown option: $1 (try --help)" >&2; exit 2 ;;
esac
shift
done

uninstall_bundle() {
if [ ! -f "$MANIFEST" ]; then
echo "No manifest at $MANIFEST — nothing tracked to uninstall."
return 0
fi
echo "Uninstalling $BUNDLE_NAME using $MANIFEST"
local rel target other owned removed=0 kept=0
while IFS= read -r rel; do
[ -z "$rel" ] && continue
target="$HOME/.claude/$rel"
owned=0
for other in "$MANIFEST_DIR"/*.txt; do
[ -e "$other" ] || continue
[ "$other" = "$MANIFEST" ] && continue
if grep -qxF "$rel" "$other" 2>/dev/null; then owned=1; break; fi
done
if [ "$owned" = "1" ]; then kept=$((kept + 1)); else rm -rf "$target"; removed=$((removed + 1)); fi
done < "$MANIFEST"
rm -f "$MANIFEST"
echo " ✓ removed $removed item(s); kept $kept still owned by another bundle (e.g. claude-bughunter)"
}

if [ "$DO_UNINSTALL" = "1" ]; then uninstall_bundle; exit 0; fi

mkdir -p "$DEST" "$MANIFEST_DIR"
echo "Installing $BUNDLE_NAME skills → $DEST"
for name in "${SKILLS[@]}"; do
src="$REPO_DIR/skills/$name"
if [ ! -d "$src" ]; then echo " ⚠ missing $src — skipping"; continue; fi
if [ -d "$DEST/$name" ] && [ ! -L "$DEST/$name" ]; then
if diff -rq --exclude=__pycache__ "$src" "$DEST/$name" >/dev/null 2>&1; then
echo " = $name already present and identical — skipped"
else
mkdir -p "$BACKUP_DEST"; mv "$DEST/$name" "$BACKUP_DEST/$name"
cp -r "$src" "$DEST/$name"; echo " ✓ $name installed (previous backed up to $BACKUP_DEST)"
fi
else
cp -r "$src" "$DEST/$name"; echo " ✓ $name installed"
fi
done

{ for name in "${SKILLS[@]}"; do echo "skills/$name"; done; } > "$MANIFEST"
echo " ✓ Install manifest → $MANIFEST"
echo ""
echo "Done. Both skills auto-trigger in Claude Code. Uninstall later:"
echo " bash scripts/install.sh --uninstall"
84 changes: 84 additions & 0 deletions scripts/sync-from-bughunter.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/usr/bin/env bash
# sync-from-bughunter.sh — mirror the shared recon skills FROM Claude-BugHunter.
#
# Claude-BugHunter is the canonical monorepo home for ALL skills. Claude-OSINT
# re-exports two of them (offensive-osint, osint-methodology). This script copies
# those two skill directories from a BugHunter checkout into this repo so the two
# copies never drift. EDIT THE SKILLS IN BUGHUNTER, NOT HERE.
#
# Usage:
# ./scripts/sync-from-bughunter.sh --from /path/to/Claude-BugHunter # sync (overwrites local copies)
# ./scripts/sync-from-bughunter.sh --from /path/to/Claude-BugHunter --check # drift check only (CI; non-zero on drift)
# BUGHUNTER_DIR=/path/to/Claude-BugHunter ./scripts/sync-from-bughunter.sh # env-var form
#
# With no --from / $BUGHUNTER_DIR, a few common sibling locations are probed.
# --check is intended for CI, where .gitattributes guarantees LF on both sides.

set -euo pipefail

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SKILLS=(offensive-osint osint-methodology)

BUGHUNTER_DIR="${BUGHUNTER_DIR:-}"
CHECK_ONLY=false

while [ $# -gt 0 ]; do
case "$1" in
--from) BUGHUNTER_DIR="${2:-}"; shift 2 ;;
--check|-c) CHECK_ONLY=true; shift ;;
--help|-h) grep '^#' "$0" | sed 's/^# \?//'; exit 0 ;;
*) echo "Unknown argument: $1 (try --help)" >&2; exit 2 ;;
esac
done

# Probe common locations if not given explicitly.
if [ -z "$BUGHUNTER_DIR" ]; then
for c in \
"$REPO_ROOT/Bug Hunter/Claude-BugHunter" \
"$REPO_ROOT/../Claude-BugHunter" \
"$HOME/security-research/Claude-BugHunter"; do
if [ -d "$c/skills" ]; then BUGHUNTER_DIR="$c"; break; fi
done
fi

if [ -z "$BUGHUNTER_DIR" ] || [ ! -d "$BUGHUNTER_DIR/skills" ]; then
echo "✗ Claude-BugHunter repo not found. Pass --from <path> or set BUGHUNTER_DIR." >&2
exit 2
fi

echo "==> Source of truth: $BUGHUNTER_DIR"
drift=0

for s in "${SKILLS[@]}"; do
SRC="$BUGHUNTER_DIR/skills/$s"
DST="$REPO_ROOT/skills/$s"
if [ ! -d "$SRC" ]; then
echo " ✗ source missing: $SRC" >&2
exit 2
fi
if [ "$CHECK_ONLY" = true ]; then
# Exclude python caches: sync strips them from the destination, so a stray
# __pycache__ in the source would otherwise report spurious drift (locally;
# CI checkouts never have one).
if diff -rq --exclude=__pycache__ --exclude='*.pyc' "$SRC" "$DST" >/dev/null 2>&1; then
echo " ✓ $s: in sync"
else
echo " ✗ $s: DRIFT (run without --check to re-sync, or edit in BugHunter)"
drift=1
fi
else
rm -rf "$DST"
mkdir -p "$DST"
cp -r "$SRC/." "$DST/"
find "$DST" -name __pycache__ -type d -prune -exec rm -rf {} + 2>/dev/null || true
echo " ✓ $s: synced from BugHunter"
fi
done

if [ "$CHECK_ONLY" = true ]; then
[ "$drift" -eq 0 ] && echo "==> In sync with BugHunter." || echo "==> DRIFT detected." >&2
exit "$drift"
fi

echo "==> Done. The 2 recon skills are mirrored from BugHunter."
echo " Reminder: edit these skills in Claude-BugHunter, then re-run this script."
Loading