klyrek-osint
Status: live on PyPI — pip install klyrek-osint
Public intelligence gathering: certificate-transparency subdomain discovery (crt.sh), WHOIS lookups, and NVD CVE search.
from klyrek_osint.certificate_transparency import query_crtsh
from klyrek_osint.whois import whois_lookup
from klyrek_osint.cve_lookup import search_cves, cve_to_finding
hosts = query_crtsh("klyrek.com") # certificate-transparency subdomain discovery
record = whois_lookup("klyrek.com")
cves = search_cves("express 4.18", max_results=3)
Real WHOIS result for klyrek.com:
registrar: NameSilo, LLC
creation_date: 2026-06-09T11:39:21Z
expiration_date: 2027-06-09T11:39:21Z
name_servers: ['mitch.ns.cloudflare.com', 'pola.ns.cloudflare.com']
whois_lookup does a raw-socket WHOIS query: it asks whois.iana.org for a refer: referral, then queries that registrar's WHOIS server directly.
Real CVE search result for "express 4.18" — NVD's search is free-text keyword matching, not a precise CPE match, so always review hits rather than trusting them blindly:
CVE-2022-24729 MEDIUM 6.5 CKEditor4 is an open source WYSIWYG HTML editor...
CVE-2025-59302 MEDIUM 4.7 Apache CloudStack improper control of code generation...
CVE-2026-4800 HIGH 8.1 Impact: the fix for CVE-2021-23337 added validation...
crt.sh is genuinely flaky
crt.sh's public API returns 502 Bad Gateway fairly often under load — three consecutive attempts against klyrek.com failed this way while writing this documentation. That's crt.sh, not a Klyrek bug. Retry, or query a mirror.
API reference
klyrek_osint.certificate_transparency
Passive subdomain discovery via crt.sh certificate transparency logs.
query_crtsh
query_crtsh(domain: str, client: Client | None = None) -> list[str]
Query crt.sh for certificates matching *.domain and return the unique hostnames found.
This queries a public certificate transparency log about the domain, not the domain's
own infrastructure, so it deliberately doesn't go through klyrek-http's
AuthorizationScope the way a direct request to the target would.
Source code in klyrek_osint\certificate_transparency.py
| def query_crtsh(domain: str, client: httpx.Client | None = None) -> list[str]:
"""Query crt.sh for certificates matching ``*.domain`` and return the unique hostnames found.
This queries a public certificate transparency log about the domain, not the domain's
own infrastructure, so it deliberately doesn't go through klyrek-http's
AuthorizationScope the way a direct request to the target would.
"""
owns_client = client is None
client = client or httpx.Client(timeout=_TIMEOUT)
try:
response = client.get(_CRTSH_URL, params={"q": f"%.{domain}", "output": "json"})
response.raise_for_status()
records = response.json()
finally:
if owns_client:
client.close()
hostnames: set[str] = set()
for record in records:
for name in record.get("name_value", "").split("\n"):
name = name.strip().lower()
if name and not name.startswith("*."):
hostnames.add(name)
return sorted(hostnames)
|
klyrek_osint.whois
Minimal WHOIS client using the standard two-step IANA-referral pattern.
Uses a raw socket rather than a python-whois dependency: ask whois.iana.org
which registrar server owns the TLD, then query that server directly.
whois_lookup
whois_lookup(domain: str) -> WhoisRecord
Look up WHOIS data for a domain via the standard IANA-referral pattern.
Source code in klyrek_osint\whois.py
| def whois_lookup(domain: str) -> WhoisRecord:
"""Look up WHOIS data for a domain via the standard IANA-referral pattern."""
iana_response = _query(_IANA_WHOIS_HOST, domain)
referral_match = _REFERRAL_PATTERN.search(iana_response)
raw = _query(referral_match.group(1), domain) if referral_match else iana_response
def _extract(pattern: re.Pattern[str]) -> str | None:
match = pattern.search(raw)
return match.group(1).strip() if match else None
name_servers = sorted({m.group(1).strip().lower() for m in _NAME_SERVER_PATTERN.finditer(raw)})
return WhoisRecord(
domain=domain,
registrar=_extract(_FIELD_PATTERNS["registrar"]),
creation_date=_extract(_FIELD_PATTERNS["creation_date"]),
expiration_date=_extract(_FIELD_PATTERNS["expiration_date"]),
name_servers=name_servers,
raw=raw,
)
|
klyrek_osint.cve_lookup
Look up known CVEs for a detected technology via the public NVD REST API.
cve_to_finding
cve_to_finding(record: CveRecord) -> Finding
Convert a CveRecord into a klyrek_core Finding, so it composes with other modules.
Source code in klyrek_osint\cve_lookup.py
| def cve_to_finding(record: CveRecord) -> Finding:
"""Convert a CveRecord into a klyrek_core Finding, so it composes with other modules."""
severity = _SEVERITY_MAP.get((record.severity or "").upper(), Severity.INFO)
score_note = (
f"CVSS base score: {record.base_score}"
if record.base_score is not None
else "no CVSS score available"
)
return Finding(
title=f"Known vulnerability: {record.cve_id}",
severity=severity,
description=record.description,
evidence=[score_note],
module="klyrek-osint",
)
|
search_cves
search_cves(keyword: str, max_results: int = 10, client: Client | None = None) -> list[CveRecord]
Search the NVD database for CVEs matching a free-text keyword (e.g. 'nginx 1.24.0').
Source code in klyrek_osint\cve_lookup.py
| def search_cves(
keyword: str, max_results: int = 10, client: httpx.Client | None = None
) -> list[CveRecord]:
"""Search the NVD database for CVEs matching a free-text keyword (e.g. 'nginx 1.24.0')."""
owns_client = client is None
client = client or httpx.Client(timeout=_TIMEOUT)
try:
response = client.get(
_NVD_CVE_URL, params={"keywordSearch": keyword, "resultsPerPage": max_results}
)
response.raise_for_status()
data = response.json()
finally:
if owns_client:
client.close()
records: list[CveRecord] = []
for item in data.get("vulnerabilities", []):
cve = item.get("cve", {})
severity, score = _extract_severity_and_score(cve)
records.append(
CveRecord(
cve_id=cve.get("id", "unknown"),
description=_extract_description(cve),
severity=severity,
base_score=score,
published=cve.get("published"),
)
)
return records
|