CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-92HV-J533-69WC

GHSA-92HV-J533-69WC: Information Disclosure via ETag Conditional Matching in Wagtail CMS

Amit Schendel
Amit Schendel
Senior Security Researcher

Aug 21, 2026·7 min read·7 visits

Executive Summary (TL;DR)

Wagtail CMS evaluates HTTP ETag headers before enforcing authentication and authorization checks on document serve views, leaking whether specific documents match guessed SHA-1 hashes.

An information disclosure vulnerability in the document serving subsystem of Wagtail CMS allows unauthorized users to verify if private documents match guessed SHA-1 hashes due to improper order of authentication checks.

Vulnerability Overview

Wagtail CMS contains a document management subsystem that allows administrators and content creators to upload, manage, and serve files securely. This subsystem controls access to documents using permissions, group access restrictions, and password protection schemes to prevent unauthorized viewing of sensitive files. The default document-serving implementation relies on a central view to parse incoming document requests and verify whether the requesting user possesses the requisite privileges to download the resource.

The vulnerability within this subsystem is classified as CWE-280: Improper Handling of Insufficient Permissions or Privileges. It emerges from the system utilizing standard HTTP ETag header validation before verifying whether the user is authorized to access the file. The vulnerability exposes an information disclosure vector, functioning as a binary verification oracle that confirms whether a specific document has a given SHA-1 hash.

Because the request processing pipeline evaluates the document's file hash early, it exposes structural information. This order-of-operations security flaw bypasses access control mechanisms entirely under specific conditions. Security researchers and operators must understand the execution flow to identify where the logic breaks down inside the application framework.

Root Cause Analysis

To optimize bandwidth usage and reduce server load, Wagtail utilizes HTTP ETags for conditional caching. In Django applications, this is typically handled by the @etag decorator, which intercepts incoming HTTP GET requests containing validation headers such as If-None-Match or If-Match. The decorator executes an auxiliary database query to determine the file hash of the requested resource before executing the primary view function.

If the client-provided header matches the database-retrieved SHA-1 hash, Django halts further processing and immediately returns an HTTP 304 Not Modified status code. If the hashes do not match, Django passes execution to the target view function, which then runs security checks. Since the security and authentication checks reside entirely inside the view function rather than a pre-execution middleware layer, the HTTP status code differs based on whether the guessed hash is correct.

An unauthorized user can exploit this logical sequencing flaw. By submitting a request with a guessed hash, the user receives an HTTP 304 if the guess is correct, and an HTTP 302 or 403 if the guess is incorrect. This differential response behavior allows an attacker to systematically verify the presence and content of files on the system without authorization.

Code Analysis

In vulnerable versions of Wagtail, the serve view in wagtail/documents/views/serve.py is directly decorated with @etag(document_etag). The document_etag utility function executes a database query to retrieve the document hash using the document_id. This evaluation occurs before the permission checks are executed within the body of the serve function, leaving the validation step entirely bypassed in the matching branch.

# Vulnerable implementation
def document_etag(request, document_id, document_filename):
    Document = get_document_model()
    if hasattr(Document, "file_hash"):
        return (
            Document.objects.filter(id=document_id)
            .values_list("file_hash", flat=True)
            .first()
        )
 
@etag(document_etag)
def serve(request, document_id, document_filename):
    Document = get_document_model()
    doc = get_object_or_404(Document, id=document_id)
    # Authentication and permission checks occur below this point

The security patch, applied in commit 4f57d589dd81dca4306b5d45a7dce34c61087966, resolves the vulnerability by restructuring how the @etag decorator is evaluated. The patch removes the global decorator from the serve view. Instead, it defines an inner function named serve_local which is wrapped in @etag(get_etag). This inner function is executed only after all authentication, group access, and password validation checks have succeeded.

# Patched implementation (simplified excerpt)
def serve(request, document_id, document_filename):
    Document = get_document_model()
    doc = get_object_or_404(Document, id=document_id)
    # All authentication and permission checks are executed here first
 
    def get_etag(request):
        try:
            return doc.file_hash
        except AttributeError:
            return None
 
    @etag(get_etag)
    def serve_local(request):
        # File serving logic runs here
        return response
 
    return serve_local(request)

This code restructuring ensures that unauthorized requests are terminated during the initial execution of serve(), returning a redirect or permission-denied response before the serve_local inner function is invoked. Consequently, the conditional ETag evaluation is never executed for unauthorized requests, resolving the information disclosure vector.

Exploitation

To exploit this vulnerability, an attacker must identify the URL path of the document serving endpoint on the target Wagtail site. The default path pattern follows the structure /documents/<document_id>/<filename>. Since document IDs are typically sequential integers, an attacker can iterate through IDs to discover document records.

The attacker must construct a list of target SHA-1 file hashes. This list can include hashes of standard corporate templates, leaked files, known public forms, or software release binaries. The attacker sends a crafted HTTP GET request containing the targeted SHA-1 hash within the If-None-Match header.

If the server returns an HTTP 304 Not Modified status code, the attacker successfully confirms that the document with the targeted ID matches the specified SHA-1 hash. If the server returns an HTTP 302 Found (redirect to login) or HTTP 403 Forbidden response, the attacker knows that the document does not match the specified hash. Repeating this process with multiple candidate hashes allows an attacker to identify the precise contents of private files.

Impact Assessment

The direct technical consequence of this vulnerability is information disclosure. While it does not allow an attacker to read arbitrary contents of private files directly, it serves as a validation mechanism to confirm the presence of known documents. This exposure is critical if attackers seek to verify whether proprietary designs, confidential contracts, or legal agreements have been stored within a private library.

