Skip to content

fix(recovery): verify recover_account signature against chain owner history - #307

Merged
ety001 merged 1 commit into
nextfrom
fix/recover-account-signature-bypass
Jul 29, 2026
Merged

fix(recovery): verify recover_account signature against chain owner history#307
ety001 merged 1 commit into
nextfrom
fix/recover-account-signature-bypass

Conversation

@ety001

@ety001 ety001 commented Jul 28, 2026

Copy link
Copy Markdown
Member

Summary

Fixes audit V2 finding #2 (High): the recover-account route verified the transaction signature against the recent_owner_authority public key read from the attacker-supplied op body. This was trivially self-satisfiable — an attacker signs with their own key and puts the corresponding public key into recent_owner_authority. The check proved only that the submitter holds some key, which is meaningless for recover_account.

Changes

src/app/api/broadcast/recover-account/route.ts:

  • Fetch the on-chain owner-key change history via SteemService.getOwnerHistory(account_to_recover).
  • Collect all real previous_owner_authority public keys from the chain.
  • Assert the op body's recent_owner_authority.key_auths[0][0] matches one of those real historical keys (attacker cannot forge this).
  • Verify the signature against that validated key.
  • Fail-closed (503) if the owner-history RPC lookup fails.
  • Fix the misleading comment that claimed the DB check was the "only application-layer gate" — the signature verification is now a real gate too.

tests/unit/broadcast-recover-account-route.test.ts:

  • Add getOwnerHistory mock, default returns a history containing VALID_KEY_A.
  • New test: recent key not in chain history → 400 (the core bypass fix).
  • New test: empty owner history → 400.
  • New test: owner-history RPC failure → 503.

Security impact

The path was not exploitable end-to-end before this fix (the DB gate + on-chain request_account_recovery still protect it), but the self-satisfiable signature check provided a false sense of security and the misleading comment could cause reviewers to over-trust it. This fix makes the application-layer signature verification meaningful.

Test plan

  • pnpm type-check — clean
  • pnpm test — 470 passed (3 new test cases)

…istory

The recover-account route verified the transaction signature against the
recent_owner_authority public key read from the attacker-supplied op body.
This was trivially self-satisfiable: an attacker signs with their own key and
puts the corresponding public key into recent_owner_authority. The check proved
only that the submitter holds *some* key — meaningless for recover_account.

Now fetch the on-chain owner-key change history (get_owner_history) and:
1. Assert the op body's recent_owner_authority key matches a real historical
   owner key recorded on-chain (attacker cannot forge this).
2. Verify the signature against that validated key.
3. Fail-closed (503) if the owner-history RPC lookup fails.

Also fix the misleading comment that claimed the DB check was the 'only
application-layer gate' — the signature verification is now a real gate too.

Tests: add cases for history-key mismatch (400), empty history (400), and RPC
failure (503); update mock to support getOwnerHistory.
@ety001
ety001 merged commit bc3399c into next Jul 29, 2026
2 of 3 checks passed
@ety001
ety001 deleted the fix/recover-account-signature-bypass branch July 29, 2026 03:31
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.

1 participant