VYPR
High severityNVD Advisory· Published Mar 26, 2024· Updated Aug 7, 2024

CVE-2024-25421

CVE-2024-25421

Description

CVE-2024-25421 is an improper access control vulnerability in Ignite Realtime Openfire that allows privilege escalation via the ROOM_CACHE component.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

CVE-2024-25421 is an improper access control vulnerability in Ignite Realtime Openfire that allows privilege escalation via the ROOM_CACHE component.

Vulnerability

Description CVE-2024-25421 is an improper access control vulnerability in Ignite Realtime Openfire versions up to and including 4.9.0. The root cause lies in the ROOM_CACHE component, which fails to update cached user affiliations when a user is deleted from the system [2]. When a user is added to a group chat, their membership and associated privileges are stored in the cache. Deleting that user does not clear the cached data, leaving the old affiliation intact [2].

Exploitation

An attacker can exploit this vulnerability by first registering a new user with the same username as a previously deleted group chat member. Because the cache still holds the original user's affiliation, the new user automatically inherits the privileges that belonged to the deleted user. This privilege escalation can be performed without requiring administrative access to the Openfire web panel; the attacker only needs the ability to create an XMPP account with the matching username [2].

Impact

Successful exploitation grants the attacker unauthorized access to group chat rooms with the same level of privileges that the deleted user had. This could include reading private conversations, sending messages, or accessing restricted rooms. The vulnerability is similar in nature to CVE-2024-25420, which affects administrative user privileges, but here the attack vector targets group chat rooms via the ROOM_CACHE [2].

Mitigation

As of the latest information, the vulnerability affects Openfire versions 4.9.0 and earlier. Users should upgrade to a patched version if available; the official Openfire download page shows version 5.0.5 as the latest release as of May 2026 [1]. Administrators can also mitigate the risk by ensuring that deleted user accounts are not reused and by monitoring for unauthorized account creation with existing usernames.

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.igniterealtime.openfire:xmppserverMaven
< 4.8.14.8.1

Affected products

2

Patches

1
d66bddd29dbf

