Ghost:本地授权 OSINT 案件文件工作区,SQLite 存储与来源溯源
juliosuas/ghost
Ghost 是一个本地授权的 OSINT 案件文件工作区,用 SQLite 存储调查记录并保留来源溯源,OpenAI 为可选项,--no-ai 走确定性启发式。
Local authorized OSINT case files + provenance
A local case-file workspace for authorized self-audits — SQLite storage, scope/authorization, and report provenance. Not a SaaS. Not an "AI platform."
Quick Start · Features · Installation · Demo · Roadmap · Contributing · Security
Run an authorized local investigation from a single target (username, email, phone, domain, or photo), store it as a case file, and keep a provenance trail of what ran and where evidence came from. OpenAI is optional (--no-ai is the Quick Start path).
🔍 Why Ghost?
Ghost is a case-file workspace for authorized OSINT — not a drop-in replacement for a username hunter like maigret.
Maigret (and Sherlock) are excellent at asking "does this handle exist on hundreds or thousands of sites?" Ghost's job is different: take a single authorized target, run the modules you choose, store a SQLite case file with scope and authorization, and emit a report with provenance (what ran, which source URLs were collected, what failed).
| Ghost | maigret alone | |
|---|---|---|
| Durable case files | SQLite investigations with ghost list / show / export / import |
Collection reports, not a Ghost-style case store |
| Authorization + scope | Recorded on the case and in report provenance (--authorized, --scope) |
Not a first-class case-file field |
| Multi-vector modules | Username, email, phone, domain, image, social, darkweb, geolocation | Username-focused |
| Username coverage | 70 built-in HTTP presence checks; optional Sherlock if installed | Thousands of sites with deeper per-site checks |
| Optional AI correlation | OpenAI when configured; --no-ai uses deterministic heuristics |
No |
| Local readiness | ghost doctor / --json (fails closed on insecure server defaults) |
No |
Use maigret or Sherlock when you need the widest username hunt. Use Ghost when you need that evidence stored as a defensible investigation you can retrieve, export, and hand off.
The built-in username module is an HTTP status check against 70 platforms. It can shell out to Sherlock when the binary is on PATH. It does not wrap maigret.
Compared with general OSINT suites (Maltego, SpiderFoot, Recon-ng), Ghost's current wedge is local, authorized case files + provenance, not "more transforms than everyone else." The REST API and graph JSON exist today; a dashboard HTML UI is not shipped yet. HTML/JSON reports always work; PDF needs the optional weasyprint extra.
📸 Screenshots
A terminal demo GIF belongs at docs/screenshots/demo.gif once captured from the self-audit walkthrough. That file is not in the repo yet (placeholder path only — see docs/screenshots/README.md). Until then, these SVG captures show the CLI:
✨ Features
Investigation Vectors
| Module | Description | Status |
|---|---|---|
| 🔤 Username Enumeration | 70 built-in HTTP presence checks; optional Sherlock expands coverage | ✅ |
| 📧 Email Intelligence | Validation, MX, Gravatar; HIBP when HIBP_API_KEY is set |
✅ |
| 📱 Phone OSINT | Carrier lookup, location, social media association | ✅ |
| 🌐 Domain Recon | WHOIS, DNS, subdomains, tech stack, SSL, Wayback | ✅ |
| 🖼️ Image Analysis | EXIF + hashes; reverse-search URLs; face detection if face_recognition is installed |
✅ |
| 🕵️ Social Media Deep Dive | Experimental HTTP probes (Instagram, X, Reddit, TikTok, GitHub, LinkedIn). Off by default. Opt in with --modules social. |
⚠️ experimental |
| 🌑 Dark Web Monitoring | Experimental Ahmia / paste / HIBP probes. Off by default. Opt in with --modules darkweb. |
⚠️ experimental |
Intelligence Engine
- 🤖 Optional AI correlation — OpenAI analysis only when
OPENAI_API_KEYis set;--no-aiuses deterministic heuristics - 📊 Risk Assessment — Heuristic scoring always; richer profiling when OpenAI is configured
- 🧩 Entity Resolution — Connects findings into graph-ready entities in SQLite
- 📈 Timeline Analysis — Heuristic event list from module output
Output & Reporting
- 📄 Reports — HTML and JSON always; PDF when the optional
weasyprintextra is installed - 🗺️ Entity graph API — D3-compatible JSON at
/api/investigation/<id>/graph(dashboard HTML is not shipped yet) - 🖥️ CLI — Rich interface,
ghost doctor, and case-file commands (list,show,export,import,ingest,delete) - 🔌 REST API — Flask at
python -m ghost.backend.server(loopback by default). Case-data routes requireGHOST_API_TOKEN;authorized_use: trueis still required as case-file policy.
⚡ 60-second Quick Start
Authorized self-audit, no OpenAI key, no extra OSINT binaries. Copy-paste:
git clone https://github.com/juliosuas/ghost.git cd ghost python3 -m pip install -e . python3 -m ghost doctor python3 -m ghost investigate demo_user \ --type username \ --modules username \ --no-ai \ --authorized \ --scope "authorized self-audit demo" \ --format json \ --output demo-report.json python3 -m ghost list
python3 -m ghost is the supported entrypoint (ghost/__main__.py). After pip install -e ., the ghost console script from pyproject.toml is equivalent.
ghost doctor checks SQLite, optional keys, module imports, and exposure gates. On a fresh clone it exits 1 until GHOST_SECRET_KEY and GHOST_API_TOKEN are set (and GHOST_HOST, if set, is 127.0.0.1 or localhost). That does not block the investigate command below — CLI-only self-audit never starts Flask. See Configuration.
The investigate command stores a case in SQLite and writes demo-report.json with a provenance block. Redacted sample output lives in examples/. Quick Start uses --modules username only; social and darkweb collectors are experimental, off by default, and run only when named in --modules.
Use only an authorized target (your own handle, or a synthetic name like demo_user). Full walkthrough: authorized self-audit demo.
More CLI: ghost show <id-prefix>, ghost export, ghost import, ghost delete, or python3 -m ghost with no arguments for the interactive menu.
📦 Installation
From source (supported)
git clone https://github.com/juliosuas/ghost.git cd ghost python3 -m pip install -e . # optional: python3 -m pip install -e ".[dev]" # pytest + ruff, matches CI # optional: cp .env.example .env # only if you need OpenAI or extra APIs
requirements.txt is a broader dependency pin used by the Docker image. For local CLI work, the editable install above is the path CI and the ghost script expect.
A pip or pipx install does not keep the SQLite database or investigation reports inside site-packages (those paths are wiped on reinstall or upgrade). Ghost writes them under a private home directory:
| Precedence | Database | Investigations and reports |
|---|---|---|
DATABASE_URL (if set) |
that SQLite file | still under the home below |
GHOST_HOME |
$GHOST_HOME/data/ghost.db |
$GHOST_HOME/investigations/ |
| platformdirs (default) | user_data_dir("ghost")/data/ghost.db |
user_data_dir("ghost")/investigations/ |
On Linux the platformdirs default is ~/.local/share/ghost. The home directory is created mode 0700 and the database file mode 0600. Override the home with GHOST_HOME=/var/lib/ghost (or any absolute path). A relative GHOST_HOME is resolved against the process working directory; ghost doctor warns when that happens. DATABASE_URL overrides only the database file and takes precedence over GHOST_HOME. ghost doctor prints the resolved data path and which of DATABASE_URL, GHOST_HOME, or platformdirs won.
Importing ghost.core.config calls prepare_storage() immediately. That creates the home directory and, when allowed, copies a legacy database before the CLI or API uses those paths.
If a previous install left ghost.db inside the package, Ghost copies it with the SQLite backup API (so uncheckpointed WAL data is included) into the new location once — only when the new file is absent and DATABASE_URL is unset. The original file is left in place and is never overwritten. Investigation reports that are still under the package investigations/ directory are not migrated; ghost doctor warns when those files are present.
PyPI
pip install ghost-osint is not published yet. The package name in pyproject.toml is ghost-osint; install from source until a GitHub release is tagged (see CHANGELOG.md).
Docker
git clone https://github.com/juliosuas/ghost.git cd ghost cp .env.example .env # set GHOST_SECRET_KEY and GHOST_API_TOKEN; required by env_file docker-compose up -d # REST API → http://127.0.0.1:5000 by default (loopback only; dashboard HTML is not shipped) # If .env sets GHOST_PORT, the host and the container both use that port.
The image sets GHOST_HOME=/app/ghost. Compose persists that home with named volumes ghost_data (/app/ghost/data) and ghost_investigations (/app/ghost/investigations). Those are not host binds: if ./data or ./investigations is missing, Docker would create it as root and uid 1000 could not write.
🔧 Configuration
Copy .env.example to .env and add your API keys:
| Key | Service | Required | Notes |
|---|---|---|---|
GHOST_SECRET_KEY |
Flask signing key | For ghost doctor / starting the API |
Doctor fails if missing or equal to ghost-dev-key. API refuses to start without a real secret (outside debug). CLI-only investigate does not need it. |
GHOST_HOST |
Flask bind address | No (unset = CLI-only OK) | Doctor fails if set off-loopback. Code default is 127.0.0.1. |
GHOST_API_TOKEN |
API token | For ghost doctor / Flask /api/* |
Doctor fails if empty. Send Authorization: Bearer <token> or X-Ghost-Token. /api/health is the only unauthenticated API route. |
OPENAI_API_KEY |
Optional LLM analysis | No (--no-ai / heuristic fallback) |
Not part of Quick Start. |
HIBP_API_KEY |
Have I Been Pwned | No | Paid API. |
SHODAN_API_KEY |
Shodan | No | Free tier available. |
GOOGLE_CX / GOOGLE_API_KEY |
Google Custom Search | No | Free tier available. |
TWITTER_BEARER_TOKEN |
Twitter/X API | No | Free tier available. |
IPINFO_TOKEN |
IP Geolocation | No | Free tier available. |
ghost doctor and ghost doctor --json exit non-zero when any exposure gate fails (ok: false in JSON, with checks[].name equal to the env var). Setting these variables is not required to run ghost investigate --authorized --no-ai. Do not start python -m ghost.backend.server until doctor is green.
Storage
Ghost v2 stores investigations, findings, entities, and graph relationships in
SQLite by default instead of JSON files. This gives local users durable,
queryable storage without requiring a separate database server. The file lives
under the home from the install section (<home>/data/ghost.db),
not inside the package directory.
# optional; overrides the database file only DATABASE_URL=sqlite:///ghost.db # optional; home for data/ and investigations/ GHOST_HOME=/var/lib/ghost
PostgreSQL is on the roadmap behind the storage adapter boundary. For now,
non-SQLite DATABASE_URL values fail explicitly so deployments do not silently
write data to the wrong place.
See the storage adapter boundary for the contract Ghost must satisfy before advertising non-SQLite backends.
Note: OpenAI is optional.
--no-ai(and a missing key) uses heuristic summaries. Additional keys unlock more modules (HIBP, Shodan, Google CSE, and so on).
📖 Usage
Python API
from ghost.core.investigator import GhostInvestigator investigator = GhostInvestigator() investigation = investigator.investigate( "demo_user", input_type="username", modules=["username"], scope="authorized self-audit", authorized_use=True, ) report_path = investigator.generate_report(investigation, format="json", output_path="demo-report.json")
REST API
# Start the server (refuses to bind without GHOST_SECRET_KEY + GHOST_API_TOKEN) python -m ghost.backend.server # Submit an investigation curl -X POST http://127.0.0.1:5000/api/investigate \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $GHOST_API_TOKEN" \ -d '{"target": "demo_user", "input_type": "username", "authorized_use": true, "scope": "authorized self-audit"}'
Ingest results from other tools
Sherlock finds accounts. Ghost turns them into a case file you can defend. For an authorized self-audit, or another investigation you are allowed to run, import a local report:
python3 -m ghost ingest sherlock-demo_user.csv --tool sherlock --authorized --scope "authorized self-audit"
python3 -m ghost ingest maigret-demo_user_simple.json --tool maigret --case demo_user
python3 -m ghost ingest holehe_1710000000_demo_user@example.com_results.csv --tool holehe --case demo_user@example.comghost ingest does not contact the network, launch the other tool, or run investigate. A file larger than 50 MB is refused: stat rejects it before reading, and the read itself stops after one byte past that cap. Invalid files import nothing (one database transaction). Each record stores the tool name, tool version when the file has one, the UTC ingest time, the SHA-256 of the file, and the URL exactly as written.
| Tool | What Ghost accepts |
|---|---|
| Sherlock | --csv (username,name,url_main,url_user,exists,http_status,response_time_s; exists is Claimed / Available / Unknown / Illegal / WAF). --txt (one URL per line, then Total Websites Username Detected On : N). A console transcript ([*] Checking username …, [+] Site: URL, [*] Search completed with N results), including ANSI colors. A JSON array of those CSV rows, or a site-keyed object with the same fields. Sherlock's --json flag loads a site manifest and is rejected. These files do not include a tool version. |
| Maigret | --json simple (one object keyed by site) and --json ndjson (one claimed site per line, with sitename). Rows must be Claimed, which is all Maigret writes. No tool version in the file. |
| Holehe | --csv columns name,domain,method,frequent_rate_limit,rateLimit,exists,emailrecovery,phoneNumber,others, or the error-row header that includes error. Booleans are True / False. The email is not a column: pass --case, or keep Holehe's holehe_<timestamp>_<email>_results.csv name. No tool version in the file. |
HTML and Markdown reports escape every imported field. Profile links are rendered only for http and https URLs; the stored URL is not rewritten. ghost investigate --format markdown writes the Markdown report.
🏗️ Architecture
.
├── ghost/ # Python package (`ghost` / `python -m ghost`)
│ ├── core/ # Orchestration, doctor checks, reports
│ ├── modules/ # OSINT collectors (username, email, phone, …)
│ ├── ai/ # Optional LLM analysis; heuristic fallback
│ ├── ui/ # Rich CLI
│ ├── backend/ # Flask REST API and SQLite case store
│ └── templates/ # HTML report templates
├── examples/ # Redacted sample case + expected report snippet
├── docs/ # Self-audit demo, storage contract, screenshots
└── tests/ # pytest suite (CI)
🗺️ Roadmap
- Plugin System — Drop-in custom modules with standard interface
- Geospatial Timeline — Map-based activity visualization over time
- Team Collaboration — Multi-user investigations with shared workspaces
- Telegram Bot — Run investigations from Telegram
- Export to STIX/TAXII — Threat intelligence format compatibility
- Graph Database — Neo4j backend for complex relationship mapping
- Mobile App — iOS/Android companion for field investigations
- Scheduled Monitoring — Continuous target monitoring with alerts
🤝 Contributing
Contributions are welcome! Here's how to get started:
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-module - Commit your changes:
git commit -m "Add amazing module" - Push to the branch:
git push origin feature/amazing-module - Open a Pull Request
CI runs Ruff and pytest on Python 3.10, 3.11, and 3.12, and pip-audit on Python 3.12. PRs should include proof plus screenshots or terminal output when user-facing behavior changes.
Good first issues and docs questions have templates under .github/ISSUE_TEMPLATE/. Please do not include private target data.
Areas We Need Help
- 🌍 New OSINT modules — More platforms, more data sources
- 🧪 Testing — Unit tests, integration tests, edge cases
- 📝 Documentation — Guides, tutorials, API docs
- 🎨 Dashboard UI — First HTML frontend for the existing graph API
- 🌐 Translations — i18n support for global users
💬 Community
- GitHub Discussions — Questions, ideas, show & tell
- GitHub Issues — Bug reports & feature requests
- Security — Report vulnerabilities privately (Security tab → Report a vulnerability). Do not open a public issue.
⚠️ Legal Disclaimer
This tool is provided for authorized security research, journalism, law enforcement, and personal use only.
By using Ghost, you agree to the following:
- You are solely responsible for ensuring your use complies with all applicable local, state, national, and international laws
- Unauthorized surveillance, stalking, or harassment is illegal and unethical
- Always obtain proper authorization before investigating individuals
- Data collected may be subject to GDPR, CCPA, and other privacy regulations
- The developers assume no liability for misuse of this tool
Ghost must NOT be used to:
| ❌ Prohibited Use |
|---|
| Stalk, harass, or intimidate any person |
| Violate any person's reasonable expectation of privacy |
| Conduct unauthorized surveillance |
| Bypass access controls or terms of service |
| Engage in any illegal activity |
If you are unsure whether your use case is lawful, consult a legal professional before proceeding.
📄 License
MIT License — see LICENSE for details.
Built with 👻 by Julio
If Ghost helps your work, consider giving it a ⭐
🌱 Also check out
AI Garden — A living world built exclusively by AI agents. Watch it grow.
来源:GitHub · github.com