# NETMapper security and privacy (netmapper.nx1xlab.dev/docs/security)

NETMapper is a network administration tool that holds switch credentials. This
page covers what the software does to protect them, how to report a problem in
it, and what it sends out about your installation.

Use NETMapper only on networks you own or are explicitly authorized to assess.

## Security posture

- **HttpOnly plus CSRF cookie auth.** The access token rides in an HttpOnly
  cookie, never in localStorage. A separate readable `csrf_token` cookie is
  validated server-side on every mutating route (double-submit), which blocks
  CSRF even in the presence of XSS.
- **bcrypt passwords with a Have I Been Pwned check.** Passwords are hashed
  with bcrypt. On set or change, the hash prefix is checked against the Have
  I Been Pwned range API using k-anonymity, so no full hash leaves the
  server.
- **Secrets encrypted at rest.** Switch passwords, notification-channel
  configs and AI provider keys are sealed with Fernet (AES-128-CBC plus
  HMAC-SHA256) through an `EncryptedString` / `EncryptedJSON` type decorator
  backed by `NETMAPPER_ENCRYPTION_KEY`. Losing that key permanently destroys
  access to those secrets, so back it up out of band.
- **Per-endpoint authorization plus an audit log.** Mutating endpoints are
  gated by granular permission checks from a 24-permission catalog across 9
  categories, with three built-in roles (admin, operator, viewer). Every
  privileged action writes a persistent `AuditLog` row.
- **Rate-limited login.** `POST /auth/login` and `POST /auth/login/json` are
  rate-limited per remote IP (default `5/minute`), and a 429 carries a
  `Retry-After` header.
- **Two-factor authentication.** TOTP 2FA is available for user accounts.
- **TLS.** `docker-compose.https.yml` terminates TLS in nginx with automatic
  Let's Encrypt certificates, or you can bring your own certificate.
- **Supply chain.** Python dependencies are hash-locked with pip-compile
  `--generate-hashes`; npm installs run `npm ci --ignore-scripts` against a
  committed lockfile with sha512 integrity. Docker base images and GitHub
  Actions are pinned by digest, Renovate enforces a seven-day release
  cooldown on new dependency versions, and CI runs Bandit, Trivy, CodeQL,
  pip-audit, npm audit and Gitleaks on every push.

### Known gaps

Rate limiting beyond the login endpoints is not implemented yet; it is
tracked on the roadmap. NETMapper is pre-1.0, only `main` is supported, and
there are no backports to earlier tags. Deploy on a trusted, isolated
management network behind a firewall, ideally behind a zero-trust access
proxy.

## Reporting a vulnerability

Do not open a public GitHub issue for a security report. A public issue
exposes the details before a fix exists.

