Skip to content

klyrek-tech

Status: live on PyPI — pip install klyrek-tech

Signature-based technology fingerprinting: web servers, frameworks, CMSes, JS libraries, hosting/CDN providers, all matched against response headers, cookies, and body content.

from klyrek_tech.fingerprint import fingerprint

for tech in fingerprint(response):
    print(tech.name, tech.category, tech.version)

Real output against admin.sandbox.klyrek.com: Express framework None, Vercel hosting None — Vercel's edge adds its own headers regardless of the app behind it, so hosting and framework both show up independently.

Signatures are declarative (klyrek_tech.signatures.SIGNATURES), matched by header regex, cookie-name regex, or body substring — adding a new technology is a new list entry, not new matching code.

API reference

klyrek_tech.fingerprint

Match an HTTP response against known technology signatures.

fingerprint

fingerprint(response: Response) -> list[Technology]

Match a response against every known signature and return the technologies found.

Source code in klyrek_tech\fingerprint.py
def fingerprint(response: httpx.Response) -> list[Technology]:
    """Match a response against every known signature and return the technologies found."""
    body = response.text if _looks_like_text(response) and response.content else ""
    meta_generator_match = _META_GENERATOR_RE.search(body) if body else None
    cookie_names = _cookie_names(response)

    technologies: list[Technology] = []

    for sig in SIGNATURES:
        evidence: list[str] = []
        version: str | None = None

        for header_name, pattern in sig.headers.items():
            value = response.headers.get(header_name)
            if value is None:
                continue
            match = pattern.search(value)
            if match:
                evidence.append(f"{header_name}: {value}")
                version = version or _extract_version(match)

        for cookie_pattern in sig.cookies:
            for name in cookie_names:
                if cookie_pattern.search(name):
                    evidence.append(f"cookie: {name}")

        if sig.meta_generator and meta_generator_match:
            content = meta_generator_match.group(1)
            match = sig.meta_generator.search(content)
            if match:
                evidence.append(f"meta generator: {content}")
                version = version or _extract_version(match)

        for body_pattern in sig.body:
            if not body:
                continue
            match = body_pattern.search(body)
            if match:
                evidence.append(f"body pattern: {body_pattern.pattern}")
                version = version or _extract_version(match)

        if evidence:
            technologies.append(
                Technology(
                    name=sig.name,
                    category=sig.category,
                    version=version,
                    evidence=evidence,
                    discovered_by="klyrek-tech",
                )
            )

    return technologies

klyrek_tech.signatures

Declarative technology signatures.

Kept data-driven (a list of Signature records) rather than one class per technology, since the matching logic (header/cookie/body regex) is identical across every signature — only the patterns differ. Adding a new technology is a new list entry, not new code.