GHSA-8vh3-g2qg-2h2c: Critical severity pip/nextcloud-mcp-server vulnerability

Published Aug 25, 2026
·
Updated

Summary The POST /webhooks/nextcloud endpoint has no authentication by default: WEBHOOKSECRET defaults to None and is never required by startup validation. When unset, the receiver accepts any unauthenticated POST. The userid is taken directly from the attacker-supplied payload and passed to Qdrant, allowing an unauthenticated attacker to delete or corrupt vector embeddings for any user.

Details Vulnerable file: nextcloudmcpserver/vector/webhookreceiver.py, function handlenextcloudwebhook(), lines 55-67

Root cause 1: Auth check is guarded by if secret: - skipped entirely when WEBHOOKSECRET is unset.

Root cause 2: webhooksecret: str | None = None in config - no startup validator enforces it, even when vector sync is enabled.

Trusted field: payload["user"]["uid"] in webhookparser.py is used as-is for all Qdrant operations - no cross-check against an authenticated session.

webhookreceiver.py, lines 55-67: python secret = getsettings().webhooksecret # None by default if secret: # skipped entirely when unset ... validate Bearer header ... else: warnmissingsecretonce() # just logs, still processes webhookparser.py, line 57: python userid = payload["user"]["uid"] # attacker-controlled PoC No credentials required. Works on any deployment where WEBHOOKSECRET is not explicitly set (the default). json POST /webhooks/nextcloud Content-Type: application/json

{ "event": { "class": "OCP\\Files\\Events\\Node\\BeforeNodeDeletedEvent", "node": { "path": "/victim/files/Notes/any.md", "id": 12345 } }, "user": { "uid": "victim" }, "time": 0 } Result: Qdrant deletes all vector embeddings for victim doc 12345 with no authentication. Attacker can loop over doc IDs for mass deletion. All user targets accepted.

Impact + Anyone on the network with access to port 8000 - no credentials needed. + Attacker can delete or trigger re-index of any user's vector embeddings in Qdrant by spoofing user.uid in the payload. + Mass-sending delete events for all doc IDs destroys the entire semantic search index for all users, requiring a full re-scan to recover.

Recommend Fix 1. Enforce WEBHOOKSECRET at startup ( file configvalidators.py ) python if vectorsyncenabled and not settings.webhooksecret: raise ConfigurationError( "WEBHOOKSECRET must be set when vector sync is enabled" ) 2. Reject requests when secret is unset ( file webhookreceiver.py ) python secret = getsettings().webhooksecret if not secret: return JSONResponse({"status": "unavailable"}, statuscode=503) provided = request.headers.get("authorization", "").encode() if not hmac.comparedigest(provided, f"Bearer {secret}".encode()): return JSONResponse({"status": "unauthorized"}, statuscode=401)

Affected Software

1 affected componentFixes available
pip/nextcloud-mcp-server<=0.117.1
0.117.2

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade pip/nextcloud-mcp-server to a version that resolves this vulnerability.

    Fixed in 0.117.2
  2. Configuration

    In file config_validators.py, enforce at startup that WEBHOOK_SECRET is set whenever vector sync is enabled (add a startup validator so WEBHOOK_SECRET cannot be None when vector_sync is enabled).

    nextcloud_mcp_server (config validation) WEBHOOK_SECRET validation when vector sync is enabled = required (no None)
  3. Configuration

    In function handle_nextcloud_webhook() (lines 55-67), reject POST /webhooks/nextcloud requests with an error response when settings.webhook_secret is unset (i.e., when WEBHOOK_SECRET is None) instead of processing unauthenticated requests.

    nextcloud_mcp_server/vector/webhook_receiver.py (handle_nextcloud_webhook) request authorization handling when WEBHOOK_SECRET is unset = reject requests

Event History

Aug 25, 2026
Advisory Published
via GitHub·04:04 PM
Data Sourced
via GitHub·04:04 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Who is exposed by this issue?

Deployments where the Nextcloud webhook endpoint is reachable and WEBHOOK_SECRET is unset are exposed. The secret defaults to None, so authentication is skipped unless an operator explicitly configures it.

2

What does an attacker need to exploit it?

An attacker only needs to send an unauthenticated POST request to /webhooks/nextcloud. They can supply a user.uid value in the payload, which is used for Qdrant operations without being tied to an authenticated identity.

3

Can this affect users other than the attacker?

Yes. Because the user ID comes directly from the request payload, an unauthenticated sender can target vector embeddings associated with any user ID and delete or corrupt them.

4

What should be done if patching is not immediately possible?

Configure WEBHOOK_SECRET to a nonempty value so the receiver validates the Bearer authorization header. Restricting network access to the webhook endpoint can also reduce exposure while the configuration is corrected.

5

How can I determine whether my deployment is affected?

Check whether WEBHOOK_SECRET is configured. If it is unset or None, the endpoint logs a missing-secret warning but continues to process webhook requests without authentication.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203