Submitted by monrel, also found by josephdara, Shield, and t0x1c
https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/bridge/Bridge.sol#L82-L95 
https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/bridge/Bridge.sol#L230-L231
The bridge_watchdog role can forge arbitrary messages and drain the bridge of all ETH and tokens.
bridge_watchdog can call suspendMessasges() to suspend and un-suspend a message
https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/bridge/Bridge.sol#L82-L95
When this function is called to un-suspend a message we set proofReceipt[msgHash] = _timestamp. If the msgHash was not proven before it will now be treated as proven since any msgHash with a timestamp != 0 is treated as proven
https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/bridge/Bridge.sol#L230-L231
bridge_watchdog can therefore forge arbitrary messages and have them treated as proven by first suspending them and then un-suspending them.
bride_watchdog is supposed to only be able to ban and suspend messages, in the expected worst case bridge_watchdog is limited to DDOSing messages and bans until governance removes the the bridge_watchdog.
With the privilege escalation shown here the role can instead drain the bridge of all ETH and tokens.
Here is a POC showing that we can forge an arbitrary message by suspending and un-suspending a message
To run this POC first change the following code in Bridge.t.sol so that we use a real signalService
Paste the below code and run into Bridge.t.sol and run forge test --match-test testWatchdogDrain -vvv
Foundry, VScode
Un-suspended messages should be set to 0 and be proven or re-proven.
dantaik (Taiko) confirmed and commented:
0xean (Judge) decreased severity to Medium and commented:
Note: For full discussion, see here.
