Skip to content

fix(runtime): allow det accounts from meta tx#15812

Merged
jakmeier merged 4 commits into
near:masterfrom
jakmeier:fix_delegated_det_id_check
May 27, 2026
Merged

fix(runtime): allow det accounts from meta tx#15812
jakmeier merged 4 commits into
near:masterfrom
jakmeier:fix_delegated_det_id_check

Conversation

@jakmeier

@jakmeier jakmeier commented May 27, 2026

Copy link
Copy Markdown
Contributor

Allow creating DeterministicStateInitAction from a delegated action by fixing the receiver id check. It used to check against the outer receiver instead of the inner. (A mistake on my initial implementation, gone unnoticed until now.)

As tests show, this is not actually exploitable. This is merely an incomplete feature, preventing anybody from using deterministic accounts from meta transactions.

This is a protocol change, hence it is protocol version gated.

edit: Thank you @loopghost for finding and reporting this bug!

jakmeier added 3 commits May 27, 2026 12:35
Allow creating `DeterministicStateInitAction` from a delegated action by fixing the receiver id check. It used to check against the outer receiver instead of the inner.

As tests show, this is not actually exploitable. This is merely an incomplete feature, preventing anybody from using deterministic accounts from meta transactions.

This is a protocol change, hence it is protocol version gated.
@jakmeier jakmeier requested a review from jancionear May 27, 2026 11:48
@jakmeier jakmeier marked this pull request as ready for review May 27, 2026 11:48
@jakmeier jakmeier requested a review from a team as a code owner May 27, 2026 11:48

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 fixes delegated (meta) transactions containing DeterministicStateInitAction by validating the receiver ID against the inner DelegateAction.receiver_id (instead of the outer transaction receiver), enabling deterministic account creation via meta transactions. The change is protocol-version gated via a new ProtocolFeature.

Changes:

  • Fix delegated-action validation to use the delegate action’s receiver ID (protocol-gated).
  • Add integration tests covering meta-tx deterministic account creation and pre-/post-fix behavior.
  • Register the new protocol feature and document it in the changelog.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
test-loop-tests/src/tests/deterministic_account_id.rs Adds meta-transaction tests and a protocol-version-configurable TestEnv setup.
runtime/runtime/src/action_validation.rs Protocol-gated fix to validate inner delegated actions against the correct receiver ID.
core/primitives-core/src/version.rs Adds FixDelegatedDeterministicStateInit protocol feature and assigns it a protocol version.
CHANGELOG.md Notes the protocol change enabling deterministic accounts via meta transactions.

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

Comment thread test-loop-tests/src/tests/deterministic_account_id.rs
Comment thread test-loop-tests/src/tests/deterministic_account_id.rs
Comment thread core/primitives-core/src/version.rs
@pugachAG pugachAG changed the title fix: allow det accounts from meta tx fix(runtime): allow det accounts from meta tx May 27, 2026
- improve test setup to be more protocol version independent
- fix typo
@jakmeier jakmeier added this pull request to the merge queue May 27, 2026
@codecov

codecov Bot commented May 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 69.83%. Comparing base (f448f52) to head (ef5b02d).
⚠️ Report is 3 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #15812      +/-   ##
==========================================
- Coverage   69.87%   69.83%   -0.05%     
==========================================
  Files         940      942       +2     
  Lines      199810   200312     +502     
  Branches   199810   200312     +502     
