GHSA-8vh3-g2qg-2h2c: Critical severity pip/nextcloud-mcp-server vulnerability
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
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
pip/nextcloud-mcp-serverto a version that resolves this vulnerability.Fixed in 0.117.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) - 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
Frequently Asked Questions
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.
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.
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.
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.
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.