Coordinated Disclosure Timeline

Summary

Signal for Android versions >= v8.1.0 and < v8.3.0 are affected by a vulnerability (GHSL-2026-082) where an attacker can exploit improperly validated group context within the Admin Delete message handler, leading to unauthorized message deletion.

Project

Signal-Android

Tested Version

v8.2.2

Details

Attacker-controlled group context in the Admin Delete message handler (GHSL-2026-082)

Admin Delete is a new group moderation feature intended to allow group administrators to delete unwanted messages. While at the moment of reporting it is not available in the UI, the RemoteConfig.receiveAdminDelete server flag is already enabled and handled in the publicly available v8.2.2 Signal app. A malicious custom (or modified) client can craft and send a custom message packet with an Admin Delete request.

The handleAdminRemoteDelete function does not validate that the target message being deleted belongs to the same group/thread where the sender claims admin status.

The isValidAdminDeleteReceive function only checks that the sender is an admin of the provided group record and the timing is valid — it never verifies the target message belongs to that group.

Contrast with properly secured code:

Attack Scenario:

  1. Attacker Alice is admin of Group A and a regular (non-admin) member of Group B. Both groups include the victim.
  2. Bob sends a message M in Group B at timestamp T. Alice sees M and knows T and Bob’s ACI since she’s in Group B.
  3. Alice crafts a DataMessage with: groupV2 pointing to Group A (where she IS admin), and adminDelete { targetSentTimestamp=T, targetAuthorAciBinary=Bob's ACI }.
  4. On the victim’s device:
  fun handleAdminRemoteDelete(context: Context, envelope: Envelope, message: DataMessage, senderRecipient: Recipient, threadRecipient: Recipient, earlyMessageCacheEntry: EarlyMessageCacheEntry?): MessageId? {
    if (!RemoteConfig.receiveAdminDelete) {
      log(envelope.timestamp!!, "Admin delete is not allowed due to remote config.")
      return null
    }

    val delete = message.adminDelete!!

    log(envelope.timestamp!!, "Admin delete for message ${delete.targetSentTimestamp}")

    val targetSentTimestamp: Long = delete.targetSentTimestamp!!
    val targetAuthorServiceId: ServiceId = ACI.parseOrThrow(delete.targetAuthorAciBinary!!)
    if (targetAuthorServiceId.isUnknown) {
      warn(envelope.timestamp!!, "[handleAdminRemoteDelete] Invalid author.")
      return null
    }
    val targetAuthor = Recipient.externalPush(targetAuthorServiceId)

    val targetMessage: MessageRecord? = SignalDatabase.messages.getMessageFor(targetSentTimestamp, targetAuthor.id) // <------- [1]

    val groupRecord = SignalDatabase.groups.getGroup(threadRecipient.id).orNull() // <------- [2]
    if (groupRecord == null || !groupRecord.isV2Group) {
      warn(envelope.timestamp!!, "[handleAdminRemoteDelete] Invalid group.")
      return null
    }

    return if (targetMessage != null && MessageConstraintsUtil.isValidAdminDeleteReceive(targetMessage, senderRecipient, envelope.serverTimestamp!!, groupRecord)) { // <------- [3]
      SignalDatabase.messages.markAsRemoteDelete(targetMessage, senderRecipient.id) // <------- [4]
      // ...
    } else if (targetMessage == null) {
      // ...
    } else {
    // ...
    }
  }

Attacker must know the exact dateSent timestamp and author ACI of the target message, which is feasible when the attacker is a member of the target group (can observe messages) or in 1:1 with the target author.

Impact

Admin privilege in one group can be leveraged to delete messages from any other conversation on the victim’s device (other groups, or even 1:1 conversations if the timestamp and author match).

CWEs

Credit

This issue was discovered with the GitHub Security Lab Taskflow Agent and verified by GHSL team member @JarLob (Jaroslav Lobačevski).

Contact

You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2026-082 in any communication regarding this issue.