Skip to content

fix(nip59): authenticate daemon via seal identity, not rumor sender - #104

Merged
grunch merged 3 commits into
mainfrom
feat/migrate-nip59-mostro-core-0.10
Apr 25, 2026
Merged

fix(nip59): authenticate daemon via seal identity, not rumor sender#104
grunch merged 3 commits into
mainfrom
feat/migrate-nip59-mostro-core-0.10

Conversation

@grunch

@grunch grunch commented Apr 25, 2026

Copy link
Copy Markdown
Member

The previous check compared the active Mostro pubkey against the rumor sender, which is self-asserted whenever the inner signature is absent — the common case for protocol responses. An attacker could seal a wrap with their own key and set the rumor pubkey to the configured Mostro key, bypassing the check.

Authenticate against identity (the seal signer, verified inside unwrap_message) and reject unsigned rumors whose sender diverges from the verified identity.

Summary by CodeRabbit

  • Bug Fixes
    • Enhanced protocol response authentication to use more secure verification methods.
    • Added stricter validation for message integrity to reject improperly signed requests.

The previous check compared the active Mostro pubkey against the rumor
sender, which is self-asserted whenever the inner signature is absent —
the common case for protocol responses. An attacker could seal a wrap
with their own key and set the rumor pubkey to the configured Mostro
key, bypassing the check.

Authenticate against `identity` (the seal signer, verified inside
`unwrap_message`) and reject unsigned rumors whose `sender` diverges
from the verified `identity`.
@coderabbitai

coderabbitai Bot commented Apr 25, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@grunch has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 50 minutes and 19 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 50 minutes and 19 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 34d76d03-50a1-40be-9d6f-d8d1b011aee8

📥 Commits

Reviewing files that changed from the base of the PR and between 9d3dab2 and cc64ad3.

📒 Files selected for processing (1)
  • rust/src/api/orders.rs

Walkthrough

The changes update NIP-59 message authentication in dispatch_mostro_message to verify protocol responses against the seal signer's identity field rather than the unauthenticated sender field. An additional guard rejects messages when the inner signature is absent and sender diverges from identity. Documentation is clarified to reflect authentication boundaries.

Changes

Cohort / File(s) Summary
Authentication Logic
rust/src/api/orders.rs
Modified dispatch_mostro_message to authenticate against NIP-59 identity (seal signer) instead of sender. Added guard to reject messages with missing inner signature when sender and identity diverge.
Documentation Updates
rust/src/nostr/gift_wrap.rs
Clarified that unwrap_mostro_message performs no daemon authentication; seal signature verifies cryptographic attribution to identity. Noted distinction between seal signer and rumor pubkey; documented that upstream routing enforces Mostro-pubkey check against identity.

Sequence Diagram(s)