The CVSS v3.1 score is evaluated at 3.7 (Low Severity) with the vector string CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N. The attack complexity is categorized as high because the attacker must have a pre-existing list of candidate SHA-1 hashes to test against the endpoint. The confidentiality impact is rated as low because file contents are not directly extracted.

From a regulatory compliance perspective, this flaw can violate data privacy standards such as GDPR or HIPAA if private records can be identified. Confirming the presence of specific medical or financial records using known hashes constitutes a privacy breach. Therefore, security teams should treat this finding with appropriate urgency despite its low CVSS score.

Remediation

The primary remediation for this vulnerability is upgrading the Wagtail installation to a patched version. Development teams should identify the current branch of Wagtail deployed in their environments and update to version 7.0.9, 7.3.4, 7.4.3, or 8.0rc2, depending on the release branch. Upgrading ensures that the secure deferred ETag evaluation mechanism is enforced globally.

For organizations unable to immediately deploy software updates, temporary mitigations can be implemented at the network edge. Reverse proxies, load balancers, or Web Application Firewalls (WAFs) can be configured to strip the If-Match and If-None-Match HTTP headers from all requests routed to the /documents/ URL pattern. This prevents the upstream Django application from processing conditional ETags, forcing the view to run the permission checks first and return standard redirects.

Additionally, administrators can implement custom middleware to sanitise incoming requests or monitor application logs for anomalous traffic. A sudden spike in HTTP requests directed at sequential document IDs containing diverse If-None-Match header values indicates brute-force scanning activity. This scanning behavior can be detected and blocked using automated rate-limiting solutions.

Official Patches

WagtailOfficial Security Advisory

Fix Analysis (1)

Technical Appendix

CVSS Score
3.7/ 10
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N

Affected Systems

Wagtail CMS

Affected Versions Detail

Product
Affected Versions
Fixed Version
Wagtail
Wagtail
< 7.0.97.0.9
Wagtail
Wagtail
>= 7.1, < 7.3.47.3.4
Wagtail
Wagtail
>= 7.4, < 7.4.37.4.3
Wagtail
Wagtail
== 8.0rc18.0rc2
AttributeDetail
CWE IDCWE-280
Attack VectorNetwork
CVSS v3.13.7 (Low)
Vulnerability TypeInformation Disclosure
Exploit StatusProof of Concept
Componentwagtail/documents/views/serve.py

MITRE ATT&CK Mapping

T1082System Information Discovery
Discovery
T1518Software Discovery
Discovery
CWE-280
Improper Handling of Insufficient Permissions or Privileges

The application does not properly handle cases where an actor has insufficient permissions, allowing execution of critical operations before security validation occurs.

Vulnerability Timeline

Security Patch Authored
2026-08-05
Security Patch Committed to Main Branch
2026-08-20
Advisory GHSA-92hv-j533-69wc Published
2026-08-20

References & Sources

  • [1]GitHub Security Advisory GHSA-92HV-J533-69WC
  • [2]Wagtail Project Security Advisory
  • [3]Wagtail CMS Main Source Code Repository

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 1 hour ago•CVE-2026-109618
9.8

CVE-2026-109618: Remote Code Execution in PHP Core via Out-of-Memory longjmp() Uninitialized Memory Access

CVE-2026-109618 (dubbed PHP2Shell) is a critical vulnerability in the PHP engine core resulting from improper out-of-memory exception handling via longjmp(). When request allocation fails mid-processing, non-local control flow bypasses cleanup procedures, leaving memory structures uninitialized or in a use-after-free state during request shutdown.

Amit Schendel
Amit Schendel
3 views•5 min read
•about 1 hour ago•CVE-2026-109619
9.2

CVE-2026-109619: Remote Code Execution in PHP Core via Stale Global State Memory Corruption (PHP2Shell)

CVE-2026-109619 (PHP2Shell) is a critical Use-After-Free vulnerability in the core PHP engine caused by improper global state cleanup during out-of-memory exception handling across persistent worker requests.

Alon Barad
Alon Barad
5 views•6 min read
•about 1 hour ago•CVE-2026-113721
4.5

CVE-2026-113721: Unsafe Link Resolution in virtualenv File Generation

In Python virtualenv prior to version 21.14.9, activation script generators and configuration writers use Path.exists() before writing files. Because Path.exists() resolves symbolic links, it returns False for dangling symlinks. Consequently, virtualenv skips unlinking pre-planted symbolic links or hard links, writing data directly to target locations outside the intended virtual environment directory.

Amit Schendel
Amit Schendel
3 views•5 min read
•9 days ago•CVE-2026-87697
8.8

CVE-2026-87697: Untrusted Deserialization in .NET PresentationCore Clipboard Handling

A remote code execution vulnerability exists in Microsoft .NET due to untrusted data deserialization within the PresentationCore component. The flaw stems from implicit auto-conversion flags during clipboard data retrieval operations.

Alon Barad
Alon Barad
31 views•5 min read
•9 days ago•CVE-2026-70007
8.8

CVE-2026-70007: Out-of-Bounds Write Vulnerability in .NET Framework and WPF Subsystem

An out-of-bounds write vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio allows unauthenticated remote attackers to execute arbitrary code via crafted pixel-shader bytecode or auto-converted clipboard payloads.

Amit Schendel
Amit Schendel
19 views•6 min read
•10 days ago•CVE-2026-70186
7.5

CVE-2026-70186: ASP.NET Core Denial of Service Vulnerability via Framework Deadlock

ASP.NET Core contains a thread deadlock vulnerability (CWE-833) that allows an unauthenticated remote attacker to cause a denial of service over the network by exhausting server thread pool resources.

Amit Schendel
Amit Schendel
18 views•5 min read