Skip to content

Add phishunt Lookup expansion/hover module - #926

Merged
adulau merged 1 commit into
MISP:mainfrom
0xDanielLopez:expansion-phishunt
Oct 13, 2026
Merged

adulau merged 1 commit into
MISP:mainfrom
0xDanielLopez:expansion-phishunt

Conversation

@0xDanielLopez

Copy link
Copy Markdown
Contributor

What

New expansion + hover module phishunt Lookup (misp_modules/modules/expansion/phishunt.py).

phishunt is a free, CC0 feed of live phishing domains, updated every hour. MISP already lists the phishunt feed in the default feeds. This module adds the per-attribute lookup: given a domain, hostname or url attribute (for a URL, only the host is used), it calls GET https://phishunt.io/api/v1/search.json?q=<host>&limit=200 (no API key) and returns misp_standard results.

The search endpoint matches substrings, so the module keeps only rows whose host is an exact match of the queried host. The module uses only this read-only endpoint. It never calls the phishunt /analyze endpoints, because those submit the value for analysis.

Mapping

  • each exact-match detection -> a phishing object (url, hostname, ip, target brand, submission-time from first seen, internal-reference with the phishunt id), referenced to the queried attribute with related-to;
  • hosting (ASN, org, country), TLS issuer, provider IP range and the other feeds that flag the URL -> the object comment;
  • one link attribute to the phishunt search page for the host.

At most 25 objects are returned (most recent first). All attributes have to_ids false. Deliberately no tag and no confidence score are set.

Rate limit

The phishunt API allows 20 requests per 10 seconds per IP on /api/*. On HTTP 429 the module waits once (Retry-After, clamped to 1-15 s) and retries one time, then returns a clear error.

Tests and docs

  • tests/test_phishunt.py: 48 pytest cases (33 functions, some parametrized) that mock requests.get with captures of the live API: exact-match filtering, URL to host, 429 retry and double 429, the 25 cap, the 200-row search cap, empty result, malformed JSON, unsupported types, hover call without uuid, introspection/version. Same style as tests/test_tweetfeed.py.
  • black, isort and flake8 clean with the project configuration.
  • README.md bullet and the documentation/README.md / documentation/mkdocs/expansion.md blocks were added by hand following the generator layout; happy to regenerate if you prefer.

Author: Daniel López (phishunt maintainer, also of the TweetFeed module, #898).

Queries https://phishunt.io/api/v1/search.json (no API key) for a domain,
hostname or url attribute (only the host of a url is used) and returns
misp_standard results. The API does a substring match, so I keep only the
rows whose host is exactly the queried one. Each detection becomes a
`phishing` object (url, hostname, ip, targeted brand, first seen, phishunt
uuid) referenced with 'related-to' from the queried attribute, with hosting,
TLS issuer, provider IP range and the other feeds that flag the URL in the
object comment, plus one link attribute to the phishunt search page. At most
25 objects are returned. HTTP 429 (20 requests per 10 s per IP) is retried
once after a backoff. Only the read-only search endpoint is used: the
phishunt analyze endpoints are never called, since they would submit the
queried value for analysis. Nothing is tagged, no confidence score is
asserted and url/ip are not flagged for IDS export.

Tests mock requests.get with verbatim API captures (48 cases). Docs blocks
added by hand following the generator layout.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-13T11:49:51.458822Z 377f697 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 377f697fa7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

value = str(value).strip().replace("[.]", ".")
if attr_type != "url":
return _normalise_host(value)
if "://" not in value and not value.startswith("//"):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict scheme detection to the URL prefix

For a supported schemeless URL such as example.com/login?next=https://target.test, the embedded redirect URL puts :// in the query even though the outer URL has no scheme. This condition therefore skips prepending //, so urlsplit finds no hostname and the handler returns “Could not extract a host” instead of looking up example.com; detect a scheme only at the start of the value rather than anywhere in it.

Useful? React with 👍 / 👎.

@adulau
adulau merged commit b6cc878 into MISP:main Oct 13, 2026
7 checks passed
@adulau

adulau commented Oct 13, 2026

Copy link
Copy Markdown
Member

Thank you for the contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants