This commit is contained in:
areebahmeddd 2026-07-31 09:11:00 +05:30
parent d1af88617b
commit c836b10d68
No known key found for this signature in database
GPG Key ID: 3246A173263AD93A
2 changed files with 6 additions and 15 deletions

View File

@ -77,20 +77,11 @@ final class GroupStore: ObservableObject {
!group.members.isEmpty,
group.members.count <= BitchatGroup.maxMembers,
group.creator != nil else { return false }
// A group keeps the creator it was created with.
//
// `applyGroupState` checks that the sender is the creator the state
// NAMES, that the creator signature verifies, that we are still in the
// roster, and that the epoch does not regress but nothing compares the
// creator against the group we already hold. Each check passes for an
// attacker who simply names themselves creator of an existing groupID at
// a higher epoch and signs with their own key, and the roster and key are
// then replaced wholesale. Members would seal their next message under a
// key the attacker holds, while the real group silently stops seeing
// them; nothing in the UI changes.
//
// Pinning here rather than in `applyGroupState` because this is the one
// point every write goes through, local and remote alike.
// A group keeps the creator it was created with. `applyGroupState`
// checks the sender is the creator the state NAMES, but never against
// the creator already stored, so a peer naming themselves creator of a
// known groupID at a higher epoch replaces the roster and key wholesale.
// Pinned here, the one point every write goes through.
if let existing = groups.first(where: { $0.groupID == group.groupID }),
existing.creatorFingerprint != group.creatorFingerprint {
SecureLogger.warning("Refusing group state that changes the creator of an existing group", category: .security)

View File

@ -92,7 +92,7 @@ struct GroupStoreTests {
#expect(store.updateRoster(groupID: group.groupID, members: [creator, me]) != nil)
let realKey = try #require(store.key(forGroupID: group.groupID))
// Same groupID, same name, higher epoch, attacker as creator every
// Same groupID, same name, higher epoch, attacker as creator. Every
// other check in applyGroupState passes for this.
let hijack = BitchatGroup(
groupID: group.groupID,