Skip to content

[contracts/identity] grant_role() is public with no auth check — any address can grant itself Admin #867

@Emeka000

Description

@Emeka000

Critical Security Bug

File: lifebank-soroban/contracts/identity/src/lib.rs (line 354)

Problem

IdentityContract::grant_role() is a pub function with no require_auth() call and no caller validation:

pub fn grant_role(env: Env, address: Address, role: Role) {
    let key = DataKey::AddressRoles(address.clone());
    // ... no auth check anywhere in this function
    env.storage().persistent().set(&key, &sorted);
}

Attack Scenario

Any Stellar address can call this function directly via the Stellar RPC:

stellar contract invoke --id <identity_contract> -- grant_role --address <attacker> --role Admin

After this call, the attacker holds the Admin role and can call verify_organization(), unverify_organization(), and award_badge() without restriction.

Impact

  • Complete role system bypass: any address can grant itself Admin, BloodBank, or Hospital roles
  • Attacker can verify fraudulent organizations or unverify legitimate ones on-chain
  • The permission scope system (PermissionScope::SettlementRelease, DisputeResolve) is also reachable through the role system

Fix

grant_role() must be restricted to admin-only and should be an internal helper, not a public entrypoint:

fn grant_role_internal(env: Env, address: Address, role: Role) { ... }

pub fn grant_role(env: Env, admin: Address, address: Address, role: Role) {
    admin.require_auth();
    Self::require_role(&env, &admin, Role::Admin)?;
    Self::grant_role_internal(env, address, role);
}

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions