Open Source Cyber Threat Intelligence and Digital Risk Protection Platform
ThreatForge is an open source platform for Cyber Threat Intelligence, Digital Risk Protection and digital risk investigation. It helps security analysts, SOC teams, fraud teams and researchers organize indicators, enrich observables, monitor brand abuse, prioritize risk and generate actionable intelligence.
Current release: v0.11.1 — Community Preview (AGPL-3.0-or-later). This is a preview, not 1.0: feature-rich and tested, but schema/API/UI may still evolve before a stable 1.0.
- Release notes:
docs/RELEASE_NOTES_v0.11.1.md - Changelog:
CHANGELOG.md - Roadmap (Community × Enterprise):
ROADMAP.md - Governance & maintainer:
GOVERNANCE.md
ThreatForge Community v0.11.1 corrects IOC enrichment semantics by
distinguishing unavailable or skipped intelligence sources from completed
negative lookups. It preserves positive scoring, normalizes unsupported
zero-score outcomes to unknown, and presents public enrichment and feed
synchronization messages in English.
ThreatForge Community v0.11.0 introduces an operational Intelligence Workspace for authorized inbound collection, provider-neutral event review, collector and source health, redacted evidence, tenant isolation and investigation linkage. Runtime acceptance validated the Community core and optional Enterprise overlay on the same schema and API release train.
ThreatForge Community can optionally integrate with the private ThreatForge Enterprise package when it is installed.
The Community repository does not include Enterprise implementation code.
See Optional Enterprise Adapter.
ThreatForge is delivered as two editions on the same release train, schema and API:
- Community Edition: the open source CTI and Digital Risk Protection core, distributed under AGPL-3.0-or-later.
- Enterprise Edition: a private/commercial overlay with signed licensing, trial mode, premium providers, continuous intelligence collection and enterprise operational controls.
Enterprise is installed as an overlay package; it is not a fork and does not require a separate database migration path.
See Product Strategy.
- IOC intake — register IPs, domains, URLs, hashes, e-mails and CVEs through the API.
- Public connectors — CISA KEV, URLhaus/abuse.ch, MITRE ATT&CK and EPSS/FIRST.
- Enrichment — query relevant sources based on observable type.
- Explainable scoring — risk score from 0 to 100 with transparent factors and reasoning.
- Reports — generate technical Markdown reports for observables.
- Brand intake — register brand names, official domains and keywords.
- Typosquatting detection — generate variations using homoglyphs, adjacent keys, omissions and lure terms such as
secure,login,pix,invoice,2faandsupport. - Certificate Transparency discovery — identify real domains mentioning the monitored brand in CT logs.
- Finding enrichment — DNS, MX, RDAP, domain age, certificate age and URLhaus correlation.
- Explainable abuse scoring — prioritize active, recent and brand-similar domains.
- Alerts — Telegram, webhook and SMTP alerts for suspicious or malicious findings.
- Web login — UI served by the API at
http://localhost:8000/. - Authentication — JWT session stored in
httpOnlyandSameSite=Strictcookies. - Secure password handling — Argon2id when available, with PBKDF2-HMAC-SHA256 fallback.
- Tenant roles —
admin,analystandviewer. - Platform roles —
platform_admin,support_operatorandsupport_viewer. - Audit logs — sensitive actions logged with user, operator, tenant, IP and user-agent context.
- Web hardening — CSP, security headers, login rate limiting and generic authentication errors.
- Operational overview — provider-neutral totals, recent collection volume, processing states, active sources and collector health. Overview metric cards are keyboard-accessible and open contextual summaries with direct feed or configuration actions.
- Intelligence Feed — tenant-scoped, redacted events with source/provider/state filters, text search and stable cursor pagination.
- Secure event detail — inert redacted content, sanitized context, processing metadata and links to findings or cases; raw provider payloads, external identifiers, fingerprints and secrets are never exposed.
- Control-plane separation — the Integrations view configures connections and authorized sources; collected evidence is reviewed in Intelligence.
- RBAC and audit — viewer access to operational summaries; analyst/admin access to redacted evidence, with event-list and event-detail reads recorded in the audit trail.
- Telegram Intelligence — authorized inbound Bot API collection is distinct from outbound Telegram alert notifications.
- Explainable automated analysis — Enterprise classification correlates redacted text with tenant-scoped brands, public monitored assets and approved sensitive terms, recording matched target, threat intent, negation/context signals and a deterministic confidence score.
- Controlled promotion — optional fail-safe policy can create an idempotent Exposure finding at the configured threshold and open one deduplicated investigation case at the higher threshold. Automatic notifications remain separate and require human review before response.
Inbound collection flow:
Authorized Telegram source → collection worker → normalized/redacted event
→ Intelligence Workspace → analysis → finding/case
Outbound notification flow:
ThreatForge finding → Telegram alert destination
- Exposure Monitoring — monitored assets, findings, manual/authorized intake, deduplication and server-side redaction.
- Attack Surface Discovery — passive discovery and manual import for subdomains, IPs and certificates.
- Credential Intelligence — identity rollup, password-reuse grouping and VIP credential leak handling.
- Operational Dashboard — tenant-scoped overview for cases, exposure findings, monitored assets, integrations and intelligence activity. Dashboard KPI cards are keyboard-accessible, open contextual summaries and provide direct navigation to the corresponding operational workspace.
- Investigation cases — manage findings through cases with severity, status, assignee and audit trail.
- Evidence and notes — attach evidence metadata, preserve SHA-256 hashes and add internal notes.
- Operational review history — append-only case reviews through
GET /cases/{case_id}/reviewsandPOST /cases/{case_id}/reviews.
ThreatForge is multi-tenant. Each customer is represented as an isolated tenant. Sensitive tables include tenant_id, and tenant-owned queries are scoped by tenant to prevent cross-tenant data exposure.
There are two main access models:
- Platform operator — creates and manages tenants, operators, invitations and API keys. To operate on a specific tenant through the API, the operator uses the
X-Tenant-Idheader. - Tenant user — bound to a single
tenant_idand only allowed to access data from that tenant.
API keys are tenant-scoped. The API_KEY value configured in .env works as a platform automation key.
Copy the example environment file:
cp .env.example .envGenerate strong values for sensitive variables:
openssl rand -hex 32
openssl rand -hex 32
openssl rand -hex 32Edit .env:
vi .envConfigure at least:
API_KEY=<generated_value>
POSTGRES_PASSWORD=<generated_value>
JWT_SECRET=<generated_value>
COOKIE_SECURE=false
APP_BASE_URL=http://localhost:8000Notes:
-
use different values for
API_KEY,POSTGRES_PASSWORDandJWT_SECRET; -
never commit
.env; -
for local HTTP usage, keep
COOKIE_SECURE=false; -
for production over HTTPS, use
COOKIE_SECURE=true; -
APP_BASE_URLis used to build invitation links. -
DATABASE_URLandPOSTGRES_PASSWORDmust be kept in sync. In the normal Docker flow,docker-compose.ymlexplicitly sets theapiservice'sDATABASE_URLfromPOSTGRES_PASSWORD(lineDATABASE_URL: postgresql+psycopg2://threatforge:${POSTGRES_PASSWORD}@db:5432/threatforge), which overrides whateverDATABASE_URLyou have in.env. So under Compose you only need to setPOSTGRES_PASSWORDin.env. If you ever run the API outside Compose (bareuvicorn, an external Postgres, or otherwise sourcingDATABASE_URLyourself), the password embedded inDATABASE_URLmust matchPOSTGRES_PASSWORDexactly, or authentication against the database will fail. -
If the Postgres data volume was already created with an old password, changing
POSTGRES_PASSWORDin.envalone will not update the database user's password — Postgres only reads that variable on first initialization of an empty volume. In that case, reset the local volume:docker compose down -v
⚠️ docker compose down -vdeletes the named volumes (pgdata,evidence_data), which removes all local data (tenants, users, findings, evidence). Only use it in development/POC environments, never against data you need to keep.
Start the application:
docker compose up -d --buildValidate the installation:
curl http://localhost:8000/healthExpected response (version tracks the current release, e.g. 0.11.1):
{"status":"ok","service":"threatforge","version":"0.11.1"}The API and UI will be available at:
http://localhost:8000
Interactive API documentation is available at:
http://localhost:8000/docs
Run the main selftest:
docker compose exec api python -m app.selftest_isolationExpected result (the full chain of scenarios covered by the selftest):
TENANT ISOLATION + INVITES + OPERATOR ROLES + BRAND EDIT + ARCHIVE/DELETE + CASES + NOTES + EVIDENCE + EXPORT + INTEGRATIONS + EXPOSURE + TIMELINE + RISK + CORRELATION + SURFACE + PROMOTE + CREDINTEL + CREDID + REUSE + VIPALERT + CREDTL + CREDREPORT + LICENSE: ALL TESTS PASSED ✅
This test validates:
- first platform operator creation;
- tenant creation;
- tenant admin authentication;
- tenant isolation for brands and observables;
- cross-tenant access blocking by ID;
- tenant-scoped API keys;
- invite flow with hashed token, expiration and single use;
- support operators without tenant assignment being blocked;
- support operators accessing only assigned tenants;
- support operators being blocked from administrative and destructive actions;
- tenant suspension/reactivation by platform admin;
- audit logging;
- immediate access revocation for support operators.
Open:
http://localhost:8000/
On a clean installation, the first step is to create the platform operator.
This first user becomes platform_admin and can:
- create tenants/customers;
- create support operators;
- create access invitations;
- create tenant API keys;
- access the platform operations view;
- review audit logs.
Create the first platform operator through the UI.
Then create two tenants, for example:
Customer A
Customer B
Create one admin user for each tenant.
Expected result:
- platform admin can access the platform operations view;
- tenants are created correctly;
- customer users are bound to the correct tenant.
Log in as Customer A admin and create tenant-owned data, such as brands and observables.
Then log in as Customer B admin and create different data.
Expected result:
- Customer A only sees Customer A data;
- Customer B only sees Customer B data;
- direct access by ID must not reveal data from another tenant.
Create a support operator.
Grant access only to Customer A.
Expected result:
- support can see only Customer A;
- support cannot see Customer B;
- support cannot create tenants;
- support cannot create operators;
- support cannot create API keys;
- support cannot perform destructive actions;
- after access revocation, support immediately loses access.
When creating a tenant without an admin password, ThreatForge generates an e-mail invitation.
The invitation uses:
- random token;
- hashed token stored in the database;
- expiration;
- single use;
- fixed tenant binding;
- activation only after acceptance.
The invitation link is built using APP_BASE_URL.
In development environments without SMTP configured, the invitation appears in the API logs.
To follow API logs:
docker compose logs -f apiYou can also run MailHog locally:
docker compose -f docker-compose.yml -f docker-compose.mailhog.yml up -d --buildMailHog UI:
http://localhost:8025
The default flow is to create the first platform operator through the UI.
For automated environments, the initial operator can be created on first startup by setting:
BOOTSTRAP_OPERATOR_EMAIL=admin.platform@threatforge.local
BOOTSTRAP_OPERATOR_PASSWORD=<strong_password>Use this mode only when automation is required. For local development, UI onboarding is simpler.
The variables below are legacy from the previous single-tenant flow and should not be used in the current multi-tenant flow:
BOOTSTRAP_ADMIN_EMAIL=
BOOTSTRAP_ADMIN_PASSWORD=Define the platform key:
export API_KEY="value-defined-in-.env"For platform calls acting on a specific tenant, also define X-Tenant-Id.
Example:
export TENANT_ID=1Sync local feeds:
curl -X POST -H "X-API-Key: $API_KEY" http://localhost:8000/sync/kev
curl -X POST -H "X-API-Key: $API_KEY" http://localhost:8000/sync/mitreCreate an observable in a tenant:
curl -X POST \
-H "X-API-Key: $API_KEY" \
-H "X-Tenant-Id: $TENANT_ID" \
-H "Content-Type: application/json" \
-d '{"type": "cve", "value": "CVE-2024-3400"}' \
http://localhost:8000/observablesEnrich and score:
curl -X POST \
-H "X-API-Key: $API_KEY" \
-H "X-Tenant-Id: $TENANT_ID" \
http://localhost:8000/observables/1/enrichGenerate a Markdown report:
curl \
-H "X-API-Key: $API_KEY" \
-H "X-Tenant-Id: $TENANT_ID" \
http://localhost:8000/reports/observable/1Defanged values are accepted, for example:
hxxp://example[.]com
They are normalized automatically.
Create a brand with official domains:
curl -X POST \
-H "X-API-Key: $API_KEY" \
-H "X-Tenant-Id: $TENANT_ID" \
-H "Content-Type: application/json" \
-d '{"name": "Example Bank", "official_domains": ["examplebank.com"], "keywords": ["examplebank"]}' \
http://localhost:8000/brandsRun a scan:
curl -X POST \
-H "X-API-Key: $API_KEY" \
-H "X-Tenant-Id: $TENANT_ID" \
http://localhost:8000/brands/1/scanList prioritized findings:
curl \
-H "X-API-Key: $API_KEY" \
-H "X-Tenant-Id: $TENANT_ID" \
"http://localhost:8000/brands/1/findings?min_score=45"Update a finding status:
curl -X PATCH \
-H "X-API-Key: $API_KEY" \
-H "X-Tenant-Id: $TENANT_ID" \
-H "Content-Type: application/json" \
-d '{"status": "takedown_requested"}' \
http://localhost:8000/brands/findings/10Use ?deep=false for a faster scan.
For recurring scans, schedule:
POST /brands/{id}/scan
Alerts are triggered only for findings with a verdict equal to or higher than ALERT_MIN_VERDICT.
ThreatForge does not perform automatic takedown.
It supports the defensive workflow by helping teams:
- identify suspicious findings;
- register evidence;
- calculate risk;
- manage status;
- track response progress.
Takedown actions must be executed through authorized channels and with human review.
| Type | Example | Enrichment Sources |
|---|---|---|
ip |
203.0.113.10 |
URLhaus host |
domain |
example[.]com |
URLhaus host |
url |
hxxp://evil.example/x |
URLhaus URL |
hash |
MD5/SHA1/SHA256 | URLhaus payload |
cve |
CVE-2024-3400 |
CISA KEV + EPSS |
email |
a@b.com |
Intake only in MVP |
The score is the sum of explainable factors, capped from 0 to 100.
| Factor | Points | Source |
|---|---|---|
| Listed in CISA KEV | +50 | CISA |
| Known ransomware usage in KEV | +10 | CISA |
| EPSS | up to +30 | FIRST |
| Active URL in URLhaus | +45, with bonus if online | abuse.ch |
| Host with malicious URLs in URLhaus | +35 | abuse.ch |
| Known payload in URLhaus | +45 | abuse.ch |
Verdicts:
| Condition | Verdict |
|---|---|
| Score 70–100 | malicious |
| Score 40–69 | suspicious |
| Score 1–39 | low |
| Score 0 after a recognized source completed a negative lookup | no_known_threat |
| No recognized source completed a lookup | unknown |
| Variable | Required | Description |
|---|---|---|
API_KEY |
yes | Platform automation key used through the X-API-Key header |
POSTGRES_PASSWORD |
yes for Docker Compose | PostgreSQL password used by compose |
JWT_SECRET |
recommended | Secret used to sign JWT sessions |
DATABASE_URL |
no | Default: compose PostgreSQL. SQLite is supported for development |
COOKIE_SECURE |
yes | false for local HTTP; true for production HTTPS |
APP_BASE_URL |
yes | Base URL used to generate invitation links |
INVITE_TTL_HOURS |
no | Invitation validity in hours. Default: 168 |
CORS_ORIGINS |
no | Comma-separated allowed origins |
ABUSECH_API_KEY |
no | abuse.ch Auth-Key for URLhaus |
Automatic promotion is disabled by default. The collector reads these variables from the ignored local Enterprise environment file:
| Variable | Default | Description |
|---|---|---|
THREATFORGE_INTELLIGENCE_AUTO_FINDING |
false |
Create an idempotent Exposure finding when the explainable score reaches the finding threshold. |
THREATFORGE_INTELLIGENCE_AUTO_CASE |
false |
Open/reuse an investigation case only when automatic finding creation is enabled and the case threshold is reached. |
THREATFORGE_INTELLIGENCE_FINDING_THRESHOLD |
60 |
Minimum score for automatic finding creation. |
THREATFORGE_INTELLIGENCE_CASE_THRESHOLD |
80 |
Minimum score for automatic case creation; never lower than the finding threshold. |
THREATFORGE_INTELLIGENCE_ANALYSIS_BATCH_SIZE |
25 |
Maximum normalized events analyzed in one collector cycle. |
The implementation is fail-safe: negation and approved-testing context prevent automatic promotion, repeated same-day evidence for the same target/category reuses the same finding and case, and raw message text is not copied into finding, case or audit metadata.
| Variable | Description |
|---|---|
ALERT_MIN_VERDICT |
Minimum verdict required to alert: low, suspicious or malicious |
TELEGRAM_BOT_TOKEN |
Outbound Telegram alert bot token |
TELEGRAM_CHAT_ID |
Outbound Telegram alert destination chat ID |
ALERT_WEBHOOK_URL |
Webhook for Slack, Discord, Teams, SIEM or SOAR |
SMTP_HOST |
SMTP server |
SMTP_PORT |
SMTP port |
SMTP_USER |
SMTP user |
SMTP_PASSWORD |
SMTP password |
SMTP_FROM |
Sender |
SMTP_TO |
Recipient |
SMTP_STARTTLS |
Enables STARTTLS |
Each alert channel is independent and best-effort. Failure in one channel does not block scans or the other channels.
These variables configure outbound notifications only. Authorized inbound Telegram Intelligence collection uses an opaque Secret Resolver reference and the Enterprise collection worker; the bot token is never entered or returned through the Intelligence Workspace.
List containers:
docker compose psAPI logs:
docker compose logs -f apiRestart:
docker compose restartStop:
docker compose downStop and remove local volumes:
docker compose down -vUse docker compose down -v only when you want to delete the local database and start from scratch.
ThreatForge Community is the open source edition.
ThreatForge Enterprise is the private/commercial overlay focused on:
- license management;
- 90-day trial;
- professional PDF reports;
- advanced case workflow, SLA/queue, approvals and analyst handoff;
- investigation graph;
- enterprise integrations;
- advanced MSSP mode;
- advanced audit and governance;
- premium connectors;
- authorized continuous intelligence collection;
- provider-specific collectors and analyzers;
- Intelligence Workspace entitlements and enterprise operational controls.
Enterprise-only modules must not be committed to this public repository.
The v0.11.0 Dashboard uses interactive, keyboard-accessible KPI cards. Selecting a metric opens a tenant-scoped contextual summary and a direct action to the corresponding operational workspace; the Dashboard does not expose raw Telegram messages, provider identifiers or secret references.
The v0.11.0 runtime acceptance validated Dashboard, Intelligence Overview, Intelligence Feed, Event Detail, Integrations and Telegram Source Management. Customer-specific acceptance evidence and operational secrets remain outside the public product repository.
ThreatForge Community has completed the open source readiness baseline.
Current baseline:
- CI workflow;
- security hardening baseline;
- public readiness validation;
- Community/Enterprise separation;
- optional Enterprise adapter;
- invitation token log redaction;
- Docker deployment;
- tenant isolation selftest;
- open source governance documentation.
ThreatForge Community is currently prepared for v0.11.1 Community Preview.
ThreatForge v0.11.1 corrects IOC enrichment verdict semantics and public
status messages.
ThreatForge v0.11.0 delivers Telegram Intelligence collection foundations, the provider-neutral Intelligence Workspace, source and collector observability, tenant-scoped correlation and dashboard integration.
The historical v0.7/v0.8/v0.9 milestones and the first v0.10 operational review workflow backend slice have already landed on main.
Future work is tracked in the canonical roadmap:
- ROADMAP.md — Community × Enterprise roadmap
- CHANGELOG.md — completed milestones
- docs/RELEASE_NOTES_v0.11.1.md — current public preview release notes
ThreatForge uses a dual-licensing model.
- Community Edition (this repository) — GNU Affero General Public License,
version 3 or later (
SPDX-License-Identifier: AGPL-3.0-or-later). Full text inLICENSE. - Enterprise Edition (private
threatforge-enterpriserepository) — commercial license. SeeCOMMERCIAL.md.
AGPL-3.0 section 13 (network use): ThreatForge is normally run as a network service. If you modify it and offer it to users over a network, you must make the Corresponding Source of your modified version available to those users under the AGPL. If that is incompatible with your deployment, a commercial license is available — contact commercial@cbgsecurity.com.br.
Both editions share the same database and schema. Enterprise is an overlay
package that unlocks gated features via app/features.py and the pluggable
registries — no fork, no migration. Upgrade by installing the Enterprise package
and activating a license (see docs/ENTERPRISE_INSTALL.md).
| Capability | Community (AGPL-3.0) | Enterprise (commercial) |
|---|---|---|
| CTI core (IOCs, scoring, connectors: CISA KEV / URLhaus / MITRE ATT&CK / EPSS) | Yes | Yes |
| Brand monitoring, typosquat, passive scanner (crt.sh / DNS / RDAP) | Yes | Yes |
| Multi-tenant isolation, RBAC, audit log, SSO-ready auth | Yes | Yes |
| Exposure Monitoring (DRP): assets, findings, manual/authorized intake, dedup, server-side redaction | Yes | Yes |
| Attack Surface Discovery (passive, manual import) | Yes | Yes |
| Credential Intelligence (identity rollup, password-reuse, VIP hits) — local intake | Yes | Yes |
| Risk score, Timeline, Correlation engine + graph view | Yes | Yes |
| Investigation cases, evidence, notes, operational review history | Yes | Yes |
| Markdown / JSON export, partial STIX 2.1 export | Yes | Yes |
PDF export (cases, credential dossiers) — export.pdf |
Locked (402) | Yes |
MISP / OpenCTI / generic integrations — integration.* |
Catalog + stubs (402) | Yes |
| Intelligence Workspace operational catalog and provider-neutral UI | Visible catalog / locked event access | Yes |
Telegram Intelligence authorized inbound collection — collection.telegram |
Locked (402) | Yes |
Telegram Intelligence analysis — analysis.telegram |
Locked (402) | Yes |
| Outbound Telegram finding notifications | Yes | Yes |
| Collector/source health and collection observability | Visible status / locked operations | Yes |
Premium enrichment — enrichment.premium |
Locked (402) | Yes |
| Automated feeds (stealer / breach / paste / dark & deep web) | No | Yes |
| Continuous monitoring & real-time alerts | No | Yes |
| k-anonymity breach enrichment (HIBP-style, hash-prefix only) | No | Yes |
| Active surface scanning (ports / Shodan / Censys, allowlisted) | No | Yes |
| Commercial support, SLAs, indemnification | Community support | Yes |
Locked Community features are visible in the UI with an upgrade call-to-action and return HTTP 402 when invoked without an active license.
- Can I use it internally? Yes.
- Can I study and modify it? Yes.
- Can I contribute? Yes — under AGPL-3.0-or-later with a DCO sign-off (see
CONTRIBUTING.md). - Can I sell a SaaS based on ThreatForge Community? Only by complying with the AGPL (including section 13 — publish your modified source to your users) or by purchasing a commercial license.
- How do I upgrade to Enterprise? Install the Enterprise package and activate a license. No database migration or platform reinstall — same schema. See
docs/ENTERPRISE_INSTALL.md. - Who maintains ThreatForge? ThreatForge is developed and maintained by CBG Assessoria e Consultoria, founded by Bruno Augusto Lobo Soares. Website: https://cbgsecurity.com.br.
Full details and worked examples: docs/LICENSE_FAQ.md.
Commercial licensing: commercial@cbgsecurity.com.br · Security: security@cbgsecurity.com.br · Community: opensource@cbgsecurity.com.br.
ThreatForge v0.11.0 adds privacy-preserving credential-exposure detection and bounded conversation correlation. E-mail local parts are removed while approved domains remain available as safe indicators; provider actors are represented only by a one-way pseudonymous reference. Related credential-exposure, claimed-access and market-continuation events reuse one finding and one investigation case.
TF-VERIFY source controls are generated dynamically from the Integrations
control plane and are valid only for the matching tenant, connection, source and
unexpired pending request. The plaintext nonce is returned once and only its
SHA-256 hash is stored. Static TF-VERIFY-* text never receives control status.
Acceptance conversations and customer-specific evidence are maintained outside the product repositories. Source-controlled tests use neutral synthetic targets and identifiers only.
ThreatForge v0.11.0 makes deduplicated intelligence activity visible from the Cases and Dashboard surfaces. A repeated event can reuse an existing finding and case without creating duplicate investigations; the case list now shows the linked intelligence source, exposure finding reference, correlated-event count and last activity. The case detail adds the decision, confidence, correlation family, first/last event timestamps and a safe list of tenant-scoped event IDs.
The Dashboard distinguishes the number of investigation cases from the number of intelligence events correlated into those cases. All values are computed from real tenant-scoped relations. These responses never read or expose message text, provider payloads, actor identifiers, chat identifiers, fingerprints or secret material.
Premium actions use canonical feature keys end to end. The Cases UI reads the
viewer-safe /license/capabilities projection for presentation only; the PDF
endpoint remains the authority and records feature.allowed or feature.denied.
A valid license granting export.pdf displays Export PDF without a lock and
must generate a real PDF. License material, signatures, paths and installation
secrets are never returned to the browser.
Enterprise case PDF export now uses tenant-scoped case correlation metadata rather than a placeholder finding. A single-case report includes the tenant name, case status, canonical severity, risk score, linked finding, source, analysis decision, confidence, correlation family, correlated-event count, first/last activity, safe event references, human-review requirement and actionable recommendations.
Severity values used by the Community case workflow (baixo, medio, alto,
critico) are normalized to the Enterprise report vocabulary. Provider message
content, actor/chat identifiers, raw payloads, fingerprints, storage paths and
license identifiers are never included in the report. The export remains one PDF
per investigation case; a consolidated multi-case report is a separate product
capability.
Report header semantics are explicit: Tenant identifies the monitored tenant,
while Prepared for resolves to the institutional customer from the verified
Enterprise license. A report-provided recipient is used only as a compatibility
fallback when the signed license has no customer name. Long case titles are
wrapped within the printable cover width so the report heading is never clipped.





