main · master · develop · release/* · *_release
thresholdsseverity ≥ minor · confidence ≥ medium · cap 12
max diff0.4 MB
pollevery 300s
AppSec SBOM-ingestion backend: ingests / scans (Grype/CVE) / stores / reports on SBOMs submitted by product build pipelines, tracks in-scope CVEs as Jira issues, notifies Slack/email, ingests SAST/SCA (QWiet). Python/Flask/SQLAlchemy/Postgres/Redis + esbuild web UI. Handles vulnerability data + many credentialed integrations.
NinjaOne's AppSec backend: it ingests, scans, stores, and reports on SBOMs (Software
Bills of Materials, CycloneDX/SPDX) submitted by the products' build pipelines, scans them for
CVEs with Grype, tracks in-scope vulnerabilities as Jira issues, and notifies via
Slack / email. Also ingests SAST/SCA findings (QWiet/ShiftLeft) and serves a web UI. A
security-sensitive service handling vulnerability data and many credentialed integrations —
review with a security lens.
Stack: Python 3.10 + Flask 3 + SQLAlchemy 2 (automap/DB reflection) + Alembic migrations;
PostgreSQL + Redis; Grype scanner; a vanilla-JS/esbuild frontend built into Flask static;
Poetry; Docker Compose (backend + postgres + redis + nginx/certbot). It reviews as a Python
repo (the small JS frontend is secondary — apply general judgment there).
web UI, integration webhooks/callbacks). SQLAlchemy models are **reflected from the live DB
(automap)** — so the DB schema and the code's assumptions about it must stay in lockstep.
scan (locally-cached vuln DB) → findings persisted → periodic auto-rescan, report,
SLO and roll-up generation.
roll-up, Jira delta-sync). Long-running work runs as tracked background tasks with logs.
(create/transition CVE issues), Slack + Microsoft Graph (notifications), QWiet/ShiftLeft
(SAST/SCA), AWS (boto3), ZAP (DAST).
findings are filed and who is notified — a data table that steers real outbound actions.
nginx fronts it (http/https profiles)..env).scripts submodule points at ninjarmm/toolbox (shared tooling).formats — malformed/oversized/malicious documents, zip/entity bombs, path traversal in file
handling, and resource exhaustion on parse are the highest-scrutiny area.
missing/incorrect auth check, a token that grants too much, or an unauthenticated ingest/admin
endpoint is a serious finding. Verify each new/changed route is gated.
AWS/QWiet — never logged, never returned in responses, scoped minimally. Flag any secret that
reaches logs, error bodies, or the UI.
text() SQL built from input,and outbound calls (SharePoint/Jira/HTTP) whose URL/host is influenced by untrusted data.
ordering, a migration that diverges from what the automap code expects, or one that locks a big
table. A bad migration is a production-data risk.
dedup, scope mapping, or SLO math mislabels real risk (false all-clear or false alarm). Scan
parsing, severity thresholds, and the mapping config deserve care.
(SharePoint / Jira / external APIs — the config deliberately keeps worker counts low), plus
concurrency on shared state. A task that double-files Jira issues or spams notifications is a
real bug.
partial state — a dropped CVE is a security miss, not just a glitch.
The SBOM/SAST ingest endpoints (untrusted parsing); auth/token verification on API + UI; the
credential-bearing integration clients (SharePoint/Jira/Slack/Graph/AWS/QWiet); the Grype
scan + CVE severity/dedup logic; the project/component/env→Jira/notification mapping; and the
Alembic migrations.
contract change can silently drop incoming SBOMs.
migrations must apply cleanly and in order on existing production data.
and the env-var config contract (Compose defaults) that operators rely on.
email recipients, Jira projects).
pyproject.toml + poetry.lock — keep the lock in sync); the JSfrontend is bundled with esbuild into the Flask static dir at image build.
UTC hours and 0 disables them. Secrets live only in .env — never commit or log them.
Grype. This repo has its OWN CLAUDE.md — consult it (and README.md) for current specifics.
_Orientation only — verify current specifics in the code; this describes durable architecture &
risk areas, not a snapshot._
How the monitored repos relate — so a change in one repo is reviewed with its blast
radius in mind (a change upstream of ncpeer can break ncpeer even if it looks local).
Orientation only; verify specifics in code.
speak the NCRP wire protocol (protocol/format changes must stay compatible across
client and server versions).
URLs, it pairs them and forwards frames verbatim. Signed join URLs are minted by the
Ninja backend — the signature scheme is a backend⇄relay contract, and the frame
semantics are a peer⇄peer contract.
a signed upload leg streams to a signed download leg through memory (never stored).
Two parallel implementations (Python ftsv2/ + Go fts_go/) must stay behaviorally
identical; the URL/signature scheme is shared-family with websocket-switch.
NinjaRemote file-transfer features ride on these relays when peers can't go direct.
or behaviour change here affects both consumers.
build against**. A dependency bump changes what those products link (security/ABI/build).
through the ncpeer_vcpkg overlay.
shares nccommon and ncpeer_vcpkg with ncpeer.
part of the remote-desktop family). Runs as a child process of the NinjaRMM agent (the
parent owns install/upgrade/policy/launch); NinjaFlow owns the CLI contract, config schema,
credential precedence, DB schema/migrations, and exit-code meanings the parent consumes —
those are cross-process contracts. Submits telemetry to the Ninja Backend. Shares no code with
ncpeer/nmsnj; adjacent to nmsnj only in domain (network), not in implementation.
not part of any product's build. It consumes the SBOMs the other products' pipelines emit
(Ninja-Remote/ncpeer, NMS/nmsnj, NinjaFlow all appear in its scope maps), scans them for CVEs
and files Jira issues — a downstream *security-scanning* relationship, not a code dependency.
Shares no code with the others; has its own DB/schema and a toolbox submodule.
authentication component: its pam_ninja.so gates SSH reverse-tunnel access into
Ninja infrastructure with a time-based OTP. Shares no code with the other repos; its
blast radius is operational (who can SSH-tunnel into hosts), not code-level. The client OTP
generators and the module must agree on the OTP scheme + shared secret.
these are *upstream* of ncpeer (and nccommon/vcpkg also of nmsnj) — weigh the consumer
side: API/ABI compatibility, build impact, and cross-platform reach.
contract.