NETMapper security and privacy

The security posture, how to report a vulnerability, and exactly what telemetry sends.

View raw Markdown

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.

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.

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. For privacy questions, use the contact form with the subject prefix [PRIVACY].