Security

Security policy

SnmpLens handles credentials for network equipment. That deserves a page saying exactly what it does with them and how to tell us when it gets it wrong.

Reporting a vulnerability

Please do not open a public issue for a security problem.

Use GitHub's private vulnerability reporting on the repository — Security → Report a vulnerability. It creates a private thread visible only to the maintainers.

What helps:

This is a project maintained in someone's own time, so please do not expect a same-day answer. Reports are acknowledged, and a fix ships in a release with the problem described in its notes.

Supported versions

Fixes go into the next release from main. There are no long-term support branches; the application updates itself, and the answer to “am I affected” is normally “update”.


What the application does

Credentials

Community strings, v3 passphrases, SMTP passwords, webhook tokens and syslog client keys are held by the operating system's own protection: DPAPI on Windows, the Keychain on macOS, a file readable only by your account on Linux. They are not stored beside the database, and the settings screen names the backend in use rather than saying “encrypted”, because those three defend against different things.

Be precise about what that buys: DPAPI and the Keychain tie the key to your account, while the Linux file keeps it away from other accounts and out of a copied profile, and nothing more. While the application runs, credentials are in its memory in the clear — every request builder needs them.

What is never written down

Transport

Content that arrives from the network

A trap is unauthenticated and its values end up in rendered messages. Anything written into a protocol where a character changes meaning is escaped: dot-stuffing for SMTP data per RFC 5321, header encoding that turns a newline into an escape rather than a new header, and sanitising for the RFC 5424 syslog header. Values substituted into a template are never re-scanned, so a trap OID that reads like a placeholder stays text. Exported CSV neutralises a cell a spreadsheet would run as a formula — one beginning with =, +, - or @ — since a device's own description can begin that way.

Dashboard presets

A preset is a file somebody else wrote, and binding one makes SnmpLens send SNMP requests to your equipment. So a preset picks from a fixed vocabulary instead of describing anything: widget kinds and map shapes the application owns, numeric OIDs only, and a bound on every list and string. It cannot carry markup — maps are drawn from four shapes, never from SVG — and it cannot carry a path or an image: a map background is a file name resolved inside your own backgrounds folder, and an image gets into that folder only if it decodes as PNG, JPEG or GIF with sane dimensions. Before a preset is bound, the library states what it will cost and whether it can raise an incident.

The simulator

Simulated devices answer on a loopback address only — 127.0.0.0/8 or ::1. That is enforced by the backend, not by the form: an address is refused when a device is saved, a host name is never resolved (localhost excepted), and the socket a device actually bound is checked again before it answers, because an address left empty binds every interface. A bench file somebody else wrote is held to the same rule. Where a device sends notifications is not restricted, so what is bounded there is the rate: a refused request is a datagram anything on the machine can send, and a device sends twenty notifications a second at most, and an authenticationFailure about once a second.

A simulated device's communities and passphrases are kept in the credential store, never in simulator.json, and a bench file carries them only when you say so at export — the file then says that it does. Recording a real device never writes that device's own SNMP subtree: its user names, its access groups and its community table stay out of the package.

Releases

Each release carries a SHA-256 manifest and an Ed25519 signature over it. The application verifies the signature against a key compiled into the binary before it trusts the manifest, and a build whose signature is missing refuses the update rather than applying it. See verifying a download.

Privileges

SnmpLens does not ask for elevation and does not need it. Ping and traceroute are pure Go rather than wrapped system tools, autostart is a per-user login entry and never machine-wide, and a trap listener on a port below 1024 will simply fail rather than prompt.

In the repository

CodeQL runs over the Go and frontend code on every push and weekly — weekly as well, because a query added after a commit landed would otherwise never see it. Dependencies are reviewed on pull requests, scanned with govulncheck and npm audit, and pinned by commit SHA with automated updates, since pinning without something to move the pins just freezes them.


Scope

These are known and are not vulnerabilities: