CVE-2026-25742 Overview
CVE-2026-25742 is an authorization bypass vulnerability affecting Zulip, an open-source team collaboration tool. The vulnerability exists in versions 1.4.0 through 11.5, where disabling spectator access (enable_spectator_access / WEB_PUBLIC_STREAMS_ENABLED) fails to properly revoke anonymous access to attachments and topic history from web-public streams. This missing authorization check (CWE-862) allows continued retrieval of file contents and topic metadata even after administrators have disabled public access.
Critical Impact
Sensitive file attachments and topic history from previously web-public streams remain accessible to anonymous users after spectator access is disabled, potentially exposing confidential organizational communications and documents.
Affected Products
- Zulip versions 1.4.0 through 11.5
- Zulip installations with web-public streams that have been subsequently disabled
- Self-hosted Zulip deployments with spectator access configuration changes
Discovery Timeline
- 2026-04-03 - CVE CVE-2026-25742 published to NVD
- 2026-04-08 - Last updated in NVD database
Technical Details for CVE-2026-25742
Vulnerability Analysis
The vulnerability stems from incomplete state management when toggling spectator access settings. When an administrator disables spectator access via the enable_spectator_access setting, Zulip failed to properly invalidate the cached is_web_public attribute on existing attachments. This architectural oversight meant that file attachments uploaded to web-public streams retained their public accessibility status despite the policy change.
Additionally, the /users/me/<stream_id>/topics endpoint lacked proper authentication enforcement when spectator access was disabled. The endpoint continued to serve topic history for streams that were previously configured as web-public, allowing anonymous users to enumerate conversation topics and potentially gain insight into organizational discussions.
The vulnerability has network-based exploitability with low attack complexity, requiring no privileges or user interaction. While the impact is limited to confidentiality exposure rather than system compromise, organizations handling sensitive information in Zulip channels face data exposure risks.
Root Cause
The root cause is CWE-862 (Missing Authorization), where the application fails to properly check authorization when the spectator access policy changes. Specifically, the Attachment and ArchivedAttachment objects retained their is_web_public flag even after the realm-level setting was disabled, and the topics endpoint did not validate that web-public streams were still enabled before serving data to anonymous users.
Attack Vector
An attacker with knowledge of attachment URLs or stream IDs from a Zulip instance can anonymously retrieve files and topic history even after the organization has disabled public access. The attack requires:
- Knowledge of attachment paths (e.g., from cached links, search engine indexing, or prior access)
- Stream IDs for querying the topics endpoint
- No authentication credentials are required
# Security patch in zerver/actions/realm_settings.py
# Source: https://github.com/zulip/zulip/commit/3c045414299680b9f5dca7d76cf6cef6121c0236
setattr(realm, name, value)
realm.save(update_fields=[name])
+ if name == "enable_spectator_access":
+ Attachment.objects.filter(realm=realm).update(is_web_public=None)
+ # We need to do the same for ArchivedAttachment to avoid
+ # bugs if deleted attachments are later restored.
+ ArchivedAttachment.objects.filter(realm=realm).update(is_web_public=None)
+
event = dict(
type="realm",
op="update",
The patch properly resets the is_web_public attribute on all attachments when spectator access is disabled, ensuring the policy change takes immediate effect.
# Security patch in zerver/actions/uploads.py
# Source: https://github.com/zulip/zulip/commit/3c045414299680b9f5dca7d76cf6cef6121c0236
if is_channel_message:
stream = Stream.objects.get(id=message.recipient.type_id)
is_message_realm_public = stream.is_public()
- is_message_web_public = stream.is_web_public
+ is_message_web_public = (
+ user_profile.realm.web_public_streams_enabled() and stream.is_web_public
+ )
if not validate_attachment_request(user_profile, path_id)[0]:
# Technically, there are 2 cases here:
This patch adds a runtime check to verify that web-public streams are actually enabled at the realm level before granting anonymous access to attachments.
Detection Methods for CVE-2026-25742
Indicators of Compromise
- Anonymous HTTP requests to attachment URLs (e.g., /user_uploads/) without valid session cookies
- Unauthenticated requests to /users/me/<stream_id>/topics endpoints
- Unusual traffic patterns to file attachment paths from external IP addresses
- Access log entries showing successful file retrievals without authenticated sessions
Detection Strategies
- Monitor web server access logs for requests to /user_uploads/ paths that return 200 status codes without associated session authentication
- Implement rate limiting and alerting on the /users/me/*/topics endpoint for unauthenticated requests
- Review Zulip audit logs for recent changes to spectator access settings followed by continued anonymous access patterns
- Deploy web application firewall rules to flag anonymous access attempts to sensitive endpoints
Monitoring Recommendations
- Enable verbose logging on Zulip's file serving endpoints to track authentication status
- Set up alerts for bulk file access patterns from single IP addresses
- Monitor for search engine crawler activity that may have indexed previously public content
- Regularly audit attachment access logs after disabling spectator access to verify policy enforcement
How to Mitigate CVE-2026-25742
Immediate Actions Required
- Upgrade Zulip to version 11.6 or later immediately
- If running affected versions, assume all attachments from previously web-public streams may have been accessed
- Review access logs for unauthorized file retrievals since disabling spectator access
- Consider rotating or re-uploading sensitive attachments that may have been exposed
Patch Information
The vulnerability has been patched in Zulip version 11.6. Two commits address the issue:
- Commit 3c045414 - Resets attachment public status when disabling spectator access
- Commit 41e23347 - Adds MissingAuthenticationError check for topics endpoint
For detailed information, see the GitHub Security Advisory GHSA-f47p-xjqq-g28w and the Zulip 11.6 Release Notes.
Workarounds
- Temporarily block anonymous access at the reverse proxy or load balancer level by requiring authentication for all requests
- Implement IP-based access restrictions to limit who can access the Zulip instance
- Delete and re-upload sensitive attachments after upgrading to regenerate attachment paths
- Consider temporarily taking the Zulip instance offline if highly sensitive data is at risk until the upgrade is complete
# Configuration example - Nginx reverse proxy workaround
# Block anonymous access to attachment and topics endpoints until patched
location /user_uploads/ {
# Require authentication for all attachment requests
auth_request /auth-check;
proxy_pass http://zulip-backend;
}
location ~ ^/users/me/[0-9]+/topics$ {
# Require authentication for topics endpoint
auth_request /auth-check;
proxy_pass http://zulip-backend;
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.


