Skip to content

fix(contracts): backport first-owner PKP binding to v1.1.10 hotfix (#575)#578

Merged
GTC6244 merged 1 commit into
release/v1.1.10from
hotfix-v1.1.10
Jul 17, 2026
Merged

fix(contracts): backport first-owner PKP binding to v1.1.10 hotfix (#575)#578
GTC6244 merged 1 commit into
release/v1.1.10from
hotfix-v1.1.10

Conversation

@GTC6244

@GTC6244 GTC6244 commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Hotfix branched from the v1.1.10 tag into a release/v1.1.10 maintenance base that backports the register-side portion of PR #577 — the global pkpIdToOwnerMaster first-owner binding that closes the cross-account PKP hijack via publicly-visible derivation paths (#575). It adds the binding in registerWalletDerivation, a fail-closed check in getWalletDerivation, an idempotent owner/config-operator-only backfillPkpOwners + hardhat migration task for pre-upgrade wallets, regenerated ABI/alloy bindings, and ported forge tests (full suite 48/48 pass, cargo check clean). The delete/re-register-race handling from #577 was intentionally dropped because v1.1.10 has no removeWalletDerivation (that feature, #553, is one of the 48 commits between v1.1.10 and main), so this diverges from the reviewed #577 code and needs a security re-review before release.

Note: main is unaffected — it should receive the original #577 (which retains the delete-race protection), not this backport. Operational: run backfillPkpOwners promptly after the facet upgrade (legacy wallets stay exploitable until then) and flush/restart nodes to clear the 300s derivation cache.

, #577)

Hotfix backport of PR #577 onto the v1.1.10 release. #577 targets main,
which is 48 commits ahead and includes the PKP hard-delete feature (#553)
that v1.1.10 lacks, so a straight cherry-pick conflicts. This applies only
the register-side security fix (the part that stands alone on v1.1.10) and
drops the delete/re-register-race handling, which is moot here because
v1.1.10 has no removeWalletDerivation.

Included:
- AppStorage: global `pkpIdToOwnerMaster` binding (appended, upgrade-safe).
- WritesFacet.registerWalletDerivation: first master to register a pkpId
  owns it forever; cross-account registration reverts.
- WritesFacet.backfillPkpOwners + PkpOwnerBackfilled event: idempotent,
  owner/config-operator-only migration for pre-upgrade wallets.
- ViewsFacet.getWalletDerivation: fails closed when a bound wallet is read
  by a non-owner (neutralizes pre-upgrade hijacks); getPkpOwnerMaster getter.
- Hardhat backfill task + regenerated ABI and alloy bindings (forge 1.5.1).
- Ported forge tests (delete-race test omitted); full suite: 48 passed.

Diverges from the reviewed #577 code (delete-race bits removed, bindings
regenerated on a different forge version) — needs security re-review before
release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@GTC6244
GTC6244 requested review from a team and Copilot July 15, 2026 23:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR backports the on-chain mitigation for issue #575 (cross-account PKP hijack via publicly visible derivation paths) into the lit_node_express AccountConfig diamond, introducing a global “first-owner” binding (pkpId → masterHash), hardening reads to fail closed for hijacked rows, and providing an owner/config-operator migration path to bind legacy wallets.

Changes:

  • Enforce a global first-owner binding in registerWalletDerivation and a fail-closed ownership check in getWalletDerivation; add getPkpOwnerMaster for auditing.
  • Add backfillPkpOwners (owner/config-operator) and a Hardhat task to scan historical WalletDerivationRegistered events and backfill legacy bindings.
  • Regenerate ABI + Rust alloy bindings and extend Foundry tests + selector registration for the new entrypoints.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
lit-api-server/src/accounts/contracts/AccountConfig.json Updated contract ABI JSON with new error/event/functions for PKP owner backfill/binding.
lit-api-server/src/accounts/contracts/account_config_contract.rs Regenerated Rust/alloy bindings to include backfillPkpOwners, getPkpOwnerMaster, and PkpOwnerBackfilled.
lit-api-server/blockchain/lit_node_express/test/helpers/DiamondDeploy.sol Registers new selectors for getPkpOwnerMaster and backfillPkpOwners in the test diamond deployment helper.
lit-api-server/blockchain/lit_node_express/test/Accounts.t.sol Adds Foundry coverage for cross-account hijack reverts, legacy backfill behavior, and fail-closed reads.
lit-api-server/blockchain/lit_node_express/tasks/backfill-pkp-owners.ts New Hardhat migration task to backfill pkpIdToOwnerMaster from on-chain event history (dry-run by default).
lit-api-server/blockchain/lit_node_express/hardhat.config.ts Wires the new backfill-pkp-owners task into Hardhat config.
lit-api-server/blockchain/lit_node_express/contracts/AccountConfigFacets/WritesFacet.sol Adds global binding enforcement on registration and introduces backfillPkpOwners.
lit-api-server/blockchain/lit_node_express/contracts/AccountConfigFacets/ViewsFacet.sol Adds fail-closed owner enforcement in getWalletDerivation and exposes getPkpOwnerMaster.
lit-api-server/blockchain/lit_node_express/contracts/AccountConfigFacets/AppStorage.sol Appends pkpIdToOwnerMaster to diamond storage layout.
CHANGELOG.md Documents the security fix, fail-closed behavior, and need to run the backfill post-upgrade.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +724 to +733
for (uint256 i = 0; i < pkpIds.length; i++) {
if (masterHashes[i] == 0) {
revert AppStorage.InvalidRequest("masterHash must be non-zero");
}
if (s.pkpIdToOwnerMaster[pkpIds[i]] != 0) {
continue; // already bound — never re-assign ownership
}
s.pkpIdToOwnerMaster[pkpIds[i]] = masterHashes[i];
emit PkpOwnerBackfilled(pkpIds[i], masterHashes[i]);
}
@GTC6244
GTC6244 changed the base branch from main to chore/investigate-stripe-balance-cache July 15, 2026 23:36
@GTC6244
GTC6244 changed the base branch from chore/investigate-stripe-balance-cache to release/v1.1.10 July 15, 2026 23:38
@GTC6244
GTC6244 merged commit ae36a42 into release/v1.1.10 Jul 17, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants