Skip to main content
PPPhishPondPhishing Tradecraft Intelligence

Attack · Detection · Validation

NewsroomCampaignTradecraftInfrastructureDetectionResearchRadarAboutSubscribe
NewsroomCampaignTradecraftInfrastructureDetectionResearchRadarAboutSubscribe

Research Desk

PhishPond

Phishing tradecraft research desk covering campaign analysis, adversary infrastructure, detection engineering, and validation workflows.

High signal for security teams who need tradecraft, not recycled filler.

Navigate

  • Home
  • Newsroom
  • Research
  • Subscribe

Signals

  • editorial@phishpond.dev
  • Research Mission & Ethics
  • Intel Brief
  • RSS Feed
  • Submit Research Tip
© 2026 PhishPond. Authorized security research use only.

GitHub RadarBlue team tool

youssefismail-dev/limnex-uie

Limnex URL Intelligence Engine: a generative model of URLs, trained from scratch, for defensive phishing research. Primary language: Python. 5 stars.

Classification confidence: medium

Inferred from repository metadata; not a reviewed classification.

Python5 stars0 forkspushed Oct 24, 2026Apache-2.0

Project links:Open GitHub projectBack to radar

README Preview

Fetched from GitHub

Limnex URL Intelligence Engine (Limnex UIE)

