DEV Community

Cover image for Jin: A Passive OSINT & Recon CLI Toolkit Built with Go
Wahyu K. A.
Wahyu K. A.

Posted on • Edited on

Jin: A Passive OSINT & Recon CLI Toolkit Built with Go

Disclaimer: This article describes a tool intended for ethical, educational, and authorized security work. Only use it against targets you own or have explicit permission to test. Unauthorized scanning is illegal in most jurisdictions.

When you start a security assessment — bug bounty, penetration test, or even just hardening your own infrastructure — the first thing you reach for is reconnaissance. You want answers to questions like:

  • What is this server actually running?
  • Which ports are exposed to the internet?
  • Is that WordPress install behind a CDN? Which framework is it using?
  • Are there subdomains I don't know about?

There are many tools that answer each of these questions. But most of them are heavyweight, require lots of setup, or spread the answers across multiple utilities with different output formats.

Jin is a single Go binary that answers all of them — with a friendly interactive shell, clean human-readable output, and JSON mode for scripting. Let me show you what it does and why I think it earns a spot in your toolkit.

What is Jin?

Jin (Just Intelligence Network) is an open-source, passive-first OSINT and reconnaissance CLI toolkit. It's an evolution of a Python project that focused on ethical port scanning, rewritten in Go and redesigned around a clean, testable architecture.

The current version ships three commands, all usable interactively or as one-shot commands:

Command What it does
info Full server reconnaissance: headers, TLS, cloud provider, plus an automated security score
ports TCP connect scan for open ports, with service detection
tech-stack Fingerprints the tech stack (CMS, frameworks, CDN, WAF...) with confidence levels and evidence
tech-stack --subdomains Also discovers subdomains from certificate transparency logs and pulls DNS records

Every command has a --json flag for structured output, so you can pipe results into other tools or CI pipelines.

Why Go?

The original version of Jin was written in Python. The rewrite in Go brings some serious quality-of-life improvements:

  • One static binary — no runtime, no virtualenv, no dependency headaches. Copy it to a box and it works.
  • Fast startup — a scan kicks off in milliseconds, which matters a lot in an interactive REPL.
  • Goroutines for concurrency — subdomain discovery and fingerprinting run in parallel.
  • Small container footprint — the Docker image is Alpine-based and statically linked.
  • Clean architecture — the codebase uses hexagonal (ports & adapters) design, which makes the tool easy to extend with new scanners without touching the domain logic.

The three commands

Let's walk through each command with real output shapes.

1. info — full server reconnaissance

Point Jin at any URL and it fetches the response, extracts the interesting headers, detects the cloud provider, and — my favorite part — produces a weighted security report with a letter grade:

🌐 URL:          https://example.com
🗃️  Base Domain:  example.com
☁️  Cloud:        Cloudflare
✅ Status:       200
🖥️  Server:      cloudflare
📄 Content-Type: text/html; charset=UTF-8
⏱️  Scan Time:   423ms

🔒 TLS Version:  TLS 1.3
🔐 Cipher Suite: TLS_AES_128_GCM_SHA256

🛡️  Security Insights: B+ (82/100)
  ✅ TLS:                       Serving over TLS 1.3
  ⚠️  HSTS:                     Missing Strict-Transport-Security header
  ✅ Content-Security-Policy:   Policy enforced
  ✅ X-Frame-Options:           Clickjacking protection enforced
  ✅ X-Content-Type-Options:    nosniff set
  ✅ Referrer-Policy:           Set to strict-origin-when-cross-origin
  ℹ️  Permissions-Policy:        Not set
  ✅ Cookie Flags:              No obvious cookie issues
  ✅ CORS:                      Restricted to: https://app.example.com
  ✅ Version Disclosure:        No version numbers exposed in Server/X-Powered-By

📋 Headers:
  cache-control:       max-age=0, private, must-revalidate
  content-encoding:    br
  content-security-policy: default-src 'self'; ...
  set-cookie:          __cf_bm=<redacted> [Secure, HttpOnly, SameSite=None]
  ...
