CVE-2025-47930 Overview
CVE-2025-47930 is an authorization bypass vulnerability in Zulip, an open-source team chat application. The flaw affects Zulip versions 10.0 through 10.2 and allows authenticated users to circumvent the "Who can create public channels" access control. An attacker with an ordinary user account can create a private or web-public channel, then modify its privacy setting to public. A similar technique bypasses restrictions on creating private channels, though it requires direct API calls or HTML manipulation because the client marks the private radio button as disabled. Zulip version 10.3 contains the patch. The weakness is categorized under CWE-863: Incorrect Authorization.
Critical Impact
Authenticated users can create channels of any privacy type regardless of organization-configured permissions, undermining administrative access controls.
Affected Products
- Zulip Server 10.0
- Zulip Server 10.1
- Zulip Server 10.2
Discovery Timeline
- 2025-05-16 - CVE-2025-47930 published to NVD
- 2026-06-17 - Last updated in NVD database
Technical Details for CVE-2025-47930
Vulnerability Analysis
The vulnerability resides in the channel update logic in zerver/views/streams.py. Zulip enforces permission checks on the channel creation endpoint, verifying whether a user holds the can_create_public_streams or can_create_private_streams role. However, the channel update endpoint did not perform the equivalent check when a user changed the privacy setting of an existing channel.
An attacker with permission to create at least one channel type can chain two operations. First, they create a channel of a permitted privacy level. Second, they issue an update request that toggles the is_private attribute to the restricted level. The absence of a re-check on the update path allows the transition to succeed, effectively producing a channel the user was never authorized to create.
Root Cause
The root cause is missing authorization enforcement on a state-changing operation. The creation flow validated caller privileges, but the update flow trusted that the initial permission check was sufficient. This design assumption fails because channel privacy is a policy-governed attribute rather than an immutable property.
Attack Vector
Exploitation requires network access and a low-privilege authenticated Zulip account within the target organization. No user interaction from an administrator is needed. The public-channel bypass works through the standard web UI, while the private-channel bypass requires API access or client-side modification because the UI disables the private option.
# public/private status for channels requires content access
# to the channel.
+ if is_private is not None:
+ if is_private and not user_profile.can_create_private_streams():
+ raise JsonableError(_("Insufficient permission"))
+
+ if not is_private and not user_profile.can_create_public_streams():
+ raise JsonableError(_("Insufficient permission"))
+
# Enforce restrictions on creating web-public streams. Since these
# checks are only required when changing a stream to be
# web-public, we don't use an "is not None" check.
Source: Zulip security patch commit d2ff4bd. The patch adds explicit calls to can_create_private_streams() and can_create_public_streams() when the update payload includes an is_private change, mirroring the checks already present in the creation path.
Detection Methods for CVE-2025-47930
Indicators of Compromise
- Channel objects whose privacy setting changed shortly after creation by a user without matching creation permissions.
- API PATCH requests to /json/streams/{stream_id} containing an is_private parameter from non-privileged accounts.
- New public channels owned or created by users whose role only permits private channel creation.
Detection Strategies
- Correlate Zulip audit log entries for channel creation and subsequent privacy updates by the same user within short time windows.
- Compare each channel privacy transition against the acting user's can_create_public_streams and can_create_private_streams role at the time of the change.
- Alert on channel update API traffic that toggles is_private when the source account lacks the target creation permission.
Monitoring Recommendations
- Ingest Zulip server access logs and RealmAuditLog events into a centralized logging or SIEM platform.
- Baseline expected channel administrators and flag channel privacy changes originating from accounts outside that set.
- Review web-public channel creation events, since these carry the broadest exposure surface.
How to Mitigate CVE-2025-47930
Immediate Actions Required
- Upgrade Zulip Server to version 10.3 or later, which contains the patch.
- Audit existing channels created between the deployment of version 10.0 and the upgrade for unexpected privacy transitions.
- Review and, where required, tighten the "Who can create public channels" and "Who can create private channels" organization settings.
Patch Information
The fix is delivered in Zulip Server 10.3 via commit d2ff4bd. Full technical details are documented in the GitHub Security Advisory GHSA-rqg7-xfqg-v7q5.
Workarounds
- Restrict channel creation permissions to trusted administrators using the Zulip channel permission settings until the upgrade is applied.
- Manually revert unauthorized channel privacy changes identified during log review.
- Monitor the RealmAuditLog for channel property updates and revoke privileges from accounts observed abusing the bypass.
# Upgrade Zulip Server to the patched release
sudo /home/zulip/deployments/current/scripts/upgrade-zulip-from-git 10.3
# Verify installed version
/home/zulip/deployments/current/manage.py print_initial_password --version
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