sequenceDiagram
    participant Client as External Client
    participant GiftWrap as Gift Wrap Handler
    participant Dispatch as Dispatch Handler
    participant Verifier as Identity Verifier

    Client->>GiftWrap: Send wrapped message
    activate GiftWrap
    GiftWrap->>GiftWrap: Unwrap message<br/>(extract sender, identity, signature)
    GiftWrap->>Verifier: Verify seal signature
    activate Verifier
    Verifier-->>GiftWrap: ✓ Seal verified against identity
    deactivate Verifier
    GiftWrap-->>Dispatch: Return UnwrappedMessage
    deactivate GiftWrap

    activate Dispatch
    alt Inner signature missing AND sender ≠ identity
        Dispatch->>Dispatch: Reject message
        Dispatch-->>Client: ✗ Rumor origin integrity check failed
    else Valid configuration
        Dispatch->>Dispatch: Match identity against<br/>Mostro pubkey
        alt Identity matches Mostro
            Dispatch-->>Client: ✓ Route message
        else Identity mismatch
            Dispatch-->>Client: ✗ Reject message
        end
    end
    deactivate Dispatch
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 The seal now speaks truth through its signer's key,
Identity rises where sender used to be,
With guards on the signatures, missing or whole,
NIP-59 messages now play their true role,
Trust flows to the source, cryptographically free! 🔐

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: fixing NIP-59 authentication by using seal identity instead of rumor sender, which is the core security fix in this PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/migrate-nip59-mostro-core-0.10

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9d3dab2a7d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread rust/src/api/orders.rs Outdated
// it (checked inside `unwrap_message`). Without a signature, a `sender`
// that diverges from the verified `identity` is an unauthenticated claim
// — drop it rather than route a message whose origin we cannot prove.
if signature.is_none() && sender != identity {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Do not reject unsigned wraps solely on sender/identity mismatch

After authenticating the wrap against identity == active_mostro_pubkey, this new guard drops any unsigned message where sender != identity. In Mostro's reputation-mode key split, sender (trade key) and identity (seal key) are expected to differ, and responses can legitimately be unsigned; in that case this returns early and prevents valid daemon updates (including order status/confirmation flows) from being dispatched even though the origin is already authenticated by the seal signature.

Useful? React with 👍 / 👎.

@MostroP2P MostroP2P deleted a comment from coderabbitai Bot Apr 25, 2026
The previous guard rejected any unsigned wrap whose rumor sender
differed from the seal identity. In Mostro's reputation-mode key split
`sender` (per-trade key) and `identity` (long-lived seal key) are
expected to differ, and protocol responses commonly omit the inner
signature, so the check dropped legitimate daemon updates (order
status, confirmations) even though the seal signature already
authenticates the origin against the active Mostro pubkey.

Authentication now relies solely on `identity == active_mostro_pubkey`
— a forger who seals with their own key cannot make it match — and the
unauthenticated `sender` is no longer used to gate dispatch.
@MostroP2P MostroP2P deleted a comment from coderabbitai Bot Apr 25, 2026
@MostroP2P MostroP2P deleted a comment from coderabbitai Bot Apr 25, 2026
@grunch

grunch commented Apr 25, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Apr 25, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
rust/src/api/orders.rs (1)

1049-1053: ⚠️ Potential issue | 🟡 Minor

Stale docstring — still says "Authenticates the sender".

The function-level doc above the changed body now contradicts the implementation: authentication is performed against the seal signer's identity, not sender. Consider tightening the wording so the contract matches the new behavior (and the clarified unwrap_mostro_message doc in rust/src/nostr/gift_wrap.rs).

📝 Suggested doc tweak
 /// Dispatch a Mostro `Message` recovered from a gift-wrap.
 ///
-/// Authenticates the sender against the active Mostro pubkey, runs the
-/// centralized `validate_response` check (catches `CantDo` responses and
-/// malformed `request_id` fields), then routes by action.
+/// Authenticates the seal signer (`identity`) against the active Mostro
+/// pubkey — never the unauthenticated rumor `sender` — and additionally
+/// rejects unsigned rumors whose `sender` diverges from the verified
+/// `identity`. Then runs the centralized `validate_response` check (catches
+/// `CantDo` responses and malformed `request_id` fields) and routes by action.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rust/src/api/orders.rs` around lines 1049 - 1053, Update the function
docstring for the dispatch implementation in rust/src/api/orders.rs so it
accurately describes that authentication is performed against the seal signer's
identity (not the message sender); mention that it uses unwrap_mostro_message
(see unwrap_mostro_message in rust/src/nostr/gift_wrap.rs) to recover the
Message and validate the seal signer, then runs validate_response and routes by
action — keep the wording concise and aligned with the current implementation
(referencing the seal signer/identity rather than sender).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@rust/src/api/orders.rs`:
- Around line 1049-1053: Update the function docstring for the dispatch
implementation in rust/src/api/orders.rs so it accurately describes that
authentication is performed against the seal signer's identity (not the message
sender); mention that it uses unwrap_mostro_message (see unwrap_mostro_message
in rust/src/nostr/gift_wrap.rs) to recover the Message and validate the seal
signer, then runs validate_response and routes by action — keep the wording
concise and aligned with the current implementation (referencing the seal
signer/identity rather than sender).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1a84dd32-adf6-421c-ad1d-167e79675e70

📥 Commits

Reviewing files that changed from the base of the PR and between 3462700 and 9d3dab2.

📒 Files selected for processing (2)
  • rust/src/api/orders.rs
  • rust/src/nostr/gift_wrap.rs

The docstring claimed authentication was performed against the rumor
sender, but the implementation authenticates against the seal signer's
identity. Update the wording to match: reference unwrap_mostro_message
as the source of the verified unwrap and clarify that identity (never
sender) is checked against the active Mostro pubkey.
@grunch
grunch merged commit b5e4dca into main Apr 25, 2026
1 check passed
@grunch
grunch deleted the feat/migrate-nip59-mostro-core-0.10 branch April 25, 2026 19:12
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