Enter fullscreen mode Exit fullscreen mode

The security checks cover the OWASP-relevant quick wins: TLS, HSTS, Content-Security-Policy (including a linter that flags unsafe-inline, unsafe-eval, and overly broad sources), X-Frame-Options, nosniff, Referrer-Policy, Permissions-Policy, cookie flags (Secure / HttpOnly / SameSite), CORS misconfigurations (like * combined with credentials=true), and version disclosure in headers.

Each check has a weight, so the final score is a genuine 0–100 weighted grade (A+ down to F) — not just a checklist. Notice the set-cookie header above: cookie values are redacted in output while security-relevant attributes are preserved, because you don't want to leak a real session token into a report.

You can also run jin https://example.com directly — a bare URL is treated as an info scan.

2. ports — TCP connect scan

Jin scans a curated default list of common services, or your own:

🔍 Open ports:
  22/ssh
  80/http
  443/https
  5432/postgresql
Enter fullscreen mode Exit fullscreen mode
jin ports -t example.com -p 80,443,8080,8443
Enter fullscreen mode Exit fullscreen mode

Default ports include FTP, SSH, SMTP, DNS, HTTP(S), mail, MySQL, PostgreSQL, Redis, and MongoDB — and you can pass a comma-separated custom list with -p. Each port is mapped to its service name, and output is clean enough to grep or script against.

3. tech-stack — fingerprinting, subdomains & DNS

This is the most fun one. Jin fingerprints a target across 13 categories — CMS, web server, backend runtime, programming language, web framework, JS framework, JS library, CSS framework, WAF/reverse proxy, analytics, CDN, security, and other:

🧩 Stack:  WordPress, Nginx, PHP, jQuery, Cloudflare
⏱️  Scan Time: 1.2s

▸ CMS
  WordPress (6.5.2)          High (80%)
    • Meta tag: generator=WordPress 6.5.2
▸ Web Server
  Nginx                      Very High (97%)
    • Header: Server: nginx
▸ Programming Language
  PHP                        High (80%)
    • Header: X-Powered-By: PHP/8.2.9
▸ JavaScript Library
  jQuery (3.7.1)             High (80%)
    • Markup: jquery-3.7.1.min.js
▸ WAF / Reverse Proxy
  Cloudflare                 Very High (97%)
    • Header: Server: cloudflare
Enter fullscreen mode Exit fullscreen mode

Every detection comes with a confidence level and the evidence that produced it — the actual header value, meta tag, cookie, or script path. No black box.

Run it with --subdomains (or -s) and Jin goes deeper:

jin tech-stack -t example.com --subdomains
Enter fullscreen mode Exit fullscreen mode
  • Subdomain discovery queries crt.sh, the public certificate transparency log. This is a purely passive technique — it reads public certificate data and never sends a single packet to the target, so there's no scanning footprint.
  • Each discovered subdomain is probed and fingerprinted independently, so you get a map of the whole attack surface: blog.example.com runs WordPress, api.example.com runs Express, mail.example.com is unreachable.
  • DNS records (nameservers, MX, TXT) are pulled with the Go standard library, which is great for spotting SPF/DKIM/DMARC posture and hosting infrastructure at a glance:
🗂️  DNS Records:
  Nameservers: ns1.cloudflare.com, ns2.cloudflare.com
  MX Records:  aspmx.l.google.com, ...
  TXT Records:
    • v=spf1 include:_spf.google.com ~all
    • google-site-verification=...
Enter fullscreen mode Exit fullscreen mode

The interactive REPL

Running jin with no arguments drops you into a proper REPL — not a crude loop, but a real readline shell:

jin
jin> https://example.com
jin> ports -t example.com -p 80,443
jin> tech-stack -t example.com --subdomains
jin> exit
Enter fullscreen mode Exit fullscreen mode