==========================================
+ Hits       139622   139878     +256     
- Misses      55516    55732     +216     
- Partials     4672     4702      +30     
Flag Coverage Δ
pytests-nightly 1.13% <0.00%> (-0.01%) ⬇️
unittests 69.21% <100.00%> (-0.05%) ⬇️
unittests-nightly 69.50% <100.00%> (-0.06%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Merged via the queue into near:master with commit 8f0e4c6 May 27, 2026
32 checks passed
@jakmeier jakmeier deleted the fix_delegated_det_id_check branch May 27, 2026 16:16
@loopghost

Copy link
Copy Markdown

@jakmeier @jancionear @pugachAG

I am the researcher who reported this bug privately through your official HackenProof bug bounty as report NEAP-432, with a working PoC and a live RPC reproduction, before this PR was opened. The fix that landed here is the fix to my report. Please do not pretend otherwise.

The PR description currently reads "A mistake on my initial implementation, gone unnoticed until now." That phrasing is factually inaccurate. The bug had not "gone unnoticed." It had been privately disclosed through your official bug bounty, triaged by HackenProof, and forwarded to NEAR engineering. The verifiable timeline is on the platform record. The fix being merged here, including the new ProtocolFeature::FixDelegatedDeterministicStateInit variant, the CHANGELOG entry, the protocol-version 85 gate, and the regression test using the exact attack pattern I described (outer receiver matches DSI derivation, inner receiver does not), is the direct engineering response to NEAP-432.

I want to be honest about how I read this, without making it personal. I invested a significant amount of time on this disclosure, the PoC, the live RPC reproduction, and the follow-up evidence. By NEAR's own engineering action in this very PR, the finding is real and worth a protocol-version-gated fix. By NEAR engineering's own code comment introduced here, it is "a bug." The NEAR security team has nonetheless closed NEAP-432 as "Informative" and refused payment, arguing that the bug is not security-impacting because there is no adversary.

There is a basic principle that holds in every reputable bug bounty program: if the team applies a fix that came from a reporter's disclosure, the team pays the reporter. Otherwise, the project is taking the reporter's work without compensating it. From the outside, the combination of shipping the fix, reframing the discovery as internal, and declining to pay the reporter is difficult to interpret as anything other than abuse of the program and unjust enrichment of the project at my expense. I am stating that plainly because I think the team deserves to hear it plainly, not as an accusation against any one of you individually but as a description of what the pattern looks like to a reporter who acted in good faith. I came in through the official channel, I followed the rules, and what I have received in return is a fix shipped on my report and a closure that denies the report ever mattered. From my side, that is, in plain terms, abuse of my good faith and a scam against a reporter who did everything the program asked of him.

The argument used to deny payment does not hold against the NEAR program's published scope on HackenProof, which lists DoS without hardfork as an in-scope category with a USD 10,000 minimum reward. An unintentional DoS is still a DoS, and the program scope does not require an adversary. The PR description states, in NEAR's own words, that the previous code is "preventing anybody from using deterministic accounts from meta transactions." That is network-wide denial of service against the entire user population for one of the program's listed primary integration paths. NEAR engineering does not consume protocol-version slots on non-issues. The classification by the NEAR security team is incompatible with the engineering treatment shown in this PR.

I am asking two things publicly here:

  1. Correct the framing. Update the PR description, the merge commit message, or the CHANGELOG entry to acknowledge that the fix originated from external disclosure (HackenProof report NEAP-432). The current language attributes the discovery to internal review, which is not what happened.

  2. Honor the HackenProof program rules NEAR publishes. Pay the USD 10,000 minimum bounty listed under DoS without hardfork. Not more than the minimum. The minimum the program itself promises.

A formal appeal has been filed through HackenProof platform mediation. If this is not corrected through that channel, the full case, including the disclosure timeline, the verbatim engineering acknowledgement in this PR, the closure message from the NEAR security team, and the appeal correspondence, will be published as a documented enforcement failure. That publication will contain no exploit-enabling material beyond what is already public in this merged PR. The decision of whether that publication becomes necessary is in your team's hands.

I would much rather this be resolved cleanly. NEAR has shipped solid security fixes from external reports before and has paid those reports per the program. This case should not be the exception.

Thanks.

@walnut-the-cat

Copy link
Copy Markdown
Contributor

@loopghost, thanks for reaching out. Since we’re also connected on HackenProof, where you submitted the initial report, we’ll follow up with you there.

Thank you again for your contribution and support for the project.

@loopghost

Copy link
Copy Markdown

Thank you @walnut-the-cat for the quick reply and for confirming the follow-up will continue on HackenProof.

I really appreciate that. I have put a significant amount of time and care into this finding (the technical analysis, the PoC, the live RPC reproduction, and the follow-up evidence), and my intention going forward is to keep investing time in the NEAR codebase and to keep collaborating responsibly with your team through the proper channel. NEAR is a serious project and I am genuinely interested in contributing to it in the long term.

I trust the NEAR team will arrive at a fair resolution on this. I will wait for your follow-up on HackenProof and I am available there for any clarification or additional material that helps the review.

Thanks again, and have a good day.

@loopghost

Copy link
Copy Markdown

Thanks @walnut-the-cat, and @jakmeier as the author of the fix. I appreciate the courtesy, but I want to be straight about where this landed, on the record and in the open.

Through the private channel, the decision was confirmed as final: this is acknowledged as a real, reproduced, fixed bug, my report and PoC were called competent and good-faith, and there is "no disagreement on the technical facts." And the payout is zero, classified Informative. So the position is that NEAR received a private disclosure, shipped my fix under a dedicated protocol feature with a 212-line regression test reconstructing exactly the attack I described, and the reporter gets nothing and was, until I raised it, not even credited.

I have made my full technical and scope argument privately and I will not relitigate it line by line here. But I do want to say this where it is visible: a confirmed defect in production consensus-critical validation logic on a live L1, fixed by the vendor under a ProtocolFeature gate, is not an Informative non-issue, and I do not accept that framing.

I understand you may prefer to keep this discussion private, and that is fine by me. I have sent an email to [email protected] laying out the case in full, and I would genuinely appreciate continuing the conversation there, directly with the engineers who wrote and shipped this fix rather than only through triage. You confirmed the bug. You wrote "this is a bug" into the committed code. I am asking to engage with your team directly on how this was handled.

Two concrete things:

  1. The reporter attribution in this PR that was promised to me. I would like it made and confirmed.
  2. Since the bug is already public and there is no embargo left, I intend to publish a full writeup of this vulnerability and the complete record of how it was handled. I will publish the facts as everyone has agreed to them and let the community draw its own conclusions about the outcome.

I came in through the proper channel, followed every rule, and did high-quality work that you used. I think that deserved a fair result, and I think the record should reflect what actually happened here.

@walnut-the-cat

Copy link
Copy Markdown
Contributor

Hello @loopghost,

Thanks for reaching out.

Please understand that we use the triaging channel to interact with all vulnerability reporters in the same manner: objectively and without emotions involved. For that reason, we avoid involving individual team members in the direct handling of bug reports or security vulnerabilities.

That said, we assure you that the author of the PR and the engineering team were involved throughout the entire decision-making process for this case.

If you would like to continue the discussion, we suggest going through HackenProof rather than [email protected], as HackenProof is the official, public channel we support, and the same team members are involved there as well. If you have additional details or reproduction steps to support the claim that this is a security vulnerability, we will gladly review and process them accordingly.

As promised, we will update the PR description to note you as the bug reporter.

Please also note that confirming a bug or writing a regression test does not make it a security vulnerability. We write regression tests for any feature development or bug fix, regardless of its security implications.

Once again, we appreciate your time and contribution.

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.

6 participants