[libtacky / OMEMO] Disappearing message timer is exposed outside OMEMO 2 encryption #20
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
[libtacky / OMEMO] Disappearing message timer is exposed outside OMEMO 2 encryption
Severity: Minor
Issue ID: EPH-01i, EPH-CTRL
Date: November 4, 2026
Summary
libtacky sends the disappearing-message timer (
<ephemeral timer='N'/>) as a plaintext child of the XMPP<message/>stanza, outside the OMEMO 2 encrypted payload.Although the message content remains encrypted, the XMPP server and intermediaries can observe:
XEP-0466 §5 recommends placing the ephemeral element inside the encryption wrapper when one is available. OMEMO 2 supports such a wrapper through XEP-0420, but libtacky does not use it for the timer.
Testing confirmed:
Affected components:
tacky/xmpp/modules/ephemeral.tclRelated issue: EPH-01 (expired message content retained in local history). This is a separate metadata-disclosure issue.
Environment
8f62071, build 942f42a2f2/ v1.2.0-beta2b9e675dmain@example.local, libtacky application profilepeer2@example.localurn:xmpp:omemo:2)Preconditions
mainandpeer2are contacts with OMEMO enabled.Steps to Reproduce
Run:
bash setup/run_all.sh run_ephemeralSet a 5-second disappearing-message timer using
ephemeral set_timer.Send an OMEMO-encrypted message from
maintopeer2.Inspect the outgoing XMPP stanzas in the server log.
Check whether
<ephemeral/>appears inside or outside the encrypted payload.Expected Behavior
For OMEMO 2, the
<ephemeral/>element should be placed inside the encrypted XEP-0420 envelope so that the expiration interval is not exposed to the XMPP server.XEP-0466 v0.1.0 §5 recommends placing this element inside the encryption wrapper when using XEP-0373 or XEP-0420.
This is a privacy recommendation, not an explicitly documented product requirement.
Behavior for OMEMO 0.3, which lacks the same envelope mechanism, may require a separate design decision.
Actual Behavior
Run
d09e839c(evidence/stanzas_ephemeral_main_d09e839c.txt) captured the following.Timer configuration — 14:18:42 UTC
The client sent a plaintext timer configuration stanza containing:
Encrypted message — 14:18:44 UTC
The subsequent OMEMO 2 message contained:
The
<ephemeral/>element is a direct child of<message/>, appearing after</encrypted>rather than inside the encrypted envelope.The visible
<body/>contains the standard OMEMO fallback text, not the actual message content.The test confirmed that the original message text was not transmitted in plaintext.
Reproduction Rate
2/2 successful automated runs:
d09e839c8f7ef5beBoth runs confirmed plaintext exposure of the disappearing-message timer alongside OMEMO 2 encryption.
Root Cause
libtacky deliberately places the ephemeral timer outside the encrypted payload.
ephemeral.tcl:12-24documents that:<ephemeral/>is sent as a direct child of<message/>.The same implementation already supports reading the timer from either the encrypted OMEMO 2 envelope or the outer message stanza.
Consequently, the receiving side supports the recommended placement, but the sending side does not follow the XEP-0466 §5 recommendation for OMEMO 2.
Suggested Fix
For OMEMO 2: Move
<ephemeral/>into the encrypted XEP-0420 envelope, following XEP-0466 §5.The existing receiving implementation already supports extracting the timer from the encrypted envelope.
For OMEMO 0.3 and unencrypted conversations: Preserve the current behavior or document the metadata exposure as a protocol limitation, subject to a separate design decision.
Verification After Fix
<ephemeral/>is absent from the plaintext portion of the message.For physical-device verification, use build 94 on two iPhones and inspect outgoing stanzas through Settings → Account → Server → XML Console.
Evidence and Status
Evidence:
evidence/stanzas_ephemeral_main_d09e839c.txtevidence/stanzas_ephemeral_main_8f7ef5be.txtevidence/run_ephemeral_1.outevidence/run_ephemeral_2.outevidence/ephemeral.tcl_12-24.txtAutomated test:
autotests/metadata-audit/checks/run_ephemeral.pyTest report:
results/2026-11-04_invite_ephemeral.md, section 3.Verified:
2f42a2f2.Not verified:
Moved to another-im/libtacky#17: the fix belongs to libtacky. The evidence archive went with it.