CVE-2026-55640
Nextcloud MCP Server: Unauthenticated `POST /webhooks/nextcloud` allows arbitrary vector data deletion when `WEBHOOK_SECRET` is unset ( default )
Nextcloud MCP Server is a production-ready MCP server that connects AI assistants to a Nextcloud instance. Prior to 0.117.2, the POST /webhooks/nextcloud endpoint in nextcloud_mcp_server/vector/webhook_receiver.py has no authentication by default because WEBHOOK_SECRET defaults to None and startup validation does not require it. When WEBHOOK_SECRET is unset, handle_nextcloud_webhook() accepts unauthenticated requests. The payload["user"]["uid"] field parsed in nextcloud_mcp_server/vector/webhook_parser.py is attacker-controlled and is used without an authenticated-session cross-check for Qdrant operations, allowing a network attacker to delete or trigger re-indexing of vector embeddings for any user and to destroy the semantic search index by sending forged deletion events. This issue is fixed in version 0.117.2.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
9.1
Nextcloud MCP Server: Unauthenticated `POST /webhooks/nextcloud` allows arbitrary vector data deletion when `WEBHOOK_SECRET` is unset ( default )
Nextcloud MCP Server is a production-ready MCP server that connects AI assistants to a Nextcloud instance. Prior to 0.117.2, the POST /webhooks/nextcloud endpoint in nextcloud_mcp_server/vector/webhook_receiver.py has no authentication by default because WEBHOOK_SECRET defaults to None and startup validation does not require it. When WEBHOOK_SECRET is unset, handle_nextcloud_webhook() accepts unauthenticated requests. The payload["user"]["uid"] field parsed in nextcloud_mcp_server/vector/webhook_parser.py is attacker-controlled and is used without an authenticated-session cross-check for Qdrant operations, allowing a network attacker to delete or trigger re-indexing of vector embeddings for any user and to destroy the semantic search index by sending forged deletion events. This issue is fixed in version 0.117.2.
- Record
CVE-2026-55640- CVSS 3.1
- 9.1 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H - Weakness
- CWE-306
- Updated
- 2026-11-02
EUVDEUVD-2026-65596
9.1
Nextcloud MCP Server is a production-ready MCP server that connects AI assistants to a Nextcloud instance. Prior to 0.117.2, the POST /webhooks/nextcloud endpoint in nextcloud_mcp_server/vector/webhook_receiver.py has no authentication by default because WEBHOOK_SECRET defaults to None and startup validation does not require it. When WEBHOOK_SECRET is unset, handle_nextcloud_webhook() accepts unauthenticated requests. The payload["user"]["uid"] field parsed in nextcloud_mcp_server/vector/webhook_parser.py is attacker-controlled and is used without an authenticated-session cross-check for Qdrant operations, allowing a network attacker to delete or trigger re-indexing of vector embeddings for any user and to destroy the semantic search index by sending forged deletion events. This issue is fixed in version 0.117.2.
- Record
EUVD-2026-65596- CVSS 3.1
- 9.1 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-8vh3-g2qg-2h2c
9.1
nextcloud-mcp-server: Unauthenticated `POST /webhooks/nextcloud` allows arbitrary vector data deletion when `WEBHOOK_SECRET` is unset ( default )
Summary
The POST /webhooks/nextcloud endpoint has no authentication by default: WEBHOOK_SECRET defaults to None and is never required by startup validation. When unset, the receiver accepts any unauthenticated POST. The user_id 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: nextcloud_mcp_server/vector/webhook_receiver.py, function handle_nextcloud_webhook(), lines 55-67
Root cause 1: Auth check is guarded by if secret: - skipped entirely when WEBHOOK_SECRET is unset.
Root cause 2: webhook_secret: str | None = None in config - no startup validator enforces it, even when vector sync is enabled.
Trusted field: payload["user"]["uid"] in webhook_parser.py is used as-is for all Qdrant operations - no cross-check against an authenticated session.
webhook_receiver.py, lines 55-67:
secret = get_settings().webhook_secret # None by default
if secret: # skipped entirely when unset
... validate Bearer header ...
else:
_warn_missing_secret_once() # just logs, still processes
webhook_parser.py, line 57:
user_id = payload["user"]["uid"] # attacker-controlled
PoC
No credentials required. Works on any deployment where WEBHOOK_SECRET is not explicitly set (the default).
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.uidin 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
- Enforce
WEBHOOK_SECRETat startup ( fileconfig_validators.py)
if vector_sync_enabled and not settings.webhook_secret:
raise ConfigurationError(
"WEBHOOK_SECRET must be set when vector sync is enabled"
)
- Reject requests when secret is unset ( file
webhook_receiver.py)
secret = get_settings().webhook_secret
if not secret:
return JSONResponse({"status": "unavailable"}, status_code=503)
provided = request.headers.get("authorization", "").encode()
if not hmac.compare_digest(provided, f"Bearer {secret}".encode()):
return JSONResponse({"status": "unauthorized"}, status_code=401)
- Record
GHSA-8vh3-g2qg-2h2c- CVSS 3.1
- 9.1 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H - Weakness
- CWE-306
- Updated
- 2026-11-02
NVD
9.1
Nextcloud MCP Server is a production-ready MCP server that connects AI assistants to a Nextcloud instance. Prior to 0.117.2, the POST /webhooks/nextcloud endpoint in nextcloud_mcp_server/vector/webhook_receiver.py has no authentication by default because WEBHOOK_SECRET defaults to None and startup validation does not require it. When WEBHOOK_SECRET is unset, handle_nextcloud_webhook() accepts unauthenticated requests. The payload["user"]["uid"] field parsed in nextcloud_mcp_server/vector/webhook_parser.py is attacker-controlled and is used without an authenticated-session cross-check for Qdrant operations, allowing a network attacker to delete or trigger re-indexing of vector embeddings for any user and to destroy the semantic search index by sending forged deletion events. This issue is fixed in version 0.117.2.
- Record
CVE-2026-55640- CVSS 3.1
- 9.1 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H - Weakness
- CWE-306
- Updated
- 2026-11-02
OSV
9.1
Nextcloud MCP Server: Unauthenticated `POST /webhooks/nextcloud` allows arbitrary vector data deletion when `WEBHOOK_SECRET` is unset ( default )
Nextcloud MCP Server is a production-ready MCP server that connects AI assistants to a Nextcloud instance. Prior to 0.117.2, the POST /webhooks/nextcloud endpoint in nextcloud_mcp_server/vector/webhook_receiver.py has no authentication by default because WEBHOOK_SECRET defaults to None and startup validation does not require it. When WEBHOOK_SECRET is unset, handle_nextcloud_webhook() accepts unauthenticated requests. The payload["user"]["uid"] field parsed in nextcloud_mcp_server/vector/webhook_parser.py is attacker-controlled and is used without an authenticated-session cross-check for Qdrant operations, allowing a network attacker to delete or trigger re-indexing of vector embeddings for any user and to destroy the semantic search index by sending forged deletion events. This issue is fixed in version 0.117.2.
- Record
CVE-2026-55640- CVSS 3.1
- 9.1 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H - Weakness
- CWE-306
- Updated
- 2026-11-02
OSVGHSA-8vh3-g2qg-2h2c
9.1
nextcloud-mcp-server: Unauthenticated `POST /webhooks/nextcloud` allows arbitrary vector data deletion when `WEBHOOK_SECRET` is unset ( default )
Summary
The POST /webhooks/nextcloud endpoint has no authentication by default: WEBHOOK_SECRET defaults to None and is never required by startup validation. When unset, the receiver accepts any unauthenticated POST. The user_id 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: nextcloud_mcp_server/vector/webhook_receiver.py, function handle_nextcloud_webhook(), lines 55-67
Root cause 1: Auth check is guarded by if secret: - skipped entirely when WEBHOOK_SECRET is unset.
Root cause 2: webhook_secret: str | None = None in config - no startup validator enforces it, even when vector sync is enabled.
Trusted field: payload["user"]["uid"] in webhook_parser.py is used as-is for all Qdrant operations - no cross-check against an authenticated session.
webhook_receiver.py, lines 55-67:
secret = get_settings().webhook_secret # None by default
if secret: # skipped entirely when unset
... validate Bearer header ...
else:
_warn_missing_secret_once() # just logs, still processes
webhook_parser.py, line 57:
user_id = payload["user"]["uid"] # attacker-controlled
PoC
No credentials required. Works on any deployment where WEBHOOK_SECRET is not explicitly set (the default).
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.uidin 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
- Enforce
WEBHOOK_SECRETat startup ( fileconfig_validators.py)
if vector_sync_enabled and not settings.webhook_secret:
raise ConfigurationError(
"WEBHOOK_SECRET must be set when vector sync is enabled"
)
- Reject requests when secret is unset ( file
webhook_receiver.py)
secret = get_settings().webhook_secret
if not secret:
return JSONResponse({"status": "unavailable"}, status_code=503)
provided = request.headers.get("authorization", "").encode()
if not hmac.compare_digest(provided, f"Bearer {secret}".encode()):
return JSONResponse({"status": "unauthorized"}, status_code=401)
- Record
GHSA-8vh3-g2qg-2h2c- CVSS 3.1
- 9.1 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H - Weakness
- CWE-306
- Updated
- 2026-11-02
OSVPYSEC-2026-3866
9.1
nextcloud-mcp-server: Unauthenticated `POST /webhooks/nextcloud` allows arbitrary vector data deletion when `WEBHOOK_SECRET` is unset ( default )
Summary
The POST /webhooks/nextcloud endpoint has no authentication by default: WEBHOOK_SECRET defaults to None and is never required by startup validation. When unset, the receiver accepts any unauthenticated POST. The user_id 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: nextcloud_mcp_server/vector/webhook_receiver.py, function handle_nextcloud_webhook(), lines 55-67
Root cause 1: Auth check is guarded by if secret: - skipped entirely when WEBHOOK_SECRET is unset.
Root cause 2: webhook_secret: str | None = None in config - no startup validator enforces it, even when vector sync is enabled.
Trusted field: payload["user"]["uid"] in webhook_parser.py is used as-is for all Qdrant operations - no cross-check against an authenticated session.
webhook_receiver.py, lines 55-67:
secret = get_settings().webhook_secret # None by default
if secret: # skipped entirely when unset
... validate Bearer header ...
else:
_warn_missing_secret_once() # just logs, still processes
webhook_parser.py, line 57:
user_id = payload["user"]["uid"] # attacker-controlled
PoC
No credentials required. Works on any deployment where WEBHOOK_SECRET is not explicitly set (the default).
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.uidin 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
- Enforce
WEBHOOK_SECRETat startup ( fileconfig_validators.py)
if vector_sync_enabled and not settings.webhook_secret:
raise ConfigurationError(
"WEBHOOK_SECRET must be set when vector sync is enabled"
)
- Reject requests when secret is unset ( file
webhook_receiver.py)
secret = get_settings().webhook_secret
if not secret:
return JSONResponse({"status": "unavailable"}, status_code=503)
provided = request.headers.get("authorization", "").encode()
if not hmac.compare_digest(provided, f"Bearer {secret}".encode()):
return JSONResponse({"status": "unauthorized"}, status_code=401)
- Record
PYSEC-2026-3866- CVSS 3.1
- 9.1 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H - Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
nextcloud-mcp-serverPyPI |
through 0.117.1 | 0.117.2 |
nextcloud-mcp-serverPyPI |
before 0.117.2, plus listed versions 0.100.00.101.00.101.10.101.20.101.3 Show 45 moreShow less0.101.40.102.00.103.00.104.00.104.10.105.00.106.00.107.00.108.00.108.10.108.20.108.30.109.00.109.10.110.00.110.10.110.20.111.00.112.00.113.00.113.10.114.00.115.00.115.10.116.00.117.00.117.10.17.10.65.30.65.40.66.00.66.10.66.20.67.00.68.00.68.10.68.20.68.30.68.40.69.00.70.00.70.10.70.20.70.30.70.4 |
0.117.2 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-55640 is a critical vulnerability (CVSS 9.1) in Cbcoutinho Nextcloud-mcp-server, published August 25, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.73%, the 54th percentile. Fixed in nextcloud-mcp-server 0.117.2.
References
github.com/cbcoutinho/nextcloud-mcp-server/security/advisories/GHSA-8vh3-g2qg-2h2c
github.com/cbcoutinho/nextcloud-mcp-server/commit/4fc2b10945108cf1008ec9698291de6706ffcb73
github.com/cbcoutinho/nextcloud-mcp-server/tree/v0.117.2
github.com/advisories/GHSA-8vh3-g2qg-2h2c
github.com/CVEProject/cvelistV5/tree/main/cves/2026/55xxx/CVE-2026-55640.json
nvd.nist.gov/vuln/detail/CVE-2026-55640
github.com/cbcoutinho/nextcloud-mcp-server
pypi.org/project/nextcloud-mcp-server
Left out here: 68 versions. The JSON record has them.