# V4 Hook Permission Flags Mismatch

> Detect Uniswap V4 hooks whose address-encoded permission flags don't match the callbacks the hook actually implements. In V4 the hook's permissions live in the low bits of its deployed address (mined via CREATE2 salt) and must agree with getHookPermissions(); a callback the hook implements but whose flag bit is unset is never invoked, and a flag set without a real implementation makes pool initia…

- **Type:** Skill
- **Install:** `agentstack add skill-omermaksutii-rugproof-v4-hook-permission-flags-mismatch`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [omermaksutii](https://agentstack.voostack.com/s/omermaksutii)
- **Installs:** 0
- **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/rules/uniswap-v4-hooks/skills/v4-hook-permission-flags-mismatch
- **Website:** https://omermaksutii.github.io/RugProof

## Install

```sh
agentstack add skill-omermaksutii-rugproof-v4-hook-permission-flags-mismatch
```

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

## About

# Uniswap V4 hook permission-flag mismatch detection

## When this applies

Trigger on any of:

- Contracts inheriting `BaseHook` / implementing `IHooks`
- An overridden `getHookPermissions()` returning a `Hooks.Permissions` struct
- Implemented callbacks: `beforeSwap`, `afterSwap`, `beforeAddLiquidity`, `afterAddLiquidity`, `beforeRemoveLiquidity`, `afterRemoveLiquidity`, `beforeInitialize`, `afterInitialize`, `beforeDonate`, `afterDonate`
- `*ReturnDelta` permission flags (`afterSwapReturnDelta`, `beforeSwapReturnDelta`, etc.)
- CREATE2 / `HookMiner.find` salt mining to encode flags into the hook address
- Pool initialization that passes the hook address to `PoolManager.initialize`

## Detection patterns

### Implemented callback whose flag bit is unset (HIGH)
```solidity
function getHookPermissions() public pure override returns (Hooks.Permissions memory) {
    return Hooks.Permissions({ beforeSwap: true, afterSwap: false, /* ...all else false */ });
}
function afterSwap(...) external override returns (bytes4, int128) {
    _accrueFees(...);          // ← real logic, but afterSwap flag is FALSE
    return (this.afterSwap.selector, 0);
}
```
The pool reads permissions from the hook *address bits*, not from the function table. With the `AFTER_SWAP` bit unset, the PoolManager never calls `afterSwap`; `_accrueFees` silently never runs.
**Signal:** a callback is implemented (non-reverting body) but its corresponding permission is `false` / the address bit is unmined.

### Flag set without implementation → init reverts (HIGH)
```solidity
return Hooks.Permissions({ beforeAddLiquidity: true, /* ... */ });
// but beforeAddLiquidity is NOT overridden → BaseHook reverts HookNotImplemented
```
`Hooks.validateHookPermissions` checks that each set address bit corresponds to an implemented callback; a set flag with no override makes `PoolManager.initialize` revert, bricking the pool.
**Signal:** permission `true` (or address bit set) with no matching overridden function, or the default `BaseHook` stub left in place (reverts `HookNotImplemented`).

### returnDelta flag mismatch (HIGH)
```solidity
beforeSwapReturnDelta: false   // but beforeSwap returns a non-zero BeforeSwapDelta
```
If `beforeSwap` returns a non-zero delta while `BEFORE_SWAP_RETURNS_DELTA` is unset, the manager ignores the delta (or reverts), stranding the accounting the hook tried to apply.
**Signal:** a callback returns a non-zero `BeforeSwapDelta`/`int128` while its `*ReturnDelta` permission is false.

### Address bits ≠ getHookPermissions (HIGH)
```solidity
address hook = address(uint160(0x...0040));  // only BEFORE_SWAP bit
// getHookPermissions() also claims afterSwap → mismatch at validateHookPermissions
```
**Signal:** the mined deployment address low bits don't equal the `getHookPermissions()` struct.

## Severity rubric

| Pattern | Severity | Notes |
|---|---|---|
| Implemented callback with unset flag → silently skipped | **High** | Fees/limits/guards never run |
| Flag set, no implementation → init reverts | **High** | Pool un-initializable (DoS) |
| returnDelta flag mismatch → delta ignored | **High** | Stranded accounting, see [[v4-hook-delta-accounting]] |
| Address bits disagree with getHookPermissions | **High** | Deterministic init revert |
| Cosmetic flag set but callback is a true no-op | **Low** | Wasted gas only |

## Remediation patterns

1. **Single source of truth** — derive the deploy salt from `getHookPermissions()` (e.g. `HookMiner.find` with the exact flag set) so address bits and the struct can't drift.
2. **Assert at construction** — `Hooks.validateHookPermissions(this, getHookPermissions())` in the constructor to fail fast on a wrong address.
3. **Implement exactly the flagged callbacks** — every `true` has an override; every override has a `true`. Remove dead callbacks or set their flag.
4. **Set the matching `*ReturnDelta` flag** whenever a callback can return a non-zero delta.
5. **Test against the real PoolManager** init path, not a mock that skips validation.

## False-positive notes

- A callback present only to satisfy an interface but truly returning zero/no-op with its flag intentionally unset is fine — Info, confirm no side effects.
- Hooks deployed via the official `HookMiner` with asserted permissions are consistent by construction.

## Related

- [[v4-hook-delta-accounting]] — returnDelta flags pair with settlement
- [[access-control]]
- [[initialization]]

## 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-v4-hook-permission-flags-mismatch
- 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%.
