# Access Control

> Detect missing or incorrect access control — missing modifiers, wrong role checks, privileged function exposure, public initializers, and role-escalation paths. Activate on any function that mutates state, transfers funds, mints tokens, sets admin parameters, upgrades implementations, or pauses/unpauses.

- **Type:** Skill
- **Install:** `agentstack add skill-omermaksutii-rugproof-access-control`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [omermaksutii](https://agentstack.voostack.com/s/omermaksutii)
- **Installs:** 1
- **Category:** [Security](https://agentstack.voostack.com/c/security)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [omermaksutii](https://github.com/omermaksutii)
- **Source:** https://github.com/omermaksutii/RugProof/tree/main/skills/access-control
- **Website:** https://omermaksutii.github.io/RugProof

## Install

```sh
agentstack add skill-omermaksutii-rugproof-access-control
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Access control detection

## When this applies

Any state-mutating function. In particular:

- Functions modifying balances, totalSupply, allowances, prices, fees
- `setOwner`, `transferOwnership`, `grantRole`, `setAdmin`, `setMinter`
- Upgrade pathways: `upgradeTo`, `_authorizeUpgrade`, proxy admins
- Pause/unpause, emergency-withdraw, sweep, recoverERC20
- Initializers (`initialize`, `__Init`, `_init`)
- Functions guarded only by `msg.sender == tx.origin` or address checks against a single static value
- Bridges, governors, vaults, anything with treasury

## Detection patterns

### Missing modifier (CRITICAL)
```solidity
function mint(address to, uint256 amount) external {
    _mint(to, amount);   // ← anyone can mint
}
```

### Wrong role check (HIGH)
```solidity
function setFee(uint256 fee) external {
    require(msg.sender == owner || hasRole(USER, msg.sender));   // ← USER role can set fee
    fee_ = fee;
}
```

### Initializer left public (CRITICAL)
```solidity
function initialize(address admin) public {     // ← no initializer guard, anyone can re-init
    _grantRole(DEFAULT_ADMIN_ROLE, admin);
}
```
**See also:** [[initialization]]

### tx.origin auth (HIGH)
```solidity
require(tx.origin == owner);   // ← phishable via intermediate contract
```

### Public privileged getter masking setter
Sometimes a setter is internal but a public wrapper exists with weak checks. Search for "alternate paths" to the same state slot.

### Role admin self-grant (HIGH)
`DEFAULT_ADMIN_ROLE` can grant itself any role. If the admin is an EOA, a single key compromises everything. Look for renounceable admin patterns or multi-sig requirements.

### `selfdestruct` reachable without ownership check (CRITICAL — but see [[selfdestruct-eip6780]])

### Sweep / recoverERC20 with no asset allowlist (MEDIUM-HIGH)
```solidity
function rescue(IERC20 token) external onlyOwner {
    token.transfer(owner, token.balanceOf(address(this)));  // ← sweeps any token incl. user deposits
}
```
Critical if it can sweep user deposits, Medium if only stuck airdrops.

## Severity rubric

| Pattern | Severity |
|---|---|
| Privileged mint/burn with no auth | **Critical** |
| Public `initialize` on a deployed proxy | **Critical** |
| Owner sweep that includes user deposits | **Critical** |
| Wrong role guards a sensitive op | **High** |
| `tx.origin` auth | **High** |
| Centralized single-key admin with no timelock | **High** *(see [[centralization-risk]])* |
| Renounced ownership but admin role retained | **Medium** |
| Missing zero-address check on role grant | **Low** |

## Remediation patterns

- Use `OwnableUpgradeable` / `AccessControlUpgradeable` from OZ — never roll your own.
- For each function: state the *one* role that should call it as a comment, then add the matching modifier.
- Initializers: `_disableInitializers()` in the constructor, `initializer` modifier on init.
- Multi-sig + timelock on `DEFAULT_ADMIN_ROLE`. Document the timelock duration.
- Two-step ownership transfer (`Ownable2Step`) to prevent locking out the contract.
- For sweeps: explicit allowlist of recoverable tokens, or `denylist` user-deposit tokens.

## False-positive notes

- Internal functions called only from properly-guarded externals are fine — verify call sites.
- A function may look unguarded but its only side-effect is emitting an event — Info, not High.
- "Permissionless" by design (e.g. `claim()` for caller) is fine — verify intent against the spec.

## Related

- [[initialization]] — initializer-specific access control
- [[centralization-risk]] — admin-power audit
- [[delegatecall-risks]] — proxy upgrade authorization

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [omermaksutii](https://github.com/omermaksutii)
- **Source:** [omermaksutii/RugProof](https://github.com/omermaksutii/RugProof)
- **License:** MIT
- **Homepage:** https://omermaksutii.github.io/RugProof

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-omermaksutii-rugproof-access-control
- Seller: https://agentstack.voostack.com/s/omermaksutii
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
