Security Advisory: Storage Aliasing in Priority Update Registry V1 09/15/26

On September 15, 2026, we identified a critical vulnerability in version 1 of the Priority Update Registry, an on-chain contract that trading integrators use to publish and read price updates. The flaw let any address authorize itself to publish prices for any registered target, and then publish arbitrary prices. The same flaw could be used to disable a legitimate publisher.

The issue has been fixed. A corrected registry has been deployed, affected integrators have secured their funds, and canonical references now point to the fixed contract. We found no evidence that the vulnerability was exploited before it was fixed.

This advisory describes the vulnerability, its impact, and the remediation so that anyone running or integrating a copy of this contract can respond.

Fixed Ethereum mainnet deployment: 0xDa7AfEeD021EAFC1c1Af9C362dE477DaD0396B81

Background

The Priority Update Registry (PUR) is a simple on-chain price feed. A few concepts:

  • Target: a contract an integrator deploys (for example, a propAMM) that authorizes updaters to publish information (e.g. prices) to PUR and reads the posted information.
  • Updater: an address authorized to publish prices for a target. The registry stores this in an authorization mapping, isUpdater[target][updater].
  • Lane: a slot of storage the registry keeps for a target, holding the posted price data. Updaters write a target’s lanes; the target reads them from the registry at settlement time.

The authorization table and the lane data both live in the same contract’s storage. Keeping them separate is what the vulnerability broke.

The vulnerability

The contract computed a lane’s storage location directly from a caller-supplied lane index:

laneSlot = keccak256(abi.encode(laneTarget, laneIndex))

laneIndex was an unbounded value chosen by the caller. Meanwhile the authorization mapping sat at storage slot 0, so an authorization record resolved to:

isUpdaterSlot = keccak256(abi.encode(updater, keccak256(abi.encode(target, 0))))

These two expressions have the same shape. A caller who set laneTarget to their own address and laneIndex to keccak256(abi.encode(target, 0)) produced a lane slot that landed on the exact storage location of isUpdater[target][attacker]. Writing to that “lane” therefore wrote directly into the authorization table.

No cryptographic search was involved. The collision is a direct consequence of the layout, and any caller could compute the colliding index.

The result was that an attacker could:

  • Authorize themselves as an updater for any target, without permission, and then publish arbitrary prices for that target; and
  • Corrupt existing authorizations by writing into the same table, for example revoking a legitimate updater and disrupting a target’s price feed. (Other authorized updaters, where they exist, could remain able to publish.)

Impact

The direct consequence is that an attacker could control the prices a target publishes. The financial impact depended on how each target contract used the feed. A contract that consumed registry prices as trusted input at settlement, without independent staleness, deviation, or per-pair checks, could have been made to settle trades at attacker-controlled prices, resulting in direct loss. Contracts that independently constrained settlement, or that gated execution behind their own authorization, were less exposed.

We assessed the integrations known to us across the affected chains. All integrator funds are now secured. We describe what we found below.

Affected deployments

The vulnerability is present in the original, non-namespaced lane layout used by the deployments below.

Chain Registry (vulnerable) Status
Ethereum mainnet 0xDa7AfeeD01fe625CF15d187a19f94B45f00b8C5F Superseded by fixed deployment; integrators migrated / funds secured
BNB Smart Chain 0x484848566dfCf43466E819D74aC76C8DdD484848 (BAP-710 variant) Remediation coordinated with maintainers and integrators

Several smaller V1-style instances share the same layout and are likewise affected; the ones we identified held no value at risk. Having no identified exposure does not by itself prove an instance is safe. Any deployment with the original layout should be treated as vulnerable and migrated.

The source and reference documentation are maintained in the Priority Update Registry repository. The original deployments remain vulnerable and should not be used.

The fix

The fix namespaces the lane storage location so it can no longer overlap the authorization table:

LANE_STORAGE_NAMESPACE = keccak256("PrioUpdateRegistry.lane")
laneSlot = keccak256(abi.encode(LANE_STORAGE_NAMESPACE, target, laneIndex))

The 96-byte lane preimage cannot equal the 64-byte authorization preimage, eliminating the deterministic alias. Finding an exploitable overlap would then require a computationally infeasible cryptographic search against Keccak-256. The same namespaced layout will carry into the next version of the registry.

The change is in commit 8701e8e of the Priority Update Registry.

Guidance for integrators

  • Migrate off the vulnerable registry to the fixed deployment. Migration is not a drop-in address change: the storage layout changed, so you must re-establish updater authorizations and re-initialize lane state on the new contract, then point both publishers and consumers at it. If your producer signs over a verifying-contract address, update that domain. An immutable consumer contract that hardcodes the old registry must be replaced, not reconfigured.
  • Minimize allowances. Scope token allowances to the minimum necessary and ensure you have emergency mechanisms in place that move funds beyond the reach of external actors or dependencies.

Findings

We found no evidence of a takeover or aliasing write prior to remediation. This is a “no evidence found,” not a proof of absence: our review covered direct transactions over the periods examined and does not fully cover signed batches or internal calls, and the aliasing write emits no event. Anyone operating a copy should review their own contract’s storage and update history directly.

The vulnerability was identified on 2026-09-15 during review of a registry integration change, and was assessed, remediated, and disclosed the same day. One propAMM team was notified a week earlier (2026-09-07) by SEAL 911, but Flashbots was not made aware of the vulnerability as the initial discovery was thought to be limited to that particular propAMM system.