![Release](https://github.com/youssefismail-dev/limnex-uie/releases/tag/v0.1.0) ![tests](https://github.com/youssefismail-dev/limnex-uie/actions/workflows/tests.yml) ![License: Apache-2.0](LICENSE) ![Python 3.11+](pyproject.toml) ![Model: 25.5M parameters, trained from scratch](MODEL_CARD.md)

A generative model of URLs, trained from scratch. It reads millions of real URLs, learns how the web names things, and invents new ones — benign and phishing-style alike (the rare exact copies of training URLs are filtered out; see Quick start). Their structure holds up against real data: in 29 of 32 measured cells, the gate's character-level detector separates them from held-out real URLs no better than it separates two real samples (within its 0.05 margin). Their vocabulary does not yet: a detector that checks whether each word occurs in real data can tell them apart. See Known limitations.

<p align="center"> <img src="docs/limnex-uie-demo.gif" alt="Terminal demo: uie generate writes ten benign URLs (shown defanged) after the safety notice and the gate report; uie score gives example.com/about-us an llr of 1.13 and secure-login.example.com/account/verify an llr of 13.17" width="100%"> </p>

At a glance

| | | |---|---| | What it is | a 25.5M-parameter character-level transformer, trained from scratch: no pretrained model, no word list, no templates | | Realism | in 29 of 32 measured cells, a detector trained to tell its URLs from real held-out ones does no better than on two real samples | | Known weaknesses | invented words (a word-checking detector can tell them apart); phishing query strings in free mode | | People | 55 of 100 correct in the project's human evaluation (chance: 50) | | Helps detectors | in a pre-registered test, adding its URLs to a detector's training data raised recall at 1% false positives in 6 of 6 settings; beating the best simpler generator held in 1 of 6. It was more realistic than all four simpler generators tested (28 of 31 comparisons). See research/u1/U1_RESULTS.md | | Reproducible | all 50 evaluation files regenerated byte for byte from the release alone | | Safety | a known-URL filter is required for every generation; runs offline; no bulk phishing data is published |

cdn-assets-eu3.shopwave.io/static/v2/bundle.js      # illustrative, benign
blog.tenjiku-books.jp/2024/03/review                # illustrative, benign
secure-verify.examplebank-alerts.support/login      # illustrative, phishing-style
signin.examplecredit-notice.online/session          # illustrative, phishing-style

These four are illustrations of the target, carried over from [DESIGN.md](DESIGN.md); they are not model output.

The test is whether an experienced security researcher, shown these shuffled together with real URLs, could sort them. (That is the project's target. The project's human evaluation — ten people, 100 URLs, its final one — found people no better than chance; 100 URLs cannot rule out a modest ability — see [Known limitations](#known-limitations-and-future-work).)

Nobody writes the rules. The model is never told that phishing URLs contain login, or to swap Latin letters for Cyrillic lookalikes. It reads data and works out the patterns itself — a rule-based generator can only ever produce attacks its author already knew about.

Status: pre-alpha, public research release v0.1.0 (2026-10-20). The baseline engine is `e16_b5` (adopted 2026-10-08): e16_cap's weights, a character-level transformer trained from scratch on the project's corpus (d_model 512, 25.5M parameters), decoded at temperature 1.0 with three structural rules that forbid only what real URLs never do (D1 and D1′ for the root slash, B5 for planned queries). Roadmap-E3 is closed, NOT MET (2026-10-08): e16_b5 clears 29 of 32 gated cells and all 8 slash rows; see Acceptance and Known limitations. The word-level experiments that followed (V2-P1, P1b and P2) are closed under the current design rules, and e16_b5 remains the baseline (2026-10-15). Full record: research/E3_FINAL_REPORT.md. Architecture and roadmap: DESIGN.md.

This repository is an independent project in the Limnex family. Limnex UIE is developed separately from the Limnex phishing detector (LIMNEX), which consumes it; it never imports from, and is never graded by, any consumer. It was released publicly once the roadmap, the evaluation and the release preparation (D2) were complete.

Quick start

Read [Responsible Use](#responsible-use) and [No Liability](#no-liability) first. Generated
URLs are synthetic and for defensive research only: never register, resolve, visit, host or
send them.
  1. Install (Python 3.11+; this installs torch, numpy and tldextract 5.3.1):
   git clone https://github.com/youssefismail-dev/limnex-uie.git
   cd limnex-uie
   pip install .
  1. Download the model from the repository's Releases page: limnex-uie-e16_b5.pt

(97 MiB), and the known-URL filter limnex-uie-known-urls.bloom.gz (34 MiB):

   curl -LO https://github.com/youssefismail-dev/limnex-uie/releases/download/v0.1.0/limnex-uie-e16_b5.pt
   curl -LO https://github.com/youssefismail-dev/limnex-uie/releases/download/v0.1.0/limnex-uie-known-urls.bloom.gz

Generation requires the filter: the model sometimes reproduces a training URL — about 1 in 100 raw phishing samples is a real phishing URL, and a rare benign copy can carry personal data that some real URLs hold (an e-mail address, a token) — and the filter removes them. uie.load refuses a model file or a filter that is not the published one (sha256 98b10b46… for the model file; for the filter, 3ef34d06… is the sha256 of its decompressed content, which uie.load checks, whereas SHA256SUMS.txt lists the sha256 of the downloaded file, 2f8a4706…).

  1. Generate and score:
   uie generate --weights limnex-uie-e16_b5.pt --known-urls limnex-uie-known-urls.bloom.gz --label phishing -n 10
   uie score --weights limnex-uie-e16_b5.pt "example.com/login"

or in Python:

   import uie
   engine = uie.load("limnex-uie-e16_b5.pt", known_urls="limnex-uie-known-urls.bloom.gz")
   urls = engine.generate("phishing", n=10, seed=7)   # always gated; see engine.report_text()
   rows = engine.score(["example.com/login"])         # log P(url | class) and their difference

Before sharing any generated URL, give the gate a current threat-feed snapshot (--blocklist feed.txt, or blocked_domains=): live threats are screened only when you supply one. Generation is free mode (the engine chooses the suffix and whether to write a path, a query and a root slash, from training statistics) and runs at about 2 URLs per second on a laptop CPU.

  1. More: the model is described in MODEL_CARD.md; the published results are

reproduced by following REPRODUCE.md.

Known limitations and future work

e16_b5 has two documented limitations and two small open cells. Each is measured against real held-out URLs, and each marks a boundary of the current design: a character-level transformer trained from scratch on the project's corpus, with no word list and no pretrained model. Each has been diagnosed, and the attempts to fix it are recorded. Resolving them is deferred to a later major version of the engine; the approach has not been chosen yet.

1. Vocabulary: the word tell. The engine uses fewer real words than real URLs do (research/E3_FINAL_REPORT.md §8).

  • It writes 1.45 words per benign URL that never occur in real data, against 0.93

for real URLs. In paths and queries, 84% of its words are known words, against 94%.

  • A detector that checks whether each word occurs in the real training corpus

separates whole URLs from held-out real ones: excess over the real-vs-real floor +0.168 benign and +0.164 phishing, both CONVICTED. Character-level detectors do not (+0.027 benign, CLEARED; +0.044 phishing, UNDECIDED), and structural features alone give AUC 0.50 benign and 0.55 phishing. The difference is in vocabulary.

  • Three attempts within the current design did not fix it: a learned memory

layer, twice (V2-P1 and V2-P1b, both stopped at their registered memory checks), and word pieces (V2-P2), which made the tell larger (research/v2/V2P2_RESULTS.md).

2. Phishing query strings in free mode: the one substantial gate failure (the report's §5.3).

  • x = 0.0733 against the 0.05 bar, CONVICTED. It concerns the query string,

present on about 4.7% of free-mode phishing URLs; every other free-mode phishing field is CLEARED.

  • A decomposition of the cell (DX8) traced about 63% of the tell to the host and

path written before the query.

  • Real phishing reuses kit strings (40.3% of real phishing queries are exact

training queries); the engine invents where real phishing repeats.

  • It is not a data-volume problem: a plain character 6-gram model trained on the

same phishing queries scores +0.036 where the transformer scores +0.124. The limit is in how the transformer generalises.

3. Two small control-mode cells, on benign URLs planned with both a path and a query (P1Q1; the report's §§5.1–5.2).

  • PTH: 0.0539, CONVICTED, 0.004 above the bar. Paths run about 10% shorter than

real ones (19.7 against 21.7 characters); a read-only check found no structural violation to correct.

  • SUB: 0.0431, below the bar but not proven at 95% (UNDECIDED).

The human evaluation (2026-10-15; final). Ten volunteers each judged 5 pairs of same-class URLs (100 distinct URLs: 50 real held-out, 50 from e16_b5's free mode; pairs could be mixed, both real or both generated). They judged 55 of 100 URLs correctly (95% interval 45–64%; chance 50%; p = 0.37); generated URLs were called real 52% of the time, real ones 62%. That is no evidence that people can tell them apart, but 100 URLs cannot show that they can't: a modest ability is not ruled out. This is the project's final human evaluation: it was the largest feasible, and no larger panel will be run (owner's decision, 2026-10-17). Record: research/eval_pages/HUMAN_PILOT_RESULTS.md.

Acceptance status

Current: e16_b5 (E3 final report, 2026-10-08)

Every cell is graded by real held-out URLs only. For each field (label, suffix, subdomain, path, query) and population, a detector is trained to separate the engine's strings from real ones; its AUC minus the AUC between two real samples is the excess x, measured over 5 generations against a bar of 0.05: CLEARED if x is proven below the bar, CONVICTED if proven above it, UNDECIDED otherwise.

| | count | |---|---| | gated cells CLEARED | 29 of 32 (9 of 10 free, 20 of 22 control) | | slash rows within tolerance | 8 of 8 | | cells UNDECIDED | 1 (benign P1Q1 SUB, below the bar) | | cells CONVICTED | 2 (free phishing QRY; benign P1Q1 PTH) |

Every cell and row: research/E3_FINAL_REPORT.md §4. The remaining cells are described under Known limitations.

Everything below in this section is the E5-era record (2026-09-23), kept as history. Its numbers describe E5, not the current engine.

E5 under