Openzeppelin EIP-3009

I'm wondering what attack scenarios transparent proxies solve. assume the following , very simple proxy contract:

contract Proxy {
    address public proxyOwner;
    address public implementation;

    constructor(address implementation) public {
        proxyOwner = msg.sender;
        implementation = imp;

    modifier onlyProxyOwner() {
        require(msg.sender == proxyOwner);

    function upgrade(address implementation) external onlyProxyOwner {
        implementation = imp;

    function () payable external {
        address impl = implementation;

        assembly {
            calldatacopy(0, 0, calldatasize)
            let result := delegatecall(gas, impl, 0, calldatasize, 0, 0)
            returndatacopy(0, 0, returndatasize)

            switch result
            case 0 { revert(0, returndatasize) }
            default { return(0, returndatasize) }

This doesn't implement transparent proxy. Ok, can you tell now what attack could happen ? but first, hear me out.

ok, it's possible that in the logic and proxy contracts, function selector clashing happens. If non-admin user calls a function(intended to call on proxy), but the proxy contains the same function selector, ok, proxy's function will be called, but since proxy functions are protected by admin modifiers, user's call fails. so no attack here.

if admin intends to call a implementation function and selector matches the proxy's one, proxy's function will be called and modifier would allow him to do it. This could be dangerous if admin was calling such a function that matches "upgrade" selector. Ok, I see the attack here. BUT, BUT, BUT. how does the transparent proxy solve this ? I mean, even in transparent proxy, if admin calls a function, let's say blabla(address) that matches the upgrade(address), it will still be proxy's upgrade that will be called and danger happened as well.

In latest version of OZ, you guys use proxyAdmin and that case wouldn't happen, but even in v4.x, you didn't have proxyAdmin contract separately and you were still happy with transparent proxy, solving attack problems.

What are the actual attacks that transparent proxies solve ? I mean "attacks" and not just uncomfortable scenarios where tx fails or whatever.

I am already familiar with malicious proxy contracts itself that add one more specific function to ensure the clashing, so please, no need to mention this in the discussion to not waste time.

As far as I know, the goal here wasn't to prevent a specific attack (or at least it wasn't the only goal).

The goal is to allow implementing two functions of the same prototype in both the proxy contract and the logic contract (in other words, allow what you refer to as "function selector clashing").

Whenever that function is called, the one in the proxy contract gets executed, regardless of what the caller has intended (there's no other option, since this function exists in the proxy contract).

However, it is the author's responsibility to implement inside that function something like:

  • Continue if msg.sender is the admin account
  • Fallback if msg.sender is not the admin account

And the second case will forward the execution from the proxy contract to the logic contract in the same way that every call to a function which is not implemented in the proxy contract is forwarded to the logic contract.

Not a direct answer to your question of course, just pointing out an aspect which you may have overlooked (in OZ's implementation and/or in your alternative implementation).

1 Like