Skip to content

Bug: GROUP_INVITE TTL overflow when > ~24.8 days produces past expiry timestamps #288

Description

@QuickMythril

Summary

Group invite TTLs are stored as seconds in an int, but expiry is computed using timeToLive * 1000 with int arithmetic. For TTL values greater than Integer.MAX_VALUE / 1000 (~2,147,483 seconds ≈ 24.85 days), the multiplication overflows and produces a negative millisecond offset. The resulting expires_when is in the past, so invites can appear immediately expired and any UI/API that interprets expiry will show incorrect results.

This is currently reachable from Qortal Hub, which offers a 30‑day invite TTL (2,592,000 seconds).

Steps to Reproduce

  1. In Qortal Hub → Groups → Invite Member, select “30 days” expiry (2,592,000 seconds).
  2. Invite any address.
  3. Query /groups/invites/group/{groupId} or /groups/invites/{address} and inspect expires_when.

Expected

expires_when = inviteTimestamp + inviteTime * 1000
For 30 days, expiry should be ~30 days in the future.

Actual

expires_when is ~19.7 days in the past (because timeToLive * 1000 overflows int), so the stored expiry is wrong and can be interpreted as already expired.

Example math:

timeToLive = 2,592,000
timeToLive * 1000 (int) = 2,592,000,000 -> overflows to -1,702,967,296
expiry = timestamp + (-1,702,967,296)

Root Cause / Code References

  • src/main/java/org/qortal/group/Group.java
    • Invite expiry: expiry = groupInviteTransactionData.getTimestamp() + timeToLive * 1000;
    • Ban expiry uses the same pattern: expiry = groupBanTransactionData.getTimestamp() + timeToLive * 1000;
  • src/main/java/org/qortal/transaction/GroupInviteTransaction.java
    • TTL validation only checks < 0, so large TTLs are accepted.
  • src/main/java/org/qortal/data/transaction/GroupInviteTransactionData.java
    • timeToLive is int.

User Impact

  • Invites with TTL > ~24.85 days are stored as expired in the past.
  • UI/API clients that display or filter by expiry will show invites as already expired.
  • If expiry enforcement/cleanup is added later, these invites could be immediately removed/ignored.
  • Same overflow pattern likely affects group bans with TTL (if/when used).

Suggested Fixes

  1. Use long arithmetic before multiplying to avoid overflow:
    • expiry = timestamp + (long) timeToLive * 1000L;
    • Apply to both invite and ban expiry in Group.java.
  2. Optionally validate upper bounds in GroupInviteTransaction.isValid() (and GroupBan if TTL is used) to prevent unrealistic TTLs, or clamp to a safe max.
  3. Add regression tests:
    • TTL = 2,592,000 should produce expiry in the future.
    • TTL = 0 should result in null expiry (no expiration).

Notes

  • The default TTL used in Qortal Hub is 3 days (259,200 seconds), which is safe, but Hub also offers 30 days (2,592,000 seconds), which triggers the overflow.
  • Simply switching to long arithmetic removes the overflow without changing on-chain formats.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions