java-topology/whitepaper/outreach/jami-daemon.md
russell@unturf.com 652608142a feat: close outreach doc gap — 276 docs (batches 11-16)
All projects with patches now have outreach docs. 276 new docs covering
CWE-407, CWE-312, CWE-362 across C, C++, Java, Python, Go, Rust, C#,
PHP, Ruby, JavaScript, Dart, Erlang, R, and more.

Outreach gap: 276 -> 0.
2026-04-15 13:57:42 -04:00

3.4 KiB
Raw Blame History

Jami Daemon — CWE-407 Disclosure Brief (jami-daemon)

2026-04-13 · Patch available — awaiting upstream merge

Finding

Two O(n²) defects in Jami daemon's conversation system. Both involve std::find on std::vector for membership testing where std::unordered_set or .count() on an existing set-like container would provide O(1) lookup.

The Defects

jami-daemon-0001 (PATCHED — MEDIUM): src/jamidht/conversation.cpp:783 in loadMessages()

std::vector<std::string> replies;
// For each message:
auto it = std::find(replies.begin(), replies.end(), message.at("reply-to"));  // O(R)
if (it == replies.end()) { replies.emplace_back(message.at("reply-to")); }
auto it = std::find(replies.begin(), replies.end(), message.at("id"));        // O(R)
if (it != replies.end()) { replies.erase(it); }

replies tracks reply-to references as a std::vector<std::string>. Every message checks membership and inserts/erases with O(R) linear scans, giving O(M*R) total cost where M = messages loaded and R = reply set size.

jami-daemon-0002 (PATCHED — MEDIUM): src/jamidht/conversation_module.cpp (three sites)

std::find(conv->info.members.begin(), conv->info.members.end(), peer)
    != conv->info.members.end()

Three call sites use std::find on conv->info.members (which already supports .count()) to test peer membership. Each fires during conversation sync and contact removal operations.

Complexity Proof

0001: At M=1,000 messages, R=200 replies:

  • Defective: 1,000 × 200 × 2 = 400,000 string comparisons
  • Fixed: 1,000 × 2 O(1) set operations = 2,000 operations
  • ~200× op reduction.

0002: At N=50 conversations, P=100 members each:

  • Defective: 50 × 100 = 5,000 comparisons per sync
  • Fixed: 50 × O(1) = 50 operations
  • ~100× op reduction.

Impact

Jami is a GNU communication platform providing encrypted messaging, video calls, and file sharing. Conversation history loading fires when a user opens or syncs a conversation. Large group conversations with hundreds of messages and reply threads hit the quadratic path in 0001. Conversation sync fires when peers reconnect, hitting 0002 for every conversation.

The Fix

0001: Replace std::vector<std::string> replies with std::unordered_set<std::string>:

std::unordered_set<std::string> replies;
replies.insert(message.at("reply-to"));   // O(1)
replies.erase(message.at("id"));          // O(1)

0002: Replace std::find(...) != end() with .count() > 0 on the existing container:

// Before: std::find(members.begin(), members.end(), peer) != members.end()
// After:  members.count(peer) > 0

Patch

Fix available: defects/jami-daemon/patch/0001.patch and defects/jami-daemon/patch/0002.patch

Two-patch set across conversation.cpp and conversation_module.cpp. 0001: ~200× speedup at 1,000 messages. 0002: ~100× speedup at 100 members.

What We Ask

Patches are ready for review.

  1. Confirm receipt and assign a GitLab issue reference (savoirfairelinux/jami-daemon).
  2. Assess severity — 0001 fires on every conversation load; 0002 fires on every peer sync.
  3. Coordinate a disclosure date — we are targeting 90 days from first contact.
  4. We will credit the Jami team in the public disclosure. Preferred acknowledgment format welcome.

Contact: see cover email. This brief is confidential until coordinated disclosure.