Skip to content

Fail closed when the NIP-17 timestamp cannot be fuzzed - #69

Merged
kwsantiago merged 2 commits into
mainfrom
nip17-fail-closed
Aug 3, 2026
Merged

kwsantiago merged 2 commits into
mainfrom
nip17-fail-closed

Conversation

@kwsantiago

@kwsantiago kwsantiago commented Aug 3, 2026 •

Copy link
Copy Markdown
Contributor

Summary

random_timestamp_past_two_days() returned the exact current time when RAND_bytes failed. It now propagates the error and both callers abort.

Why this is a real weakening, not a nit

NIP-17 back-dates seals and gift wraps by a random offset for one reason: so a relay observer cannot correlate send times. Collapsing to now() on RNG failure removes exactly that property, and removes it silently. The event still builds, still validates, still sends. The only observable difference is that the timing metadata the construction exists to hide is published in the clear.

Same shape as the RNG defects fixed in #63: a failure path that returns a plausible value instead of an error, so nothing downstream can tell the difference.

Both call sites, the seal at nip17.c:121 and the gift wrap at :236, now destroy the partially built event, null the out-param, and return the error rather than emitting an event whose timestamp is not fuzzed.

On the error code

Returns NOSTR_ERR_MEMORY, which is what key.c:229 and event.c:627 already return for an RNG failure. Semantically loose for this case, but consistent with the codebase, and a dedicated code would be a public enum change that belongs in its own commit rather than riding along here.

I first wrote NOSTR_ERR_CRYPTO_FAILED, which does not exist. The compiler caught it; worth noting because the fix was to read what the codebase actually does rather than to invent what it ought to.

Test plan

  • Compiles clean
  • Both call sites verified to propagate; grep for return now; returns 0, so no path emits an unfuzzed timestamp
  • Full suite: 15/15 pass
  • openssl/err.h added for ERR_clear_error, matching how the OpenSSL branch in key.c clears the error queue after a failed draw
  • CI

Closes libnostr-c-lp6.

Summary by CodeRabbit

  • Bug Fixes
    • Improved reliability when secure timestamp generation fails.
    • Prevented incomplete seal and gift-wrap events from being returned after an internal error.
    • Enhanced error handling to avoid using fallback timestamps in failure scenarios.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@kwsantiago, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 51 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 96c1af54-2dac-4f86-97f2-1e433690ac22

📥 Commits

Reviewing files that changed from the base of the PR and between 0ac48c8 and fbd0316.

📒 Files selected for processing (1)
  • src/nip17.c

Walkthrough

NIP-17 timestamp generation now fails with NOSTR_ERR_MEMORY when randomization fails. Seal and gift-wrap creation propagate the error, destroy partial events, and clear output pointers.

Changes

NIP-17 error handling

Layer / File(s) Summary
Error-aware timestamp generation
src/nip17.c
The timestamp helper returns nostr_error_t, clears OpenSSL errors after RNG failure, and no longer uses the current time as a fallback.
Creation failure propagation
src/nip17.c
Seal and gift-wrap creation destroy partial events, clear output pointers, and return timestamp-generation failures.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

A rabbit checks the random seed,
No clock fallback meets the need.
If errors hop from OpenSSL,
Partial wraps depart as well.
Null pointers mark the halt.

🚥 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 clearly summarizes the main change: fail closed when NIP-17 timestamp fuzzing fails.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch nip17-fail-closed

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.

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/nip17.c`:
- Around line 121-126: The timestamp-failure cleanup paths in src/nip17.c lines
121-126 and 236-241 must release all acquired resources before returning: in the
first path, free encrypted_rumor after destroying the partial seal; in the
second path, free encrypted_seal and wipe ephemeral_privkey before returning.
Update the corresponding cleanup logic around the affected seal/event
construction functions while preserving the existing error returns.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 136527a3-006b-4c35-8a96-d1b2072efb08

📥 Commits

Reviewing files that changed from the base of the PR and between b115744 and 0ac48c8.

📒 Files selected for processing (1)
  • src/nip17.c

Comment thread src/nip17.c
@kwsantiago
kwsantiago merged commit 3a61e60 into main Aug 3, 2026
13 checks passed
@kwsantiago
kwsantiago deleted the nip17-fail-closed branch August 3, 2026 02:02
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