50916 sc high token creators can bypass factory upgrade controls via wrong code implementation of default admin role in arctokenfactory sol

Submitted on Jul 29th 2025 at 17:17:21 UTC by @demonhat for Attackathon | Plume Network

  • Report ID: #50916

  • Report Type: Smart Contract

  • Report severity: High

  • Target: https://github.com/immunefi-team/attackathon-plume-network/blob/main/arc/src/ArcTokenFactory.sol

  • Impacts: Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield


Description

Brief / Intro

In the ArcTokenFactory.sol contract, the createToken() implementation grants DEFAULT_ADMIN_ROLE to the token creator (the msg.sender of createToken) instead of keeping the factory as the default admin. That is:

// Grant all necessary roles to the owner
// Grant the DEFAULT_ADMIN_ROLE to the deployer <--------
token.grantRole(token.DEFAULT_ADMIN_ROLE(), msg.sender); //issue! not following the comment, this grants the highest role to the Token creator!
token.grantRole(token.ADMIN_ROLE(), msg.sender);
token.grantRole(token.MANAGER_ROLE(), msg.sender);
token.grantRole(token.YIELD_MANAGER_ROLE(), msg.sender);
token.grantRole(token.YIELD_DISTRIBUTOR_ROLE(), msg.sender);
token.grantRole(token.MINTER_ROLE(), msg.sender);
token.grantRole(token.BURNER_ROLE(), msg.sender);
token.grantRole(token.UPGRADER_ROLE(), address(this));

Because DEFAULT_ADMIN_ROLE is the highest privileged role in an AccessControl setup, token creators who receive it can grant themselves any other role (including UPGRADER_ROLE) and then call upgrade functions on the token proxy directly to replace the implementation with malicious code. This completely bypasses the factory's intended upgrade controls (which are supposed to be enforced by the factory's own upgradeToken() function).

High-level impact

  • Token creators can grant themselves UPGRADER_ROLE and call the proxy's upgradeToAndCall() to replace the implementation with malicious implementations that steal funds or freeze transfers.

  • The factory's upgradeToken() security checks (only callable by factory admins, whitelist checks, tracking) are bypassed by direct proxy upgrades from the token creator.

  • Once malicious implementation is installed, factory admins cannot recover control; funds are at risk permanently for the affected token(s).


Vulnerability Details

  • Root cause: Excessive (and incorrect) role granting — granting DEFAULT_ADMIN_ROLE to token creators during creation rather than to the factory itself.

  • Example problematic line (ArcTokenFactory.sol):

  • Bypass mechanism:

    • Creator grants self UPGRADER_ROLE (because they hold DEFAULT_ADMIN_ROLE).

    • Creator calls proxy upgrade directly:

    • This replaces proxy implementation with malicious code (examples below) that can steal transfers or freeze user transfers while allowing attacker to bypass restrictions.

  • Malicious implementation technique:

    • Implementations can hardcode an attacker address so they don't rely on preserved storage layout when used as an implementation, e.g.:

    • Hardcoded attacker addresses and overriding core logic leads to reliable theft even when storage/layout differs.


Complete Factory Invariant Bypass

Factory intended invariants:

  • Only factory admins can upgrade tokens.

  • Only whitelisted implementations can be used.

  • Factory maintains control over token upgrades.

Attack breaks all invariants:

  • Creator can upgrade without factory permission.

  • Malicious implementations bypass whitelist checks.

  • Factory loses authoritative control and tracking of final implementation.


Impact Details

  • Direct Fund Theft: demonstrated in PoC below — transfers redirected to attacker.

  • Permanent Control: malicious creator retains upgrade ability and can deploy multiple malicious implementations.

  • Multiple attack vectors: complete theft, transfer freeze, overriding factory upgrades.

  • Recovery: impossible for factory admins once malicious implementation is installed.

  • Scope: all tokens created by malicious creators via this factory pattern.

  • Estimated loss potential: potentially total TVL of tokens created by malicious creators (e.g., $1M TVL could be fully stolen).


References

  • ArcTokenFactory.sol: lines granting DEFAULT_ADMIN_ROLE to creator (approx lines 192-193 in referenced file).

  • ArcTokenFactory.sol: upgradeToken function (approx lines 260-285) showing factory-side checks that are bypassable by direct upgrades.


Proof of Concept

Below is the POC test (Forge-style) submitted. It demonstrates creation of a token by a malicious creator, the granting of upgrade privileges, direct upgrade to malicious implementations, and theft/freeze behaviors.

Do not modify — original PoC code preserved:


FIX

Correct behavior: grant DEFAULT_ADMIN_ROLE to the factory contract (so the factory retains the highest privilege) and keep UPGRADER_ROLE and other operational roles consistent with factory control.

Suggested minimal code change in ArcTokenFactory.sol:


If you want, I can:

  • create a minimal patch/PR diff for ArcTokenFactory.sol showing the exact change(s) and locations, or

  • statically analyze ArcTokenFactory.sol to confirm the exact line numbers and produce a suggested commit.

Was this helpful?