Skip to content

Fix the on-chain role-eligibility resolver checking the wrong account #171

Closed

Description

@Lakes41

Difficulty: Advanced
Type: Bug / Security

Background: resolveChainRoleEligibility() in src/features/access/roleEligibilityResolver.ts receives a walletAddress parameter (the connected wallet whose role membership is being checked) and passes it through to buildRoleRequirementCallData — except it doesn't: buildRoleRequirementCallData(requirement: AccessRequirement) takes only the requirement, and internally builds the ABI call-data's hasRole(bytes32,address) second argument (addr) from requirement.address — the role/access-control contract's own address — not from the walletAddress parameter that resolveChainRoleEligibility receives but never forwards into the call-data builder at all.

Problem: The resulting eth_call effectively asks the contract "does this contract's own address hold this role" instead of "does the connected wallet hold this role" — the on-chain fallback path for multi-chain role eligibility is checking the wrong account on every single invocation. Depending on the target contract's own role assignments, this can produce either false negatives (a legitimate role-holder is reported as ineligible on this fallback path) or, in principle, false positives if the contract address itself happens to satisfy hasRole for reasons unrelated to the user — either way, the fallback resolver's output cannot be trusted for any wallet today.

Expected outcome: buildRoleRequirementCallData (or its caller) correctly encodes the connected wallet's address as the hasRole(bytes32,address) account argument, and the resolver's output accurately reflects the connected wallet's on-chain role status.

Suggested implementation: Change buildRoleRequirementCallData(requirement: AccessRequirement, walletAddress: string) to accept the wallet address explicitly, validate it with the same /^0x[a-fA-F0-9]{40}$/ pattern currently applied to requirement.address, and encode that into the call data's second argument instead of requirement.address; update resolveChainRoleEligibility's call site to pass walletAddress through. Add a regression test asserting the encoded call data's second 32-byte argument matches the connected wallet, not the requirement's contract address.

Acceptance criteria:

  • A test constructs a hasRole call and asserts the ABI-encoded account argument equals the passed-in walletAddress, not requirement.address.
  • Existing tests in tests/ covering this resolver are updated to catch this class of regression (i.e., use a walletAddress and requirement.address that are deliberately different values, so the bug would have been caught).
  • No change to the resolver's public function signatures beyond what's needed to thread walletAddress through correctly.

Likely affected files: src/features/access/roleEligibilityResolver.ts, its test file(s).

Labels: bug, security, priority: high, GrantFox OSS, Maybe Rewarded, Official Campaign | FWC26

Activity

  1. added
    bugConfirmed defect or incorrect behavior that needs to be fixed
    Maybe RewardedIssue may qualify for a reward upon successful completion per campaign rules
    GrantFox OSSGrantFox Open Source Sponsorship program tag
    Official Campaign | FWC26Official FWC26 campaign issue — eligible for campaign scoring and rewards
    securitySecurity-related fix, hardening, audit, or vulnerability remediation
    on Jul 21, 2026
  2. grantfox-oss commented on Sep 14, 2026

    @grantfox-oss

    🎉 This issue has been marked as completed on GrantFox!

    @abojeEdwin's PR #301 was approved and merged by @Lakes41.

    🏆 @abojeEdwin: You earned 35 FoxPoints for this contribution! Your current tier: Explorer (468 total points). Track your full progress on GrantFox.

    👏 Great work, @abojeEdwin! Keep contributing to Adamantine-guild.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    GrantFox OSSGrantFox Open Source Sponsorship program tagMaybe RewardedIssue may qualify for a reward upon successful completion per campaign rulesOfficial Campaign | FWC26Official FWC26 campaign issue — eligible for campaign scoring and rewardsbugConfirmed defect or incorrect behavior that needs to be fixedpriority: highpriority: highsecuritySecurity-related fix, hardening, audit, or vulnerability remediation

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions