NIP-59 gift wraps may be rejected under strict createdAtSecondsPast config #3

Open
opened 2026-05-03 13:41:28 +00:00 by padreug · 0 comments
Owner

Problem

NIP-59 (Gift Wrap) instructs clients to randomise created_at up to 2
days in the past for metadata protection (timing-correlation defense).
Our EventValidator._created_at_in_range applies a single
operator-configured past-window to all kinds:

# relay/event_validator.py:127
if created_at < (current_time - self.config.created_at_in_past):
    return False, "created_at is too much into the past"

Default is 0 (unlimited past) so gift wraps work out of the box, but
any operator who sets a strict NIP-22 past-window — say "1 hour" to
suppress historical replays — will silently break NIP-17 messaging on
their relay.

Suggested approach

Either:

  1. Per-kind exemption list (config-driven). Operators can list kinds
    that bypass the past-window check; default to [1059].
  2. Hardcoded floor. For kind == 1059, raise the past-window to at
    least 2 days × 1.1 (≈4 hours of slack) regardless of config.

Option 1 is more flexible; option 2 is cheaper to implement and matches
the spirit of NIP-59 without operator effort.

Survey

Surveyed relays don't special-case 1059 timestamps either:

  • strfry: no kind-specific timestamp logic
  • khatru: PreventTimestampsInThePast(threshold) policy applies uniformly
  • nostream: generic window only

So this is a quality-of-life improvement we'd lead on, not a spec gap.

Out of scope

Deferred from #PR-feat-nip17-gift-wrap-support. Not blocking the default
nostrmarket NIP-17 flow because the default config has no past-window.

## Problem NIP-59 (Gift Wrap) instructs clients to randomise `created_at` up to 2 days in the past for metadata protection (timing-correlation defense). Our `EventValidator._created_at_in_range` applies a single operator-configured past-window to **all** kinds: ```python # relay/event_validator.py:127 if created_at < (current_time - self.config.created_at_in_past): return False, "created_at is too much into the past" ``` Default is `0` (unlimited past) so gift wraps work out of the box, but any operator who sets a strict NIP-22 past-window — say "1 hour" to suppress historical replays — will silently break NIP-17 messaging on their relay. ## Suggested approach Either: 1. **Per-kind exemption list** (config-driven). Operators can list kinds that bypass the past-window check; default to `[1059]`. 2. **Hardcoded floor**. For `kind == 1059`, raise the past-window to at least 2 days × 1.1 (≈4 hours of slack) regardless of config. Option 1 is more flexible; option 2 is cheaper to implement and matches the spirit of NIP-59 without operator effort. ## Survey Surveyed relays don't special-case 1059 timestamps either: - strfry: no kind-specific timestamp logic - khatru: `PreventTimestampsInThePast(threshold)` policy applies uniformly - nostream: generic window only So this is a quality-of-life improvement we'd lead on, not a spec gap. ## Out of scope Deferred from #PR-feat-nip17-gift-wrap-support. Not blocking the default nostrmarket NIP-17 flow because the default config has no past-window.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
aiolabs/nostrrelay#3
No description provided.