Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-87803

CVE-2026-87803: Countly Server DBViewer Auth Bypass Flaw

CVE-2026-87803 is an authorization bypass flaw in Countly Server DBViewer that allows non-admin users to access sensitive data and perform account takeover. This post covers technical details, affected versions, and mitigation.

Updated:

CVE-2026-87803 Overview

CVE-2026-87803 is an authorization bypass vulnerability in the Countly Server DBViewer component. The flaw resides in the aggregation stage sanitizer used by the /o/db endpoint. The sanitizer incorrectly classifies nested arrays containing unknown stage operators as generic arrays, causing it to skip stage-level filtering for sibling stages. Attackers with non-admin DBViewer read permission can abuse this to inject forbidden operators such as $lookup inside $facet sub-pipelines. The result is unauthorized cross-collection reads into restricted collections, exposing sensitive data such as password-reset tokens (prid) and enabling account takeover. The weakness is categorized as CWE-863: Incorrect Authorization.

Critical Impact

Authenticated low-privileged users can exfiltrate password-reset tokens from restricted collections and take over accounts, including administrative ones.

Affected Products

  • Countly Server (DBViewer plugin)
  • Deployments exposing the /o/db aggregation endpoint to non-admin users
  • Instances relying on the aggregation stage sanitizer with the hardcoded KNOWN_STAGE_OPERATORS allow-list

Discovery Timeline

  • 2026-09-10 - CVE-2026-87803 published to NVD
  • 2026-09-10 - Last updated in NVD database

Technical Details for CVE-2026-87803

Vulnerability Analysis

Countly Server exposes the /o/db endpoint to allow users with DBViewer permissions to run MongoDB aggregation pipelines. To prevent misuse, user-controlled aggregation JSON passes through a stage sanitizer that strips forbidden operators from each pipeline stage. The sanitizer distinguishes real sub-pipelines from generic nested arrays by checking whether every element contains a key present in the hardcoded KNOWN_STAGE_OPERATORS set.

This all-or-nothing check is the root of the bypass. When any single element uses a stage key outside the allow-list, the sanitizer treats the entire array as opaque data and skips per-stage sanitization for its siblings. Attackers exploit this by mixing a benign but unrecognized stage operator with a forbidden operator inside the same array.

The most reliable trigger is the undocumented MongoDB-internal $_internalInhibitOptimization operator. Because it is not in the allow-list, its presence causes the sanitizer to abandon inspection of the surrounding stages, allowing operators such as $lookup to survive inside a $facet sub-pipeline. $lookup then performs a join against a collection the caller has no permission to read.

Root Cause

The root cause is a logic flaw in sub-pipeline detection. The sanitizer conflates classification with enforcement: an unrecognized element short-circuits both. Combined with an incomplete allow-list that omits internal MongoDB operators, this converts a defense-in-depth filter into a bypass primitive.

Attack Vector

Exploitation requires network access to the Countly Server and a valid account with DBViewer read permission. The attacker sends a crafted aggregation payload to /o/db containing a $facet stage whose sub-pipeline includes both $_internalInhibitOptimization and a $lookup targeting a restricted collection such as the users or password-reset collection. The response returns the joined documents, including prid values that the attacker replays to reset arbitrary account passwords.

No synthetic proof-of-concept is reproduced here. Technical details are available in Countly Pull Request #7868.

Detection Methods for CVE-2026-87803

Indicators of Compromise

  • Requests to /o/db containing $facet combined with $lookup in the aggregation JSON.
  • Aggregation payloads referencing $_internalInhibitOptimization or other undocumented MongoDB-internal operators.
  • Non-admin user sessions returning documents from collections outside the DBViewer scope, such as user or password-reset collections.
  • Unexpected password-reset events immediately following DBViewer API activity from the same account.

Detection Strategies

  • Parse /o/db request bodies at the reverse proxy or WAF and alert on $lookup, $graphLookup, $merge, $out, and $_internalInhibitOptimization tokens.
  • Correlate DBViewer API calls with subsequent /i/users/reset_password or equivalent password-reset endpoint activity across short time windows.
  • Baseline aggregation query shapes per user role and flag deviations, particularly nested $facet pipelines from non-admin roles.

Monitoring Recommendations

  • Enable MongoDB profiling for slow or unusual aggregation stages and forward logs to a centralized analytics platform.
  • Monitor Countly application logs for DBViewer permission checks that succeed while accessing sensitive collections.
  • Track outbound response sizes on /o/db and alert on responses containing token-like fields such as prid, token, or reset.

How to Mitigate CVE-2026-87803

Immediate Actions Required

  • Upgrade Countly Server to the release containing the fix from Pull Request #7868.
  • Revoke DBViewer read permission from any account that does not strictly require it, especially non-administrative roles.
  • Rotate all outstanding password-reset tokens and force password resets for privileged accounts if exploitation is suspected.
  • Audit recent /o/db traffic for the indicators listed above and treat any matches as suspected data exfiltration.

Patch Information

The vendor fix is delivered in Countly PR #7868. The patch reworks the aggregation stage sanitizer so unknown stage operators no longer disable sanitization for sibling stages, and it enforces stage-level stripping recursively inside $facet sub-pipelines. Apply the corresponding tagged release rather than cherry-picking the diff to ensure related sanitizer changes are included.

Workarounds

  • Block requests to /o/db at a reverse proxy when the JSON body contains $lookup, $graphLookup, $merge, $out, or $_internalInhibitOptimization.
  • Restrict the DBViewer plugin to administrator accounts only until the patched release is deployed.
  • Place the Countly management interface behind an authenticated VPN or IP allow-list to reduce the attack surface for authenticated abuse.
  • Configure MongoDB role-based access control so the Countly service account cannot read password-reset or credential collections beyond the minimum required.
bash
# Example reverse proxy rule (NGINX) to block risky aggregation operators on /o/db
location /o/db {
    if ($request_body ~* "\$lookup|\$graphLookup|\$merge|\$out|\$_internalInhibitOptimization") {
        return 403;
    }
    proxy_pass http://countly_upstream;
}

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.