PRISM 2.8.0 — Accurate Username Search, LLM Fallback & Keyless Shodan
Username search stopped inventing accounts, and two panels that used to sit empty now have something in them.
Username search was reporting accounts that do not exist
Most of the 50 sites were judged by HTTP status alone, so any site that answers 200 for a name nobody registered was reported as a hit. Probing every site with a nonexistent username caught ten doing exactly that: Pinterest, Spotify, Medium, 500px, Imgur, HackerRank, Kaggle, Trello, Duolingo and OnlyFans. Five of them returned a body byte-identical to a real profile's, so nothing in the response said the account was there.
A 200 now triggers one control request per site, using a username that cannot exist. The hit only stands if the target's page names the target while the control's page does not name the control. Sites that echo whatever name sits in the URL can no longer produce a hit at all. The control is fetched once per site per search and only for sites that answered 200, so a scan that finds nothing costs no extra requests.
Measured against 21 live sites: false positives went from ten to zero. Six sites that serve identical HTML for every username now report nothing instead of inventing an account — for a reconnaissance tool that is the right way round.
Twitch was a separate case: its text marker had stopped appearing on the page, so every username came back found. Markers are now cross-checked against the control response, and one missing from both is treated as stale.
401, 403, 429 and 5xx became unknown rather than not_found. A site that blocked us tells us nothing about the account, and calling that absence was producing quiet false negatives.
The AI panel only ever tried one provider
It picked one at import — LLM_API_KEY, else OpenRouter, else Groq — and whichever won was the only one ever contacted. A configured Groq key sat unused while OpenRouter answered Access denied by security policy, which is what the public demo has been showing: providers reject traffic from its hosting region at their edge, before the request reaches a model.
Every configured key is now a provider, tried in order until one answers, each carrying its own model. GROQ_MODEL overrides the Groq default. When all of them fail the response names each provider and its reason instead of one opaque message.
That only helps if some provider accepts your instance. If none do, run the model yourself — the compose file now ships Ollama behind a profile:
docker compose --profile ollama up -d
docker compose exec ollama ollama pull qwen2.5:3bLLM_BASE_URL=http://ollama:11434/v1/chat/completions
LLM_MODEL=qwen2.5:3bNo key needed — LLM_BASE_URL alone is enough now. Budget about 4 GB of RAM for a 3B model. Nothing leaves the machine.
Shodan without a paid key
A free Shodan key gets 403 on the host endpoint, and no key skipped the module outright, so that panel was empty either way. It now falls back to InternetDB, Shodan's own keyless dataset: ports, hostnames, tags, CPEs and the CVE list. Checked against 45.33.32.156 with no key — four ports, one hostname, four CPEs and 120 CVEs where the module previously returned nothing.
A paid key still goes to Shodan and still returns organisation, location and service banners, none of which InternetDB carries. The result records which source answered, and the panel says so. An invalid key is still an error rather than a quiet downgrade.
host_info now requires an IP; it was interpolating whatever it was handed into the request path.
Also
GROQ_MODELand theLLM_*variables are in.env.example, which had none of them despite the README documenting them since 2.6.0.- Thanks to @nightcityblade for correcting the language counts in the README and tightening the exception handling in the username checker.
Tests: 285 → 326.
Full notes in the CHANGELOG. If PRISM is useful to you, a ⭐ helps others find it.