I think your design is missing a mechanism to initialize the memory state of the proxy when the logic contract is updated.
updateCodeAddress must include much more then just updating the targeted logic. It potentially needs to reset the memory state of the proxy and configure the new logic. An exmaple is that, if you have an identity proxy that is a simple ownable contract, and you want to update it to a multisig, you should cleanup the owner and set up the multisig persmissions in a single transaction when updating the logic. This is why I include semantics for initilization function, and pass bytes to describe initialization operation.
Without that I’m afraid updating security policy will be either insecure of non user friendly