master · main · *_release · release/*
thresholdsseverity ≥ minor · confidence ≥ medium · cap 12
max diff0.4 MB
pollevery 300s
SSH one-time-password PAM gatekeeper (Linux C): a pam_ninja.so module in sshd's auth stack validates a time-based OTP (timestamp + SHA-256 over timestamp+shared secret, short TTL) to gate SSH reverse-tunnel access to Ninja infra; ships client OTP generators + tunnel scripts. Auth gate — a weakness is an SSH auth bypass.
A small Linux C security component that gates SSH (reverse-)tunnel access to Ninja
infrastructure with a time-based one-time password. A PAM module (pam_ninja.so) is loaded
into sshd's auth stack on the server; client-side generators mint the OTP and a thin script
opens the SSH tunnel. The whole thing is an authentication gatekeeper — a weakness here is an
SSH auth bypass, i.e. potential remote access to the host.
pam_sm_authenticate et al.).It reads a shared secret from a keyfile (path passed as a module argument in the PAM
stack), takes the presented password, and validates a time-stamped digest OTP: a
timestamp concatenated with a SHA-256 digest computed over timestamp + secret. It recomputes
the digest, compares, and checks the embedded timestamp falls inside a short TTL window
(freshness / replay defence). A debug/skew allowance may widen that window.
timestamp || SHA-256(timestamp+secret)with a few-seconds TTL — the value a client feeds as the SSH password.
tunnel** (ssh -R … -N) as a locked-down, shell-less tun user.
etc/): where pam_ninja.so sits in sshd's auth stack(relative to pam_unix, pam_deny, pam_permit) and how sshd is wired to use it. The stack
ordering is the security policy — reordering changes what authenticates.
anonymous client) is parsed and compared before access is granted. Scrutinize: digest
recomputation, constant-time comparison of the secret-derived digest, timestamp parsing,
and the TTL / replay window (too wide, or a debug allowance left on in prod, weakens it).
secret that reaches logs, world-readable key material, or a weak/hardcoded key is a critical
finding. Client and server must derive from the same secret and scheme.
strncpy/sprintf/strtoll-style parsing of attacker-controlled input — classic
buffer-overflow / off-by-one / missing-NUL / format-string territory. A parsing bug on the
pre-auth path is remotely reachable.
the timestamp at non-debug levels leaks material into syslog — treat as security-sensitive.
PAM_SUCCESS (or the wrong code) on an error/edgepath is an auth bypass; every failure path must deny. Control-flow that can fall through to
"allow" is the highest-severity class here.
The pam_sm_authenticate OTP parse + verify path; keyfile/secret loading; the timestamp/TTL
freshness check; the client generators (must match the verifier's scheme); and the PAM-stack
ordering in etc/.
ordering (timestamp + secret), digest algorithm, and the TTL must stay in lockstep between the
generators and the module — a change on one side breaks authentication (or, worse, weakens it).
Readme) describe where themodule and secret live; a change to argument order or file paths is an operational break.
DEBUG/debug mode exists (extra logging + a wider time allowance) — **must never be thereviewed/shipped default**; flag debug artifacts on the auth path.
tun account is deliberately shell-less (/bin/false) and exists only to terminatetunnels — changes that grant it more capability are security-relevant.
is operational (who can SSH-tunnel into Ninja hosts), not code-level. Depends only on system
PAM headers + OpenSSL (SHA-256).
_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.