Nice touches that make it genuinely usable for research sessions:

  • Tab completion for all commands.
  • Command history persisted to ~/.jin_history.
  • Up/Down arrow to recall previous commands.
  • Ctrl+C aborts the in-flight scan and exits cleanly; exit/quit/Ctrl+D (EOF) also work.
  • Even a plain line reader fallback when stdin isn't a TTY.

One-shot usage still works exactly as before, which keeps Docker and scripting happy:

jin ports -t example.com
jin tech-stack -t example.com --subdomains --json | jq '.categories'
Enter fullscreen mode Exit fullscreen mode

JSON output for automation

Every command accepts --json. The output is a stable, well-shaped document designed for parsing — with scanned_at, duration_ms, and machine-friendly fields. For example, the tech-stack JSON groups detections by category and includes per-technology evidence and confidence scores, plus the subdomain and DNS sections when requested.

This makes Jin easy to slot into recon pipelines, dashboards, or internal asset-discovery tooling.

Installation

From source

Requires Go 1.25+:

git clone https://github.com/sapiuwu/jin.git
cd jin
go build -o jin ./cmd/
./jin
Enter fullscreen mode Exit fullscreen mode

With Docker

docker pull wahyouka/jin:v2.3.0

# interactive REPL
docker run -it --entrypoint jin wahyouka/jin:v2.3.0

# one-shot
docker run -it wahyouka/jin:v2.3.0 tech-stack -t example.com --subdomains
Enter fullscreen mode Exit fullscreen mode

The image is a static, Alpine-based build with CA certificates and timezone data baked in.

A peek under the hood

If you're the kind of person who reads the source before trusting a security tool (you should be), Jin won't disappoint. It's organized as a textbook hexagonal architecture:

cmd/          → composition root (main.go)
internal/
  domain/     → pure domain models, no dependencies
  port/       → driving ports (services) & driven ports (scanners)
  application/→ use-case services (scan orchestration, security scoring)
  adapter/
    in/cli/   → CLI + REPL, argument parsing, rendering
    out/scanner/ → HTTP scanner, TCP port scanner, CT-log enumerator, DNS lookup
  config/     → centralized timeouts & tuning knobs
  container/  → dependency wiring
Enter fullscreen mode Exit fullscreen mode

Each scanner is an out adapter implementing a driven port, and the CLI is the in adapter talking to driving ports. That means:

  • Adding a new detection signature is a self-contained change.
  • Swapping crt.sh for another CT log source doesn't touch application code.
  • The rendering layer is fully decoupled from the scanning layer.
  • Everything is testable with fake adapters.

When would you actually use this?

  • Bug bounty / pentest recon — map the attack surface before touching a target: what runs, where, on which ports, and which subdomains exist.
  • Own-infrastructure hygiene — run info against your own sites and fix the "free wins": missing HSTS, missing CSP, cookie flags, CORS misconfigs.
  • Competitive intel (legally) — a quick fingerprint of public-facing stacks.
  • Learning security — watching the evidence lines is a great way to learn how fingerprinting actually works.
  • Rapid triage — one binary, one command, one screen, instead of assembling nmap + whatweb + dnsrecon output by hand.

The honest limits

Jin is not a replacement for a full arsenal:

  • The port scanner is a TCP connect scan — it's slower and more detectable than SYN scanning, and it won't detect UDP services.
  • Fingerprinting is signature-based — heavily obfuscated or custom-built apps may come back with nothing.
  • Subdomain discovery relies on certificate transparency only — it won't find subdomains that never got a public certificate.
  • The security score is a starting point, not a certification. It can't catch logic bugs, auth flaws, or injection vulnerabilities.

Wrapping up

Jin is a thoughtful, well-engineered little tool that makes the first five minutes of any recon fast and pleasant — a passive OSINT pass, a port overview, and a tech-stack map, all from one binary with output you can actually read.

If that sounds useful to you:

And remember — with great recon power comes great responsibility. Only point it at targets you're authorized to investigate. Happy (ethical) hunting.

Top comments (0)