Vulnerability: Maintainer can bypass exit game quarantine by registering not-yet-deployed contracts
Severity: medium

Description:
The plasma framework uses an `ExitGameRegistry` to allow the maintainer to add new exit games after deployment. An exit game is any arbitrary contract. In order to prevent the maintainer from adding malicious exit games that steal user funds, the framework uses a “quarantine” system whereby newly-registered exit games have restricted permissions until their quarantine period has expired. The quarantine period is by default `3 * minExitPeriod`, and is intended to facilitate auditing of the new exit game's functionality by the plasma users.\\nHowever, by registering an exit game at a contract which has not yet been deployed, the maintainer can prevent plasma users from auditing the game until the quarantine period has expired. After the quarantine period has expired, the maintainer can deploy the malicious exit game and immediately steal funds.\\nExplanation\\nExit games are registered in the following function, callable only by the plasma contract maintainer:\\n```\\n/\\*\\*\\n \\* @notice Registers an exit game within the PlasmaFramework. Only the maintainer can call the function.\\n \\* @dev Emits ExitGameRegistered event to notify clients\\n \\* @param \\_txType The tx type where the exit game wants to register\\n \\* @param \\_contract Address of the exit game contract\\n \\* @param \\_protocol The transaction protocol, either 1 for MVP or 2 for MoreVP\\n \\*/\\nfunction registerExitGame(uint256 \\_txType, address \\_contract, uint8 \\_protocol) public onlyFrom(getMaintainer()) {\\n    require(\\_txType != 0, "Should not register with tx type 0");\\n    require(\\_contract != address(0), "Should not register with an empty exit game address");\\n    require(\\_exitGames[\\_txType] == address(0), "The tx type is already registered");\\n    require(\\_exitGameToTxType[\\_contract] == 0, "The exit game contract is already registered");\\n    require(Protocol.isValidProtocol(\\_protocol), "Invalid protocol value");\\n\\n    \\_exitGames[\\_txType] = \\_contract;\\n    \\_exitGameToTxType[\\_contract] = \\_txType;\\n    \\_protocols[\\_txType] = \\_protocol;\\n    \\_exitGameQuarantine.quarantine(\\_contract);\\n\\n    emit ExitGameRegistered(\\_txType, \\_contract, \\_protocol);\\n}\\n```\\n\\nNotably, the function does not check the `extcodesize` of the submitted contract. As such, the maintainer can submit the address of a contract which does not yet exist and is not auditable.\\nAfter at least `3 * minExitPeriod` seconds pass, the submitted contract now has full permissions as a registered exit game and can pass all checks using the `onlyFromNonQuarantinedExitGame` modifier:\\n```\\n/\\*\\*\\n \\* @notice A modifier to verify that the call is from a non-quarantined exit game\\n \\*/\\nmodifier onlyFromNonQuarantinedExitGame() {\\n    require(\\_exitGameToTxType[msg.sender] != 0, "The call is not from a registered exit game contract");\\n    require(!\\_exitGameQuarantine.isQuarantined(msg.sender), "ExitGame is quarantined");\\n    \\_;\\n}\\n```\\n\\nAdditionally, the submitted contract passes checks made by external contracts using the `isExitGameSafeToUse` function:\\n```\\n/\\*\\*\\n \\* @notice Checks whether the contract is safe to use and is not under quarantine\\n \\* @dev Exposes information about exit games quarantine\\n \\* @param \\_contract Address of the exit game contract\\n \\* @return boolean Whether the contract is safe to use and is not under quarantine\\n \\*/\\nfunction isExitGameSafeToUse(address \\_contract) public view returns (bool) {\\n    return \\_exitGameToTxType[\\_contract] != 0 && !\\_exitGameQuarantine.isQuarantined(\\_contract);\\n}\\n```\\n\\nThese permissions allow a registered quarantine to:\\nWithdraw any users' tokens from ERC20Vault:\\n```\\nfunction withdraw(address payable receiver, address token, uint256 amount) external onlyFromNonQuarantinedExitGame {\\n    IERC20(token).safeTransfer(receiver, amount);\\n    emit Erc20Withdrawn(receiver, token, amount);\\n}\\n```\\n\\nWithdraw any users' ETH from EthVault:\\n```\\nfunction withdraw(address payable receiver, uint256 amount) external onlyFromNonQuarantinedExitGame {\\n    // we do not want to block exit queue if transfer is unucessful\\n    // solhint-disable-next-line avoid-call-value\\n    (bool success, ) = receiver.call.value(amount)("");\\n    if (success) {\\n        emit EthWithdrawn(receiver, amount);\\n    } else {\\n        emit WithdrawFailed(receiver, amount);\\n    }\\n```\\n\\nActivate and deactivate the `ExitGameController` reentrancy mutex:\\n```\\nfunction activateNonReentrant() external onlyFromNonQuarantinedExitGame() {\\n    require(!mutex, "Reentrant call");\\n    mutex = true;\\n}\\n```\\n\\n```\\nfunction deactivateNonReentrant() external onlyFromNonQuarantinedExitGame() {\\n    require(mutex, "Not locked");\\n    mutex = false;\\n}\\n```\\n\\n`enqueue` arbitrary exits:\\n```\\nfunction enqueue(\\n    uint256 vaultId,\\n    address token,\\n    uint64 exitableAt,\\n    TxPosLib.TxPos calldata txPos,\\n    uint160 exitId,\\n    IExitProcessor exitProcessor\\n)\\n    external\\n    onlyFromNonQuarantinedExitGame\\n    returns (uint256)\\n{\\n    bytes32 key = exitQueueKey(vaultId, token);\\n    require(hasExitQueue(key), "The queue for the (vaultId, token) pair is not yet added to the Plasma framework");\\n    PriorityQueue queue = exitsQueues[key];\\n\\n    uint256 priority = ExitPriority.computePriority(exitableAt, txPos, exitId);\\n\\n    queue.insert(priority);\\n    delegations[priority] = exitProcessor;\\n\\n    emit ExitQueued(exitId, priority);\\n    return priority;\\n}\\n```\\n\\nFlag outputs as “spent”:\\n```\\nfunction flagOutputSpent(bytes32 \\_outputId) external onlyFromNonQuarantinedExitGame {\\n    require(\\_outputId != bytes32(""), "Should not flag with empty outputId");\\n    isOutputSpent[\\_outputId] = true;\\n}\\n```\\n

Impact:

Recommended mitigation:
`registerExitGame` should check that `extcodesize` of the submitted contract is non-zero.\\nCorresponding issue in plasma-contracts repo: https://github.com/omisego/plasma-contracts/issues/410