OF-2795 / OF-2166: Remove MUC affiliation of a user that is being deleted. (#2420)

https://github.com/igniterealtime/openfireGuus der KinderenFeb 29, 2024via ghsa
3 files changed · +55 13
  • xmppserver/src/main/java/org/jivesoftware/openfire/muc/MUCRoom.java+47 2 modified
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (C) 2004-2008 Jive Software, 2016-2022 Ignite Realtime Foundation. All rights reserved.
    + * Copyright (C) 2004-2008 Jive Software, 2016-2024 Ignite Realtime Foundation. All rights reserved.
      *
      * Licensed under the Apache License, Version 2.0 (the "License");
      * you may not use this file except in compliance with the License.
    @@ -24,8 +24,10 @@
     import org.jivesoftware.openfire.XMPPServer;
     import org.jivesoftware.openfire.auth.UnauthorizedException;
     import org.jivesoftware.openfire.event.GroupEventListener;
    +import org.jivesoftware.openfire.event.UserEventListener;
     import org.jivesoftware.openfire.group.*;
     import org.jivesoftware.openfire.muc.spi.*;
    +import org.jivesoftware.openfire.user.User;
     import org.jivesoftware.openfire.user.UserAlreadyExistsException;
     import org.jivesoftware.openfire.user.UserNotFoundException;
     import org.jivesoftware.util.*;
    @@ -48,6 +50,7 @@
     import java.time.temporal.ChronoUnit;
     import java.util.*;
     import java.util.concurrent.*;
    +import java.util.concurrent.locks.Lock;
     import java.util.stream.Collectors;
     
     /**
    @@ -61,7 +64,7 @@
      * @author Guus der Kinderen, guus@goodbytes.nl
      */
     @JiveID(JiveConstants.MUC_ROOM)
    -public class MUCRoom implements GroupEventListener, Externalizable, Result, Cacheable {
    +public class MUCRoom implements GroupEventListener, UserEventListener, Externalizable, Result, Cacheable {
     
         private static final Logger Log = LoggerFactory.getLogger(MUCRoom.class);
     
    @@ -3817,4 +3820,46 @@ private void applyAffiliationChangeAndSendPresence(JID groupMember) {
         public void groupCreated(Group group, Map params) {
             // ignore
         }
    +
    +    @Override
    +    public void userCreated(User user, Map<String, Object> params)
    +    {}
    +
    +    @Override
    +    public void userDeleting(User user, Map<String, Object> params)
    +    {
    +        // When a user is being deleted, all its affiliations need to be removed from chat rooms (OF-2166). Note that
    +        // this event handler only works for rooms that are loaded into memory from the database. Corresponding code
    +        // in MultiUserChatManager will remove affiliations from rooms that are not in memory, but only in the database.
    +        final JID userJid = XMPPServer.getInstance().createJID(user.getUsername(), null);
    +
    +        final Lock lock = getMUCService().getChatRoomLock(getJID().getNode());
    +        try {
    +            lock.lock();
    +
    +            if (getAffiliation(userJid) == MUCRole.Affiliation.none) {
    +                // User had no affiliation with this room.
    +                return;
    +            }
    +
    +            // Cannot remove the last owner of a chat room. To prevent issues, replace the owner with an administrative account.
    +            if (getOwners().contains(userJid) && getOwners().size() == 1) {
    +                final JID adminJid = XMPPServer.getInstance().getAdmins().iterator().next();
    +                Log.info("User '{}' is being deleted, but is also the only owner of MUC room '{}'. To prevent having a room without owner, server admin '{}' was made owner of the room.", user.getUsername(), getJID(), adminJid);
    +                addOwner(adminJid, getRole());
    +            }
    +
    +            // Remove the affiliation of the deleted user with the room
    +            addNone(userJid, getRole());
    +            getMUCService().syncChatRoom(this);
    +        } catch (Throwable t) {
    +            Log.warn("A problem occurred while trying to update room '{}' as a result of user '{}' being deleted from Openfire.", getJID(), user);
    +        } finally {
    +            lock.unlock();
    +        }
    +    }
    +
    +    @Override
    +    public void userModified(User user, Map<String, Object> params)
    +    {}
     }
    
  • xmppserver/src/main/java/org/jivesoftware/openfire/muc/MultiUserChatManager.java+3 2 modified
    @@ -951,10 +951,11 @@ public void userCreated(User user, Map<String, Object> params) {
     
         @Override
         public void userDeleting(User user, Map<String, Object> params) {
    -        // Delete any affiliation of the user to any room of any MUC service
    +        // When a user is being deleted, all its affiliations need to be removed from chat rooms (OF-2166). Note that
    +        // every room is an event listener for the same event, which should update rooms that are loaded into memory
    +        // from the database. This event handler intends to update rooms that are not in memory, but only in the database.
             MUCPersistenceManager
                     .removeAffiliationFromDB(XMPPServer.getInstance().createJID(user.getUsername(), null, true));
    -        // TODO Delete any user information from the rooms loaded into memory (OF-2166)
         }
     
         @Override
    
  • xmppserver/src/main/java/org/jivesoftware/openfire/muc/spi/LocalMUCRoomManager.java+5 9 modified
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (C) 2016-2023 Ignite Realtime Foundation. All rights reserved.
    + * Copyright (C) 2016-2024 Ignite Realtime Foundation. All rights reserved.
      *
      * Licensed under the Apache License, Version 2.0 (the "License");
      * you may not use this file except in compliance with the License.
    @@ -20,6 +20,7 @@
     import org.jivesoftware.openfire.cluster.ClusteredCacheEntryListener;
     import org.jivesoftware.openfire.cluster.NodeID;
     import org.jivesoftware.openfire.event.GroupEventDispatcher;
    +import org.jivesoftware.openfire.event.UserEventDispatcher;
     import org.jivesoftware.openfire.muc.MUCRole;
     import org.jivesoftware.openfire.muc.MUCRoom;
     import org.jivesoftware.openfire.muc.MultiUserChatService;
    @@ -36,14 +37,7 @@
     import javax.annotation.Nonnull;
     import javax.annotation.Nullable;
     import java.time.Duration;
    -import java.util.Collection;
    -import java.util.Collections;
    -import java.util.Date;
    -import java.util.HashMap;
    -import java.util.HashSet;
    -import java.util.List;
    -import java.util.Map;
    -import java.util.Set;
    +import java.util.*;
     import java.util.concurrent.locks.Lock;
     import java.util.stream.Collectors;
     
    @@ -160,6 +154,7 @@ void add(@Nonnull final MUCRoom room)
             }
     
             GroupEventDispatcher.addListener(room); // TODO this event listener is added only in the node where the room is created. Does this mean that events are not propagated in a cluster?
    +        UserEventDispatcher.addListener(room);
         }
     
         /**
    @@ -234,6 +229,7 @@ MUCRoom remove(@Nonnull final String roomName)
                 if (room != null) {
                     room.getRoomHistory().purge();
                     GroupEventDispatcher.removeListener(room);
    +                UserEventDispatcher.removeListener(room);
                     updateNonPersistentRoomStat(room, null);
                 }
                 localRooms.remove(roomName);
    

Vulnerability mechanics

Root cause

"Missing cleanup of MUC room affiliations for in-memory rooms when a user is deleted, allowing a new user with the same username to inherit the deleted user's privileges."

Attack vector

An attacker can register a new account using the same username as a previously deleted user who held MUC room affiliations (e.g., owner, admin, member). Because the old affiliations were not removed from in-memory rooms, the new user inherits those privileges. The attack requires the ability to create a user account on the Openfire server and knowledge of a deleted user's username that had MUC room affiliations. No special network position is needed beyond normal XMPP client access. [CWE-863]

Affected code

The vulnerability resides in the MUC room affiliation handling within `MUCRoom.java` and `MultiUserChatManager.java`. When a user is deleted, `MultiUserChatManager.userDeleting()` only removed the affiliation from the database but did not update rooms already loaded in memory (the TODO comment in the diff confirms this gap). The `MUCRoom` class did not implement `UserEventListener`, so in-memory rooms never received the deletion event.

What the fix does

The patch makes `MUCRoom` implement `UserEventListener` and registers it via `UserEventDispatcher.addListener(room)` in `LocalMUCRoomManager`. When a user is deleted, the new `userDeleting()` method in `MUCRoom` checks if the user has an affiliation with that room, handles the edge case of a sole owner (replacing with an admin), and removes the affiliation via `addNone()`. The corresponding code in `MultiUserChatManager.userDeleting()` is updated to clarify that it now only handles database-only rooms, while in-memory rooms handle themselves. [patch_id=1708717]

Preconditions

  • authAttacker must be able to create a new user account on the Openfire server
  • configA previously deleted user must have had MUC room affiliations (owner, admin, member, etc.) that were not cleaned up
  • configThe MUC room must have been loaded into memory at the time of the original user's deletion

Generated on May 23, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.