Open-source platform for NIS2 Directive (EU 2022/2555) continuous posture management. Governance framework, technical validation engine, remediation playbooks, incident response workflows, and supply chain risk management.
Designed for self-hosted, on-premise deployment. Your scan data, asset inventory, and vulnerability reports never leave your infrastructure.
For CISO, DPO, NIS2 consultants, and IT teams bridging the gap between compliance documentation and operational execution.
Part of the CertMate ecosystem for TLS / certificate operations and EU compliance:
- CertMate — open-source SSL certificate management (API + UI).
- certmate-tools — free, privacy-first, client-side TLS / certificate / ACME diagnostics.
- certmate-agent — conversational assistant for CertMate (local LLM + REST API + RAG).
Enterprise / high-scale — multi-tenant, mTLS, white-label and NIS2-aligned TLS deployments are available through CertMate-ng (source-available, BSL 1.1, EU-built). Contact fabrizio.salmi@gmail.com.
This is not a scanner that calls itself a compliance platform. It's a GRC layer with an integrated technical validation engine. It does not replace a CISO, an internal audit programme, or a real legal review of your D.Lgs 138/2024 obligations.
| Layer | What it does |
|---|---|
| Governance Framework | 30-item checklist cross-referenced to NIS2 Art. 21 sub-paragraphs, document tracking, owner assignment |
| Remediation and Execution Control | Structured playbooks, open/acknowledged/resolved workflow. An optional LLM copilot exists as an API endpoint (see below) but has no dashboard screen |
| Technical Validation Engine | 30+ automated checks (TLS, DNS, ports, certificates, headers, secrets) — the probe that verifies if the network reflects the policy |
The scanner is the technical probe. The governance framework is where the substantive NIS2 work lives — and most of it is human work, not automation.
Read this before the feature tables below. Several modules exist as a working REST API but have no write path in the web UI — records must be created with curl, an API key, or the MCP tools. That is a real limitation for the audience this platform targets, and it is stated here rather than buried.
| Module | Dashboard | API |
|---|---|---|
| Assets, Scans, Findings, Reports | full read + write | full |
| Governance checklist (Art. 21) | full read + write | full |
| Organizations, members, API keys, audit log | full read + write | full |
| Vendors / supply chain (Art. 18) | full read + write | full CRUD |
| Business Impact Analysis | full read + write | full CRUD |
| Incidents (Art. 23) | full read + write — declare, revise, close; the 24h/72h/1-month countdown runs from the recorded detection time | full CRUD (/incident-monitor) |
| Notification channels | full read + write, with a test-send | /notification-channels |
| CSIRT "Red Button" | three-field emergency declaration on the Incidents screen; declaring starts the Art. 23 clocks and returns the Early Warning payload | POST /csirt/emergency |
| ACN export (Italy) | export buttons on Suppliers and Business Impact | GET /acn-export/art18, /bia |
| Compliance deadline countdown | statutory dates with urgency bands on the Compliance screen | GET /deadlines |
| Deep certificate analysis | dedicated Certificates screen — chain, key strength, CT presence, SANs, expiry | /certificates (3 endpoints) |
| AI remediation copilot | no UI — findings show only the scanner's static remediation string | POST /remediation/explain |
| TOTP MFA | enrolment, recovery codes and removal from the profile screen | /auth/totp/setup|verify|disable |
On Art. 23 alerting. Deadline alerts are dispatched to the notification
channels you configure under Settings → Notifications (email, HMAC-SHA256 signed
webhook, or Slack), and each channel has a test-send so you can confirm delivery
before an incident rather than during one. With no channel configured the
platform falls back to emailing organisation admins, which needs SMTP_* set;
with neither, the alert is written to the application log only.
Two incident tables, on purpose. incidents is the lifecycle record that
carries the Art. 23 deadlines — it is what the countdown, the alerting task and
the report dossier read, and what "Declare incident" creates. incident_reports
behind POST /api/v1/incidents is the separate CSIRT submission artefact.
Contributions closing the remaining gaps above are welcome; they are the highest-value work in the project.
The compliance matrix references all ten sub-paragraphs (a) through (j). Several of them — by design of the directive itself — cannot be evaluated by an automated scanner and are tracked through the governance checklist (status: manual verification required). What the platform automates vs. what stays manual:
| Sub-paragraph | Scope | Implementation status | How the platform supports it |
|---|---|---|---|
| (a) Risk analysis policies | Methodology, periodic updates | Partial — automated bridge from scanner findings | Governance checklist + POST /governance/sync-risk automatically escalates checklist items when HIGH/CRITICAL scanner findings are open; risk summary via GET /governance/risk-summary |
| (b) Incident handling | Detection, response, CSIRT notification | Implemented — end to end, dashboard included | Declare an incident and its 24 h / 72 h / 1-month clocks start from the recorded detection time; Celery beat checks every 15 min and dispatches to the notification channels you configure (email / signed webhook / Slack), with Redis-backed dedup and a test-send per channel. Submission to CSIRT Italia remains a manual step |
| (c) Business continuity | BCP, DRP, backup, periodic testing | Implemented — manual verification | BIA module (RTO/RPO/MTPD), 5-dimension impact scoring, BCP/DRP gap detection, editable from the dashboard |
| (d) Supply chain security | Vendor assessment, contracts, monitoring | Implemented — transparent scoring formula | Vendor Risk module (Art. 18), editable from the dashboard, with a documented 100-point scoring formula (certification, data access, audit recency, geography, security clauses) and an auditor-facing GET /vendors/score-formula |
| (e) Secure acquisition and development | SDLC, code review, vulnerability management | Partial — scanner automates surface checks | Technical validation engine (TLS, headers, secrets, ports) + governance checklist for organisational controls |
| (f) Effectiveness assessment | Internal audits, KPIs, penetration testing | Partial — scan-driven | Technical validation engine + checklist |
| (g) Cyber hygiene and training | Awareness, phishing simulation | Manual | Governance checklist (human verification required by design) |
| (h) Cryptography | Crypto policy, key management | Partial — automated for public-facing TLS | Technical validation (TLS version, cipher suites, cert expiry, HSTS) + checklist for key-management policy |
| (i) Human resources security | Onboarding/offboarding, screening, PAM | Manual | Governance checklist (human verification required by design) |
| (j) Authentication and access control | MFA, RBAC, PAM, SSO, access logging | Implemented — TOTP MFA, RBAC, audit log, API key scopes | TOTP MFA enrolled and removed from the profile screen, with single-use recovery codes and an MFA-gated login; role-based access in three tiers (admin / auditor / viewer, defined in app/dependencies.py: auditor creates and edits the compliance record but cannot delete or reconfigure), per-request scoped API keys (dual_auth_with_scope), per-request audit log, RS256 JWT with GET /.well-known/jwks.json |
The per-sub-paragraph detail, with what each status rests on, is in docs/reference/compliance-matrix.md (italiano). The statuses there and here are checked against each other in CI.
Legend: Implemented = available end-to-end, dashboard included, with no manual step required. Partial = either the automated checks cover only the technically observable surface and organisational controls need human verification, or the capability exists in the API but not yet in the dashboard — the "How the platform supports it" column says which. Manual = the directive explicitly requires human judgement; automation cannot substitute.
Incident lifecycle aligned with the legal deadlines:
| Phase | Deadline | Platform support | Reachable from |
|---|---|---|---|
| Early Warning | 24 hours | Clock starts at the recorded detection time; alert 2 h before / on breach | Dashboard — declare, revise, close |
| Incident Notification | 72 hours | Structured taxonomy, impact category, affected systems; alert 2 h before / on breach | Dashboard |
| Final Report | 1 month | Aggregated data, impact assessment, lessons learned; alert 2 h before / on breach | Dashboard |
| Live countdown across open incidents | — | 24h / 72h / 1-month clocks, per incident | Dashboard |
Before relying on the alerting, configure at least one notification channel under Settings → Notifications and use its test-send. With none configured the deadline monitor falls back to emailing organisation admins, which needs
SMTP_*set; with neither, the alert is written to the application log only.Deadlines are computed from the detection time you record, not from when you entered the incident, and they are fixed at declaration — a later edit cannot move an obligation you may already have acted on.
Submission to CSIRT Italia is a manual step through
csirt.gov.it. There is no automated push to the CSIRT portal.
| Feature | Status |
|---|---|
| Vendor inventory with criticality classification (1-4) | Implemented |
| Security assessment scoring (0-100) | Implemented |
| Contract tracking (SLA, audit rights, security clauses) | Implemented |
| Geographic location and data access level | Implemented |
| Certification tracking (ISO 27001, SOC2, CSA STAR) | Implemented |
| ACN Art. 18 relevance flagging (Italy) | Implemented |
| Feature | Status |
|---|---|
| Business process inventory with criticality levels | Implemented |
| RTO/RPO/MTPD definition per process | Implemented |
| 5-dimension impact scoring (financial, operational, reputational, regulatory, safety) | Implemented |
| Asset and vendor dependency mapping | Implemented |
| BCP/DRP gap detection | Implemented |
| Impact matrix with automatic gap identification | Implemented |
The NIS2 Directive requires each EU member state to transpose it into national law. This platform provides a reference implementation for Italy, extensible to other jurisdictions.
| Reference | Coverage |
|---|---|
| D.Lgs 138/2024 (Italian NIS2 transposition) | Art. 21 cross-reference in the governance checklist |
| Determina ACN 127434/2026 | Technical baseline references in the compliance matrix |
| Determina ACN 127437/2026 | Art. 18 vendor inventory with ACN-specific fields |
| ACN BIA template | Internal model in place; alignment to the official ACN model pending publication |
| Compliance deadlines | Real countdowns: CSIRT referent (Dec 2026), 24h notification (Jan 2027), baseline measures (Jul 2027). Shown with urgency bands on the Compliance screen |
| ACN-compatible JSON export | /api/v1/acn-export/art18 and /api/v1/acn-export/bia, with export buttons on Suppliers and Business Impact. Schema is preliminary, pending the official ACN modello di categorizzazione |
ACN export — preliminary schema. The official modello di categorizzazione announced by ACN (publication expected May/June 2026 per the Tavolo NIS) has not been released yet. The current export is a best-effort structural mapping based on Determina 127437/2026; field names and shape will be re-validated and may change once the official template is published.
The governance checklist maps to NIS2 Art. 21 at the EU level. National-specific modules (like the Italian ACN module) can be added for ANSSI (France), BSI (Germany), CCN-CERT (Spain) and others — contributions welcome.
A CISO of an essential entity will not upload their vulnerability data to a third-party cloud. This platform is designed to run inside your perimeter.
| Tool | Why | Notes |
|---|---|---|
| Docker + Docker Compose v2.20+ | Runs the API, web, scanner, postgres, redis, celery containers | compose v2.20 is required for --wait on healthchecks (make dev / make prod rely on it) |
| GNU Make | Drives the standardised targets (dev, prod, clean, test, etc.) |
Pre-installed on macOS / Linux. On Windows: install via Git Bash, WSL2, or Chocolatey |
| Python 3.10+ on the host | Used by make clean, make clean-all, and make test-* (pytest) |
Linux/macOS package manager works; on Windows install from python.org (the Microsoft Store stub at %LOCALAPPDATA%\Microsoft\WindowsApps\python.exe is not a real Python — disable that alias in Settings → Apps → Apps & Features → App execution aliases). The Makefile detects python3 / py / python in that order. |
openssl (or any random-bytes generator) |
Generates JWT_SECRET, POSTGRES_PASSWORD, NIS2_APP_PASSWORD and REDIS_PASSWORD for production deploys |
openssl rand -base64 32 is the canonical recipe |
The platform itself runs inside containers and pulls all its runtime deps from the images — Node, Postgres, Redis, the Python interpreter for the API, etc. The host-side prerequisites above only drive build / clean / test from the Makefile.
git clone https://github.com/fabriziosalmi/nis2-public.git
cd nis2-public
cp .env.example .env # Generate real secrets — see comments inside
make prod # Production: Caddy auto-HTTPS + all services
# Or development:
make dev # http://localhost:8077 (UI) + http://localhost:8000/docs (API)All data stays in your PostgreSQL instance. No telemetry, no external calls, no cloud dependencies.
make prod runs a pre-flight check (prod-preflight) before bringing up the stack. If .env is missing or carries placeholder values for POSTGRES_PASSWORD / JWT_SECRET / CORS_ORIGINS, the target exits early with a self-contained error message describing the exact command to fix it. The minimum recipe to put .env into a runnable shape:
# Postgres password — any non-empty string; rotate before sharing infra
sed -i.bak 's|^POSTGRES_PASSWORD=.*$|POSTGRES_PASSWORD='$(openssl rand -base64 24)'|' .env
# JWT secret — must be ≥32 chars; the API refuses to start otherwise
sed -i.bak 's|^JWT_SECRET=.*$|JWT_SECRET='$(openssl rand -base64 32)'|' .env
# Runtime database role — must match the password embedded in DATABASE_URL.
# The API refuses to start on a superuser role, because Postgres bypasses RLS
# for one and tenant isolation would rest on app-level filters alone.
APP_PW=$(openssl rand -base64 24)
sed -i.bak "s|^NIS2_APP_PASSWORD=.*$|NIS2_APP_PASSWORD=${APP_PW}|" .env
sed -i.bak "s|CHANGE_ME_APP_ROLE_PASSWORD|${APP_PW}|g" .env
# Redis password
sed -i.bak 's|^REDIS_PASSWORD=.*$|REDIS_PASSWORD='$(openssl rand -base64 24)'|' .env
# CORS allow-list — comma-separated, no wildcards. Example:
sed -i.bak 's|^CORS_ORIGINS=.*$|CORS_ORIGINS=https://nis2.example.com|' .env
rm -f .env.bak(macOS users: that's GNU sed syntax. For BSD sed drop the .bak argument or use a different editor — the goal is "replace the placeholder line with a real secret".)
On the optional LLM copilot. POST /api/v1/remediation/explain can call a local OpenAI-compatible server or OpenAI itself; OpenAI egress stays off unless ENABLE_OPENAI=true. Three caveats before planning around it:
- It has no dashboard screen. Findings display the scanner's static remediation string only.
- The shipped default
LLM_API_URL=http://localhost:1234/v1is LM Studio's port (Ollama listens on 11434), andlocalhostinside the API container is that container — not your host. A local model server needs the container-reachable address, e.g.http://host.docker.internal:11434/v1on Docker Desktop. - With
model: "auto"the request sends the literal model namedefault, which LM Studio accepts and Ollama rejects. Pass a real model name for Ollama.
Finding text is interpolated into the prompt, and that text derives from content fetched from scanned third-party sites. Treat generated remediation commands as untrusted input to be reviewed, never as something to paste into a shell unread.
Before a target can be scanned, the organisation has to establish authority over it. There is no way to add an arbitrary host and press scan.
| Target | Proof | How |
|---|---|---|
| Domain | DNS TXT challenge | Publish _nis2-challenge.<domain> with the issued token. Only someone controlling the zone can, which is what makes it evidence — the mechanism certificate authorities use for DNS-01 |
| IP address, CIDR | Recorded attestation | An address range has no DNS to prove anything with. An admin states authority in their own words; the statement is stored against their account and written to the audit log |
All three paths that can start a scan enforce this — the manual POST /scans,
the scheduled-scan task, and the MCP scan_target tool, which additionally
requires the target to match an asset of the caller's organisation rather than
accepting a free-form host.
An attestation is not available for domains: they have DNS proof, and a signature must never be the easy way around evidence that exists.
Assets created before this existed are marked
legacyand keep working — an upgrade that silently stopped every existing scan would be its own defect. They display as not verified, so they are visible rather than forgotten.
What this is and is not. DNS verification is proof. An attestation is not: nothing can verify authority over an address range from the outside, and RDAP would only say who it is allocated to, not whether you are authorised by them. What the attestation does is move the record from "the platform allowed it" to "this person asserted it, on this date, in these words". Scanning a third party without authorisation carries civil and in places criminal exposure in the EU, and an AXFR attempt plus a request for
/.envis indistinguishable from reconnaissance in the target's logs.
These automated checks verify whether the security measures documented in your governance framework are actually implemented on the network:
These checks run as part of a scan. The right-hand column says what each one establishes, because several of them used to verify that a control was present rather than correct — and a compliance report that records a permissive header as a satisfied measure is worse than one that omits it.
| Category | Checks | What the check establishes |
|---|---|---|
| TLS/SSL | Chain and hostname verification, negotiated protocol and cipher, active TLS 1.0 / 1.1 downgrade probe, HSTS | SNI is sent, so the certificate read is this host's and not the default one a shared IP or CDN answers with. The chain is verified for real; an untrusted or mismatched certificate is reported, and the two are distinguished because they have different fixes. When verification stops at an earlier fault the hostname is reported as undetermined rather than passing. The downgrade probe lowers the security level for the probe alone, and the report states whether the probe was available at all |
| DNS security | DNSSEC (DNSKEY and parent DS), SPF, DMARC, zone transfer (AXFR), MX redundancy | DNSSEC requires both halves: a signed zone with no DS record in the parent has no chain of trust and resolvers ignore the signatures — the most common DNSSEC misconfiguration, and one that a DNSKEY-only check reported as enabled |
| HTTP headers | CSP, HSTS, X-Frame-Options, X-Content-Type-Options, cookie flags, SRI, security.txt | Judged on content. default-src *, 'unsafe-inline', 'unsafe-eval', max-age=1 and max-age=0 (which disables HSTS) are all reported. Cookie flags are parsed as attributes, so a cookie merely named secure_session does not count as Secure, and SameSite=None is distinguished from SameSite=Strict |
| Port exposure | 14 critical ports (SSH, RDP, SMB, MySQL, PostgreSQL, Redis, MongoDB) | TCP reachability from the scanner's vantage point |
| Resilience | WAF/CDN detection, version disclosure | Header and cookie fingerprinting |
| Secrets | AWS keys, GitHub tokens, private keys, JWT in responses | Pattern matching over the first 1 MB of the response body |
| Certificates — chain validation, CT logs (crt.sh), OCSP, key strength, SAN coverage, expiry prediction, 0-100 health score | not part of a scan | The deep analyser is reachable only through POST /api/v1/certificates/check and the MCP check_certificate tool, neither of which has a dashboard screen. Scans, reports and the compliance score do not include it |
CVSS scores in findings are fixed per check type, not computed from the target's context, exposure or compensating controls. Treat them as severity labels, not as CVSS assessments.
On the Art. 21 matrix in the report. Every value names the evidence behind it or says the control is out of scope for an external scan. Supply-chain security (d) and cyber hygiene & training (g) are marked not assessed: an SRI check on
<script>tags is not a partial automation of supplier assessment, and training leaves no trace in an HTTP response. A matrix that claims more than it can evidence is the one thing in this platform most likely to fail in front of an auditor.
These checks verify GDPR / ePrivacy / Consumer Code requirements. They are not NIS2 controls and are clearly labelled as such in all reports — never aggregated into the NIS2 score.
- P.IVA (Italian commercial website requirement)
- Privacy policy detection
- Cookie banner compliance (via Playwright)
| Router | Endpoints | Purpose |
|---|---|---|
/api/v1/auth |
16 | JWT authentication, registration, change-password, forgot/reset password, switch active organization, TOTP setup/verify/disable |
/api/v1/scans |
8 | Scan management, results, comparison. Read endpoints accept API-key Bearer auth |
/api/v1/findings |
5 | Finding lifecycle (open/acknowledged/resolved). Read endpoints accept API-key Bearer auth |
/api/v1/assets |
9 | Asset inventory management. Read endpoints accept API-key Bearer auth |
/api/v1/api-keys |
3 | Long-lived nis2_* Bearer tokens for CI/CD pipelines (raw value shown once) |
/api/v1/audit-logs |
1 | Read-only org-scoped audit trail (90-day retention) |
/api/v1/organizations |
8 | Org settings, members, role management, self-serve org creation |
/api/v1/vendors |
9 | Vendor risk management (Art. 18) |
/api/v1/bia |
6 | Business Impact Analysis |
/api/v1/incidents |
7 | CSIRT submission artefact (table incident_reports) |
/api/v1/incident-monitor |
6 | Art. 23 incident lifecycle — declare/revise/close, live 24h/72h/1-month countdowns |
/api/v1/governance |
9 | Art. 21 checklist, weighted score, sync-risk bridge, risk summary, by-subparagraph |
/api/v1/schedules |
5 | Recurring scan schedules (cron-style, per asset set) |
/api/v1/reports |
3 | Report generation, status polling and download (PDF/A, CSV, JSON, Markdown, JUnit, HTML) |
/api/v1/notifications |
5 | Notification channels (email / signed webhook / Slack) with a per-channel test send |
/api/v1/certificates |
3 | Deep certificate analysis |
/api/v1/remediation |
5 | Playbooks, AI copilot, cost estimation. No dashboard screen |
/api/v1/acn-export |
2 | ACN-compatible JSON export (Italy, preliminary schema). Export buttons on Suppliers and BIA |
/api/v1/deadlines |
1 | Compliance deadline countdown, shown on the Compliance screen |
/api/v1/csirt/emergency |
1 | "Red Button" — declares the incident, starts the Art. 23 clocks and returns the Early Warning payload |
/api/v1/mcp |
2 | Model Context Protocol for AI assistants |
/.well-known/jwks.json |
1 | RS256 public key set for JWT verification |
/.well-known/security.txt |
1 | Responsible disclosure contact |
/health, /health/live, /health/ready |
3 | Three-tier liveness / readiness (DB + Redis + Celery). /health also reports the running version and commit |
/metrics |
1 | Prometheus exposition: request rate, errors, latency by route template, and DB pool utilisation. Unauthenticated — block it at the edge if the API is directly exposed |
Designed for NIS2 consultants and DPO-as-a-service managing multiple clients:
- Organization-based data isolation (
organization_idfilter on every protected query, enforced by PostgresFORCE ROW LEVEL SECURITYpolicies — even the table owner cannot bypass them) - RBAC: admin, auditor, viewer per organization
- Org switcher in the sidebar — a user with memberships in multiple orgs can move between client tenants without logging out (
POST /api/v1/auth/switch-orgremints the JWT with the neworg_idclaim, the FE clears the TanStack Query cache so no stale data leaks, audit log records the transition) - Self-serve org creation — the switcher dropdown has a "Create new organization" footer entry that opens a dialog: enter a name, the API derives a unique slug, the user lands as
accepted_at-stamped admin in the new tenant, and the FE auto-switches into it (POST /api/v1/organizations) - Full NIS2 dossier report per client (PDF/HTML) — cover with score donut, "posture at a glance" hero, Art. 21 a–j coverage heatmap, plus governance / incidents / supply-chain / BIA / findings sections. Archival PDF/A-2b, tagged/accessible, embedded font, localized in all 5 languages
- Aggregated compliance dashboard across all organizations
- Each client's data stays in the same self-hosted instance
| Layer | Technology |
|---|---|
| Frontend | Next.js 15, React 19, shadcn/ui, Tailwind v4, Zustand, TanStack Query, Recharts, next-intl |
| Backend | FastAPI, SQLAlchemy (async), Pydantic v2, Celery, Redis, slowapi |
| Database | PostgreSQL 16 |
| Scanner | Python asyncio, aiohttp, dnspython, Playwright, python-whois |
| Security | CSP/HSTS/X-Frame-Options at the proxy and API layers, rate limiting (SlowAPI), SSRF prevention, API key auth, RS256 JWT + JWKS, Postgres RLS tenant isolation under a NOSUPERUSER NOBYPASSRLS role, audit log retention (90 days). TOTP MFA is enrolled and removed from the profile screen, with an MFA-gated login |
| AI / MCP | MCP Server (stdio + HTTP), Ollama/OpenAI |
| Infra | Docker, Caddy 2 (auto-HTTPS), GitHub Actions CI |
| English | Italiano | Français | Deutsch | Español |
|---|
945 translation keys per locale across 5 locales, at full parity — no locale is missing or carrying an extra key. Cookie-based locale switching.
The documentation site (
docs/) exists in English and Italian only, so a German, French or Spanish user gets a fully localised application and no documentation in their language.
Platform developed and maintained by Fabrizio Salmi, independent NIS2 consultant.
| Service | Description |
|---|---|
| Private NIS2 scan | White-label scan with executive report for the board |
| Certificate remediation | TLS/SSL lifecycle with CertMate and CertMate-NG |
| NIS2 readiness assessment | Gap analysis on all 10 Art. 21 sub-paragraphs |
| Incident response | CSIRT Art. 23 notification support, taxonomy, timeline |
| Continuous monitoring | Scheduled scans, trend analysis, quarterly reports |
| Platform customization | Private deploy, sector modules, SIEM/SOAR integration |
| Training | Board-level NIS2 overview, technical training for IT teams |
Contact: fabrizio.salmi@gmail.com
Related tools: CertMate | CertMate-NG (private — request access)
The 30-item Art. 21 governance checklist shipped with the platform is a community-curated didactic heuristic, not a verbatim reproduction of the official ACN framework. The Italian National Cybersecurity Agency (Agenzia per la Cybersicurezza Nazionale — ACN) has translated the ten NIS2 risk-management measures into a NIST-derived control set detailed across multiple Determinazioni (e.g. Determina 127434/2026, 127437/2026, and follow-ups). The checklist included here is a starting point that maps to the ten Art. 21(2) sub-paragraphs at a high level and references the relevant ACN determinazioni; it does not, and is not intended to, replace a formal ACN-grade audit, a Modello di Categorizzazione filing, or any other regulatory deliverable.
The technical validation engine performs automated checks on publicly-observable surface (TLS, DNS, HTTP headers, port exposure, etc.) — these correspond to a subset of Art. 21(2)(h) "cryptography" and Art. 21(2)(e) "security in network and information systems acquisition" controls. They do not validate organisational controls (risk-management policies, incident-response procedures, supply-chain contracts, HR processes, training records, etc.) which by directive design require human verification.
This platform is a tool for governance and discovery, not legal or compliance advice. Engagement with a qualified NIS2 advisor and direct reference to ACN guidance remain mandatory for any production compliance posture.
Operator identity, VAT (P.IVA), ATECO and the D.Lgs 70/2003 e-commerce disclosure are on the dedicated legal notice. Privacy — the GDPR Art. 13 information notice — is in docs/privacy.md. Contact: fabrizio.salmi@gmail.com.
Self-hosted deployments: when you run this platform on your own infrastructure, you become the data controller under Art. 4(7) GDPR for the personal data processed by your instance (registered users, scan results, asset inventory, audit logs). The maintainer is not the data controller for self-hosted instances and provides no
informativa privacyon your behalf. Adapt docs/privacy.md to your deployment, publish it at a stable URL, and notify your users.
AGPL-3.0 — see LICENSE.
You can freely use, modify, and deploy this platform. If you modify it and offer it as a service to third parties, you must make your modifications available under the same license.
Commercial license / dual licensing available for Enterprise. If your organization needs a commercial license without copyleft obligations, contact fabrizio.salmi@gmail.com.