- **Preferred:** open a private
  [GitHub Security Advisory](https://github.com/NX1X/NETMapper/security/advisories/new).
- **Alternative:** the [contact form](https://nx1xlab.dev/contact), with the
  word "security" in the message so it is routed to the maintainers.

What to expect:

| Stage | Target |
|---|---|
| Initial acknowledgment | 72 hours |
| Triage and severity assessment | 7 days |
| Fix available or mitigation guidance | 90 days from acknowledgment |
| Public disclosure | When the fix ships, or at 90 days, whichever comes first |

You are credited in the CHANGELOG security entry unless you would rather stay
anonymous. If a fix cannot land inside the window, a mitigation advisory is
published on the original acknowledgment date and the open issue is tracked
publicly.

**In scope:** the backend (FastAPI application, migrations, scanner modules,
auth, security and crypto modules, notification delivery), the frontend
(React app, API client, pages and components), the published Docker images,
and the `docker-compose.yml` and `docker-compose.dev.yml` deployment
configuration.

**Out of scope:** your own switch credentials and private keys, your network
topology and scan results (that is your data), third-party dependencies (file
those upstream, though findings are tracked and lockfiles updated),
vulnerabilities that need physical access to the host, and social engineering
of the maintainers.

Research only against instances you own and control, or a lab you set up for
the purpose. Do not probe other people's deployments or switches.

The full policy is in
[SECURITY.md](https://github.com/NX1X/NETMapper/blob/main/SECURITY.md).

## Privacy

NETMapper is self-hosted: your inventory, topology, scan results and audit log
never leave your deployment. Two mechanisms send anything outward at all, and
both are described below.

### Anonymous usage statistics, on by default

NETMapper Core sends one small anonymous ping per day. It exists so the
project knows which versions, platforms and scanner kinds to test and support.
It is on by default and the opt-out is one switch or one variable.

This is the complete payload; the backend enforces the list:

| Field | Meaning |
|---|---|
| `install_id` | Random UUID generated once per installation. Carries no user or network identity. |
| `version` | NETMapper version string. |
| `python_version` | Python version string. |
| `os` | Operating system family, for example `Linux`. |
| `switch_count_bucket` | Active switch count as a bucket (`0`, `1-4`, `5-9`, `10-19`, `20-49`, `50-99`, `100-199`, `200+`), never the exact number. |
| `device_count_bucket` | Active device count, same buckets. |
| `scans_per_day_bucket` | Scans in the last 24 hours, same buckets. |
| `alerts_per_day_bucket` | Alerts in the last 24 hours, same buckets. |
| `scanner_kinds` | Scanner kinds in use, for example `["cisco_ios", "nokia_srl"]`. |
| `ai_provider_kinds` | AI provider kinds configured, for example `["openai", "ollama"]`. |

Nothing about your network: no IPs, MACs, hostnames, switch names,
credentials or scan output. Never sent either: usernames, passwords, contact
details, AI API keys, prompt contents, or audit log contents.

**How to turn it off.** Two ways, and either is enough:

- In the UI, as an admin: open Settings, then Telemetry, and switch off
  "Anonymous usage statistics (this installation)". The choice is stored in
  the database and takes effect immediately.
- In the environment, which is the right choice for fleet or automated
  deployments:

  ```
  NETMAPPER_TELEMETRY_ENABLED=false
  ```

  Restart the backend afterwards. The environment variable always wins over
  the UI switch, and the UI then shows the switch as locked.

You can also keep the ping but send it to yourself, by pointing
`NETMAPPER_TELEMETRY_URL` at an endpoint you control. The payload is a JSON
POST with exactly the fields above.

The install UUID lives in the `system_settings` table under
`telemetry_install_id`. Deleting that row makes NETMapper generate a new UUID
on the next start, with no association between the old and new values.

### Crash reporting, off by default

Sentry crash reporting stays off unless you set `NETMAPPER_SENTRY_DSN` to a
Sentry project you own. When it is set, unhandled exceptions from the backend
and the frontend are forwarded there, along with the user-agent string, the
NETMapper version and the URL path that failed.

Scrubbed before anything is sent: all HTTP request and response bodies, all
environment variables (including `NETMAPPER_ENCRYPTION_KEY`,
`NETMAPPER_JWT_SECRET` and any `*_PASSWORD` or `*_TOKEN` variable), switch SSH
credentials and switch IP addresses, AI provider API keys, and
notification-channel secrets such as SMTP passwords, webhook URLs and bot
tokens.

The Sentry project, its retention policy and its team access are entirely
yours. The NETMapper maintainers hold no copy of it.

### The AI assistant

The assistant is read-only and its tool use is gated to a fixed whitelist:
`list_devices`, `list_switches`, `list_neighbors`, `list_alerts` and
`stats_summary`. It cannot change anything. It talks to whichever
OpenAI-compatible provider you configure, including a local one such as
Ollama, so you decide whether any prompt leaves your network at all. Provider
keys are encrypted at rest.

The full privacy policy is in
[PRIVACY.md](https://github.com/NX1X/NETMapper/blob/main/PRIVACY.md). For
privacy questions, use the [contact form](https://nx1xlab.dev/contact) with
the subject prefix `[PRIVACY]`.
