Skip to the content.

← All documentation · English | 繁體中文

Security scan results

The toolchain document describes what should be run. This is what was run, and what it found.

A report of counts alone is not worth submitting. Every finding below carries a verdict and the reasoning for it, because the question a reviewer actually has is not “how many” but “why is each one acceptable”.

   
Date 2026-08-27
Version jt-snmpd 1.1.3
Scope deploy/, tools/, packaging/ — 14 files, 4,967 lines

Summary

Check Tool Result
Static analysis (SAST) Bandit 1.9.4 HIGH 0, MEDIUM 3, LOW 12 — all accounted for below
Dependency vulnerabilities (SCA) pip-audit 2.10.1 0 across 70 packages
Personal data and secrets tools/check-privacy.py HIGH 0 — runs on every push
Test suite pytest 963 passed, 1 skipped — runs on every push
Installer artefact checks Windows Installer tables 5 checks — run on every push

The runtime dependency surface is two packages. pysnmp 7.1.29, which requires pyasn1 0.6.4, which requires nothing. Everything else in the 70 is build or test tooling that never reaches a customer machine. That is deliberate: the fewer dependencies, the shorter this section stays.


Static analysis: every finding

Bandit reports no HIGH findings. The fifteen below are MEDIUM and LOW, and each one is either a false positive or a documented decision.

The SNMPv3 code added none of them. deploy/usm.py — key localization, the DPAPI-protected store, the algorithm allowlist — is the newest file and the one handling secrets, and it is clean. That is worth stating rather than leaving to be inferred from a total.

B104 — “possible binding to all interfaces” (MEDIUM ×3)

Location Verdict
deploy/jt_agent.py:3441, :3716 Accepted, by design. The agent binds 0.0.0.0 deliberately. A bind address does not filter senders; it only chooses which local addresses receive. Source restriction is enforced twice over and in the right places: the Windows Firewall rule is scoped to the management networks, and the pre-parse gate checks the source address before pysnmp sees a byte. Binding a single address would break multi-homed hosts and would add no security. See Security assessment §1.
tools/check-privacy.py:163 False positive. "0.0.0.0" appears in a list of addresses the IP rule excludes, so that wildcards are not reported as leaks.

B105 — “possible hardcoded password” (LOW ×2)

deploy/diskhealth.py:314 and :317. False positive. The values are the booleans in {"health_pass": True}. Bandit’s heuristic matches any name containing pass, and health_pass is a SMART result, not a credential.

B110 / B112 — try/except pass, try/except continue (LOW ×3)

Location Verdict
deploy/jt_agent.py:220 Accepted. Writing to the Windows Event Log can fail on permissions or an unregistered source. A monitoring agent that dies because it could not log an error is worse than one that carries on; the same message is already written to the log file.
deploy/jt_agent.py:1613 Accepted. The last resort inside an already-failed path: reading the engine identity threw, the outer handler has logged why, and this is the second attempt at the machine GUID. Failing here leaves "unknown", which produces a volatile engine ID — worse than a stable one, and far better than no agent.
deploy/diskhealth.py:413 Accepted. A disk that does not answer a SMART command is skipped rather than fabricated. One unresponsive USB bridge must not remove every other disk from the snapshot.

All three are narrow, each catches a specific expected failure, and each carries a comment saying why.

B404 / B603 / B607 — subprocess use (LOW ×7)

tools/check-privacy.py, tools/prepare-public-repo.py and tools/check-terminology.py call git to list the tracked files. Accepted. All three pass a fixed argument vector with no shell and no user-supplied input, and none of them ships to a customer machine: they are repository tooling. B607 is the same call flagged again for naming git rather than an absolute path. The agent itself starts no subprocess at all, which is a project rule.


Dependency vulnerabilities

pip-audit found no known vulnerabilities across 70 installed packages, checked against the PyPI Advisory Database and OSV.

Worth separating, because 70 overstates the exposure:

  Packages Reaches a customer machine
Runtime pysnmp, pyasn1 Yes, inside the MSI
Packaging pyinstaller, pywin32 Their output does; they do not
Testing and tooling The rest No

What is not yet run

Stating this plainly is part of the report. The toolchain document lists more than has actually been executed:

Item State
Semgrep, including the project-specific rules Not run
gitleaks over the full history Not run
CycloneDX SBOM Generated once; not refreshed on a schedule
24-hour boofuzz against UDP/161 Not run
PROTOS c06-snmpv1 Not run
Windows platform checks (signtool, accesschk, PrivescCheck) Not run as a batch; sc qprivs verified by hand
HVCI / WDAC endpoint survival Blocked; no such endpoint available

None of these are blocked on effort except the last. They are listed so nobody reads the toolchain document and assumes all of it has happened.


Reproducing this

pip install bandit pip-audit
bandit -r deploy/ tools/ packaging/ -f json -o reports/bandit.json
pip-audit --format json -o reports/pip-audit.json
python3 tools/check-privacy.py
python3 -m pytest tests/ -q

reports/ is not published: the raw JSON carries local filesystem paths. This page is the submittable form.