Skip to content

Releases: NovaCode37/Prism-platform

PRISM 2.8.1

Choose a tag to compare

@NovaCode37 NovaCode37 released this 07 Sep 11:25

A maintenance release. No new capability worth a minor bump, but enough security and correctness work that it should not wait for 2.9.

Security

A webhook could still be sent to a host that refused to resolve. The guard checks every address a hostname resolves to and blocks the private ones, but an unresolvable hostname fell through and the request went out anyway. That branch existed only so two delivery tests aiming at hooks.example.com would pass — the production behaviour was a side effect of the tests. It leaves a rebinding window: answer NXDOMAIN while the check runs, resolve to an internal address by the time requests looks it up again. Any refusal from the resolver now stops the send.

The container ran everything as root. It creates uid 1000 and drops to it. If you bind-mount ./results from a directory owned by someone else, run chown -R 1000:1000 results on the host. CI now checks the image is unprivileged and can still write to all four data directories.

Leaflet came off unpkg with no integrity attribute — the map page trusted whatever the CDN served. Script and stylesheet now carry the sha256 hashes published on leafletjs.com.

numverify was called over plain HTTP, with the phone number and API key in the query string. HTTPS now, falling back only on error 105, the one case where the free plan itself refuses TLS.

Secret scanning, push protection and Dependabot security updates are on for the repository. That surfaced nine advisories nobody had seen; five are closed here.

Added

RDAP module (#306, by @sOuL2000s) — registration data over RDAP alongside WHOIS. Finds the server per TLD from the IANA bootstrap file, falls back to rdap.org, and returns registration dates, registrar, nameservers and contacts.

A keyboard shortcuts panel, tooltips on the standalone tool cards (#305), and multi-arch images on GHCR for linux/amd64 and linux/arm64 on every release tag.

CodeQL runs on pushes, pull requests and weekly. Stale handling touches pull requests only and leaves issues alone.

Fixed

RDAP reported 292 as the registrar. jCard properties are [name, params, type, value], so reading index 2 returned the type and every contact came back as "text". The registrar was read from the entity handle instead, which is the IANA registrar id, not a name. The test fixture used a three-element vCard, which real RDAP never sends, so nothing caught it.

Every .ru domain looked unregistered. A 404 from rdap.org was read as "not registered", but plenty of TLDs serve no RDAP at all. The zone is checked against the bootstrap map first and the module reports skipped.

A rate-limited request came back as a CORS error. add_middleware wraps from the inside out, so CORS ended up innermost and anything short-circuited above it answered without the headers — the browser hid the 429 behind an opaque network failure. CORS is outermost now, and proxy headers still run before the limiter, so the client IP behind a proxy is unchanged.

File work blocked the event loop in two routes. The metadata endpoint copied the whole upload to a temp file inline, and clearing scans read every file in scan_data inline. Both stalled every other request while they ran, websocket scan progress included.

The demo now says on the page, not just in the docs, that AI analysis will not work there.

Upgrading

docker pull ghcr.io/novacode37/prism-platform:2.8.1

Nothing to migrate. The one thing to know is the uid change above if you bind-mount a results directory.

326 → 343 tests.

PRISM 2.8.0 — Accurate Username Search, LLM Fallback & Keyless Shodan

Choose a tag to compare

@NovaCode37 NovaCode37 released this 02 Sep 13:46

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:3b
LLM_BASE_URL=http://ollama:11434/v1/chat/completions
LLM_MODEL=qwen2.5:3b

No 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_MODEL and the LLM_* 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.

PRISM 2.7.0 — Domain Exposure & Security Fixes

Choose a tag to compare

@NovaCode37 NovaCode37 released this 01 Sep 12:31

A new exposure source, and three security fixes worth reading before you upgrade.

Domain Exposure (Lunar)

A second angle on compromised credentials, next to the Hudson Rock module. Where Hudson Rock gives you a snapshot of what is exposed right now, this one covers a rolling year: how often the domain turns up in infostealer logs and breach data month by month, split between your staff and your customers, plus which malware families were involved, which services were hit, and where from.

No API key. Aggregates only — the endpoint returns no credentials.

Off by default, like every module that talks to a third party:

LUNAR_ENABLED=true

Domain targets only, since the API covers no other type. Outbound requests honour MODULE_PROXY. Lunar builds a report on first request and caches it for a month, so the first scan of a domain nobody has looked up yet comes back as skipped with GENERATING_REPORT — scan it again once it's ready.

Thanks to @rangeva for proposing it in #286 and for putting the terms in writing.

Security

Rate limits could be bypassed with a header. The limiter keyed on X-Forwarded-For / X-Real-IP whatever TRUST_PROXY_HEADERS was set to. With no proxy in front — the default — a different header value per request meant a fresh bucket every time, so 10/minute on /api/scan and the 200/day and 60/hour ceilings did nothing. Each scan that bought fans out to dozens of third-party lookups. The headers are now read only when TRUST_PROXY_HEADERS is on, which is also when FORWARDED_ALLOW_IPS decides who may set them. Behaviour behind a configured proxy is unchanged, and the daily scan quota was never affected — it keys on the API-key principal.

A username could redirect a lookup to another host. Blackbird interpolated the username into its URL templates unescaped, and the Tumblr template carries the placeholder in the host position. Scanning evil.com/# built https://evil.com/#.tumblr.com/ and sent the request to evil.com. validate_target rejects only [;|`$<>{}], so a slash or a hash reached the module untouched. Usernames are percent-encoded now.

A username could write outside results/. Blackbird built its export filenames straight from the username, so ../../pwned escaped the output directory.

If you run an instance that is reachable from the internet, especially with ALLOW_ANON_API=1, upgrade.

Fixes

  • JSON export failed on some usernamesuser?name raised OSError before writing anything, a very long name raised FileNotFoundError. Same root cause as the export path issue above.
  • A hanging maigret froze the scan — the wrapper read output to EOF and then called process.wait(), neither with a timeout, so a maigret that stopped producing output blocked its worker for good and the scan neither finished nor reported an error. A watchdog stops it after MAIGRET_MAX_RUNTIME seconds, 600 by default.
  • A failed Blackbird search looked like a clean one — the API and CLI threw away what the module returned and read its result list, storing an empty list for a search that raised, which reads the same as checking every site and finding nothing.

Tests

249 → 285, covering the new module, the maigret watchdog, the rate-limit key, hostile usernames in export paths, and host escapes in the username URL templates.


Full notes in the CHANGELOG. If PRISM is useful to you, a ⭐ helps others find it.

PRISM 2.6.0 — Browser Extension, Bring-Your-Own LLM & Accessibility

Choose a tag to compare

@NovaCode37 NovaCode37 released this 27 Jul 15:02

PRISM now lives in your browser.

Browser extension

Highlight or right-click any domain, IP, email, phone, or username on a page and a full scan runs inside the extension popup — live module progress, OPSEC score, and result cards, without leaving the page you're on.

It points at your own PRISM instance or the public demo, takes an optional API key, and speaks all 9 languages.

Install it from Firefox Add-ons →

PRISM browser extension demo

Bring your own LLM

The AI summary and chat are no longer tied to two hardcoded providers. Set these in .env and point PRISM at any OpenAI-compatible endpoint — OpenRouter, Groq, Gemini, a local Ollama, whatever you run:

LLM_BASE_URL=https://your-provider/v1/chat/completions
LLM_API_KEY=...
LLM_MODEL=...
LLM_PROXY=http://user:pass@host:port   # optional

Useful if your host is geo-blocked by a provider, or you simply want a different model.

Accessibility

  • Animations and transitions are neutralized when the OS requests prefers-reduced-motion (#136)
  • Scan progress is announced to screen readers via an aria-live region (#182)
  • Scan-type toggles carry proper aria-label / aria-pressed (#198)

Quality of life

  • Copy button on the raw JSON tab (#195) and a / shortcut to jump to the target field (#196)
  • Clear button on the target input (#197), legend on the entity graph (#205), "Report an issue" link in the topbar (#202)
  • Watchlists: pause/resume, a "Send test webhook" button, JSON/CSV alert export, and readable alert labels

Fixes

  • Rate limiting behind a proxy — the limiter now keys on the real client IP instead of collapsing every visitor into the proxy address, which was causing shared 429s
  • LLM errors — providers that return an error as a plain string no longer crash the endpoint; non-JSON responses surface a readable message
  • Clearer message when an instance requires an API key; spinner on Run Scan while the request is in flight; Watchlists screen fully localized

Full notes in the CHANGELOG. If PRISM is useful to you, a ⭐ helps others find it.

PRISM 2.5.0 — Watchlists, Graph Export, Quotas & Chinese locale

Choose a tag to compare

@NovaCode37 NovaCode37 released this 04 Jul 07:38

PRISM 2.5.0

This release finishes everything that was on the 2.5 roadmap, plus some security fixes.

Watchlists and scheduled scans

You can now save a target and have PRISM re-scan it on a schedule. Instead of dumping the full results every time, it only alerts you when something actually changed — a port that opened, a new subdomain, a fresh breach, a modified DNS record. Timestamps and other noisy fields are ignored, so an alert means a real change.

Alerts can go to a webhook, and there's a Watchlists screen in the top bar. Endpoints: POST/GET/DELETE /api/watchlist and GET /api/watchlist/{id}/alerts.

Graph export for Gephi and Maltego

Any scan's entity graph can be exported as GraphML or GEXF, either from the Graph tab or via GET /api/scan/{id}/graph/export?fmt=graphml|gexf. Open it straight in Gephi or Maltego.

Per-key quotas and a usage endpoint

Set SCAN_QUOTA_PER_DAY to cap scans per API key. Over the limit returns a 429. GET /api/usage reports how many scans a key has used, its limit, what's left, and when the window resets.

Chinese locale

Added a full Simplified Chinese translation. That's nine languages now, with auto-detection from the browser.

Security fixes

  • Scan and watchlist targets that resolve to private, loopback, link-local, or cloud-metadata addresses are blocked by default. Self-hosters who actually want to scan internal hosts can set ALLOW_PRIVATE_TARGETS=true.
  • Fixed a path-traversal issue in the Maigret module: usernames are sanitized before they're used in filenames and passed after a -- so a username starting with - can't be read as a flag.

Smaller stuff

  • --quiet and --version flags on the CLI
  • Copy-as-cURL button, a Gravatar recon module, and empty-state placeholders in results
  • Contributor work: custom 404 page, aria-labels, Italian/Portuguese/Polish locales, a /api/health endpoint, target normalization, and more tests
  • The frontend now runs in CI

Thanks to everyone who sent a PR — 30+ people have contributed at this point.

Demo: https://getprism.su
Full list of changes: CHANGELOG.md

PRISM v2.4.0 — Graceful Degradation, Demo & New Tools

Choose a tag to compare

@NovaCode37 NovaCode37 released this 17 Jun 05:28

PRISM v2.4.0 — a big quality-of-life release: modules now fail gracefully, a one-command demo, two new standalone tools, per-module refresh, and a pile of fixes.

Live demo: https://getprism.su

Added

  • Graceful degradation for key-dependent modules — Shodan, VirusTotal, AbuseIPDB, Censys, Leak-Lookup/HIBP and Telegram now report skipped (no key) or rate_limited (HTTP 429) instead of failing, with per-module status badges in the dashboard (#61).
  • HIBP_API_KEY support for breach lookups (#61).
  • One-command demodocker compose -f docker-compose.demo.yml up boots PRISM with preloaded sample scans, no API keys required (#63).
  • IP / Subnet calculator standalone tool (#45).
  • Hash Identifier standalone tool — MD5 / SHA-1 / SHA-256 / SHA-512 (#76).
  • Per-module refresh — re-run a single module from its result card (#104).
  • Approximate region-level GeoIP map for phone scans (geocoded operator region).
  • Bundled Unicode fonts (DejaVu) so PDF reports render non-Latin text.
  • Project polish — README API reference + env-vars table, FAQ, Table of Contents, LICENSE (MIT), CITATION.cff, SUPPORT.md, CODEOWNERS, .editorconfig, .gitattributes, .dockerignore, Sponsor config, and Bug/Feature issue forms.

Changed

  • Scan history is sorted newest-first, auto-refreshes after a scan, and is localized in all 5 languages.
  • The scan engine caches only successful (ok) results, so a missing key isn't frozen in cache (#61).
  • The Censys tab is hidden when the module is skipped (no key) instead of showing an empty card.
  • Removed the default Leaflet attribution flag from all maps.

Fixed

  • PDF reports rendered non-Latin (e.g. Cyrillic) text as empty grey boxes — fixed with bundled DejaVu fonts.
  • GeoIP map sometimes rendered blank — map now recalculates size after layout.
  • New scans could be missing from history — list was capped before sorting.
  • Sidebar "Modules" label showed a raw i18n key — fixed and localized.
  • Empty numeric env vars crashed startupCACHE_TTL_HOURS / MAX_STORED_SCANS / MAX_UPLOAD_MB now fall back to defaults (#122).

Full changelog: https://github.com/NovaCode37/Prism-platform/blob/main/CHANGELOG.md

v2.3.0 — Scan History, Comparison, Exports, CLI & 5 Locales

Choose a tag to compare

@NovaCode37 NovaCode37 released this 03 Jun 04:36

What's New

Scan History & Comparison

  • Scan history panel in sidebar — browse past scans from /api/scans, click to load results (#38)
  • Comparison mode — select two scans and view a side-by-side diff table with added/removed/changed fields (#58)

Export Formats

  • CSV export — flattened Module/Key/Value download with BOM for Excel (#43)
  • Markdown export — structured .md report with OPSEC, WHOIS, DNS, subdomains, accounts (#55)

Localization

  • French (FR) — full UI translation (#14)
  • Spanish (ES) — full UI translation (#28)

CLI

  • Standalone CLIpython cli.py scan <target> with --json, --html, --pdf, --modules, auto-type detection (#39)
  • python -m prism scan entry point

Integrations & API

  • Slack/Discord webhook formattersWEBHOOK_FORMAT=slack|discord env var (#35)
  • Rate-limit response headersX-RateLimit-Limit, Remaining, Reset via slowapi (#37)

UX Improvements

  • Keyboard shortcuts — Arrow Left/Right cycles result tabs (#33)
  • Copy all found emails to clipboard (#34)
  • Scan duration in results header (#29)
  • Username filter in accounts tab (#44)
  • Loading skeleton during scan progress (#54)

DevEx

  • ESLint next/core-web-vitals config (#36)
  • GitHub PR template (#48)

PRISM v2.2.0 — Security Hardening, Report i18n, Code Cleanup

Choose a tag to compare

@NovaCode37 NovaCode37 released this 25 May 11:54

Security Fixes

  • Webhook SSRF mitigation — all webhook URLs now validated against private/internal address ranges (closes #23)
  • Multi-tenant API key scoping — scan listings and access filtered by principal; no cross-tenant data leaks (closes #24)
  • SSRF guard hardened — DNS re-resolution check to prevent TOCTOU bypass on webhook delivery

New Features

  • Multilingual Report Engine ([modules/report_i18n.py] — PDF/HTML reports now support EN/RU/DE via ?lang= parameter
  • i18n keys added: precision, approximate for IP geolocation map markers
  • Copy button for AI summary (PR #19)

Version

2.1.02.2.0 (backend + frontend)

Compatibility

  • No breaking API changes
  • No new external dependencies
  • Drop-in upgrade from v2.1.x

Full Changelog

v2.1.0...v2.2.0

v2.1.1 — Webhooks, German locale, PDF fix

Choose a tag to compare

@NovaCode37 NovaCode37 released this 18 May 16:35

Changelog


[2.1.1] — 2026-05-18

Added

  • Webhook callback support — pass an optional webhook_url in
    POST /api/scan; a POST is delivered to that URL when the scan
    reaches a terminal state. Signed with X-Prism-Secret when
    WEBHOOK_SECRET is set. Private/loopback hosts are rejected.
    Docs: docs/ARCHITECTURE.md (issue #18).
  • OPSEC category tooltips — hover over a category in the score bar
    to see a one-line explanation of what it measures (issue #17).
  • Alt+T keyboard shortcut to toggle dark/light theme. Topbar
    tooltip updated with the hint (issue #15).
  • German (DE) locale — full UI translation; language switcher now
    cycles EN → RU → DE and auto-detects from navigator.language
    (issue #12).
  • AI summary copy button refactored to share the global
    copyValue + toast mechanism (PR #19 follow-up).

Changed

  • PDF export switched from WeasyPrint (52.5, broken on Windows
    without GTK) to xhtml2pdf (pure-Python). A dedicated
    PDF-friendly template is used so output is stable across OSes.

Fixed

  • PDF export endpoint no longer returns 501 / install errors on
    Windows. Generated PDFs render OPSEC score, findings, WHOIS, DNS,
    GeoIP, subdomains, threat intel and phone data correctly.

v2.1.0 — Censys, Dark Web checker, PDF export, i18n & progress bar

Choose a tag to compare

@NovaCode37 NovaCode37 released this 26 Apr 15:21

What's new in v2.1

New modules

  • Censys — host services, ASN, open ports, certificate-based subdomain discovery
  • Dark Web checker — searches .onion mirrors via Ahmia + DarkSearch

PDF export

  • New "PDF Report" button generates a server-rendered print-ready PDF via WeasyPrint
  • Endpoint: GET /api/scan/{id}/report/pdf

i18n — English & Russian UI

  • Language switcher in the topbar (EN / RU)
  • Auto-detects browser language on first visit
  • Easy to extend: drop a JSON file in frontend/src/messages/

Scan progress bar

  • Real-time 5/8 modules · 62% progress bar during scans
  • Per-module status chips (running / ok / error)
  • Works via WebSocket with polling fallback

Other improvements

  • One-click copy buttons across all result tabs
  • Version badge bumped to v2.1
  • Module & source counters updated (22 modules, 12 sources)
  • Architecture docs added: docs/ARCHITECTURE.md
  • CHANGELOG.md added

Bug fixes

  • CI lint fixed (was failing on pre-existing whitespace warnings)
  • Progress bar now animates correctly in polling fallback mode (shared hosting)
  • WeasyPrint version pinned for Python 3.8 / old libpango compatibility

Self-host in one command:

cp .env.example .env && docker compose up --build