Automated review finding for PR #167 — "Security audit follow-up: install-directory ACL, log redaction, pre-auth limits, SignalR scoping, HSTS ordering"
Author: @Sev7eNup · Status: merged
The PR is otherwise strong: the other four fixes (H-18 install-dir ACL, M-31 scheduler log redaction, M-33 SignalR subscription eviction on workflow/folder move, L-17 HSTS/forwarded-headers ordering) are correct, coherent, and each ships accompanying tests (9 backend tests + 12 PowerShell template assertions). No new API endpoints (no CLI/MCP client obligation); the only new user-visible strings are backend English BadRequest messages, consistent with existing API messages; docs updated in step. One finding rises to medium:
This is an automated PR-review finding and needs triage. Low-severity notes, if any, are intentionally omitted.
Automated review finding for PR #167 — "Security audit follow-up: install-directory ACL, log redaction, pre-auth limits, SignalR scoping, HSTS ordering"
Author: @Sev7eNup · Status: merged
The PR is otherwise strong: the other four fixes (H-18 install-dir ACL, M-31 scheduler log redaction, M-33 SignalR subscription eviction on workflow/folder move, L-17 HSTS/forwarded-headers ordering) are correct, coherent, and each ships accompanying tests (9 backend tests + 12 PowerShell template assertions). No new API endpoints (no CLI/MCP client obligation); the only new user-visible strings are backend English
BadRequestmessages, consistent with existing API messages; docs updated in step. One finding rises to medium:src/NodePilot.Api/Controllers/AuthController.cs:327-337(finding M-32) — The newinvalidPasswordgate rejects any login whereUTF8.GetByteCount(password) > MaxPasswordBytes (72)and runs at the very top ofLogin(), beforeTryLdapLoginAsync(which binds with the raw password viaLdapAuthenticator.AuthenticateAsync). The inline comment justifies the cap by "every password-setting path already runsValidatePasswordPolicy, which caps atMaxPasswordBytes" — but that premise only holds for local BCrypt accounts. For LDAP/AD the password lives in the directory, NodePilot never governs it, BCrypt's 72-byte truncation never applies, and AD permits passwords up to 256 chars. An AD user with a passphrase longer than 72 bytes (~72 ASCII chars, i.e. a ~12-word passphrase — plausible exactly in the security-conscious orgs that deploy LDAP SSO) now gets a generic 401 with audit reasoninvalid_password_lengthand never reaches the bind. The added testOverlongPassword_IsRejectedBeforeLdapOrThrottleWorkpins this short-circuit, so the regression is intentional but the reasoning is incomplete for the LDAP path. Suggestion: apply the strict 72-byte reject only on the local-BCrypt branch (after the LDAP fall-through), or raise the pre-LDAP cap to the AD maximum (e.g. 256 bytes). The[RequestSizeLimit(8 KiB)]already on the endpoint removes the multi-megabyte DoS amplifier, so the tight 72-byte gate buys almost no additional abuse protection while introducing the lockout.This is an automated PR-review finding and needs triage. Low-severity notes, if any, are intentionally omitted.