{"id":"CVE-2026-55640","aliases":["EUVD-2026-65596","GHSA-8vh3-g2qg-2h2c","PYSEC-2026-3866"],"status":"published","title":"Nextcloud MCP Server: Unauthenticated `POST /webhooks/nextcloud` allows arbitrary vector data deletion when `WEBHOOK_SECRET` is unset ( default )","description":"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.","severity":{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H","level":"critical","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-10","score":0.0073,"percentile":0.54602,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-306"],"published":"2026-08-25T16:03:28Z","modified":"2026-10-28T02:30:22Z","fixes":[{"ecosystem":"PyPI","package":"nextcloud-mcp-server","fixed_in":["0.117.2"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"PyPI","package":"nextcloud-mcp-server","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"0.117.1"},{"fixed":"0.117.2"}]}]},{"source":"osv","ecosystem":"PyPI","package":"nextcloud-mcp-server","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.117.2"}]}],"versions":["0.100.0","0.101.0","0.101.1","0.101.2","0.101.3","0.101.4","0.102.0","0.103.0","0.104.0","0.104.1","0.105.0","0.106.0","0.107.0","0.108.0","0.108.1","0.108.2","0.108.3","0.109.0","0.109.1","0.110.0","0.110.1","0.110.2","0.111.0","0.112.0","0.113.0","0.113.1","0.114.0","0.115.0","0.115.1","0.116.0","0.117.0","0.117.1","0.17.1","0.65.3","0.65.4","0.66.0","0.66.1","0.66.2","0.67.0","0.68.0","0.68.1","0.68.2","0.68.3","0.68.4","0.69.0","0.70.0","0.70.1","0.70.2","0.70.3","0.70.4","0.71.0","0.72.0","0.72.1","0.72.2","0.72.3","0.72.4","0.72.5","0.72.6","0.72.7","0.73.0","0.73.1","0.73.2","0.74.0","0.75.0","0.75.1","0.75.2","0.76.0","0.77.0","0.77.1","0.78.0","0.79.0","0.79.1","0.79.2","0.79.3","0.80.0","0.81.0","0.82.0","0.83.0","0.83.1","0.83.2","0.83.3","0.83.4","0.84.0","0.84.1","0.84.2","0.85.0","0.85.1","0.86.0","0.86.1","0.86.2","0.86.3","0.86.4","0.87.0","0.87.1","0.87.2","0.88.0","0.88.1","0.88.2","0.88.3","0.89.0","0.90.0","0.90.1","0.90.2","0.91.0","0.91.1","0.91.2","0.91.3","0.92.0","0.92.1","0.93.0","0.94.0","0.94.1","0.95.0","0.96.0","0.97.0","0.98.0","0.98.1","0.99.0"]},{"source":"osv","ecosystem":"PyPI","package":"nextcloud-mcp-server","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.117.2"}]}],"versions":["0.100.0","0.101.0","0.101.1","0.101.2","0.101.3","0.101.4","0.102.0","0.103.0","0.104.0","0.104.1","0.105.0","0.106.0","0.107.0","0.108.0","0.108.1","0.108.2","0.108.3","0.109.0","0.109.1","0.110.0","0.110.1","0.110.2","0.111.0","0.112.0","0.113.0","0.113.1","0.114.0","0.115.0","0.115.1","0.116.0","0.117.0","0.117.1","0.17.1","0.65.3","0.65.4","0.66.0","0.66.1","0.66.2","0.67.0","0.68.0","0.68.1","0.68.2","0.68.3","0.68.4","0.69.0","0.70.0","0.70.1","0.70.2","0.70.3","0.70.4","0.71.0","0.72.0","0.72.1","0.72.2","0.72.3","0.72.4","0.72.5","0.72.6","0.72.7","0.73.0","0.73.1","0.73.2","0.74.0","0.75.0","0.75.1","0.75.2","0.76.0","0.77.0","0.77.1","0.78.0","0.79.0","0.79.1","0.79.2","0.79.3","0.80.0","0.81.0","0.82.0","0.83.0","0.83.1","0.83.2","0.83.3","0.83.4","0.84.0","0.84.1","0.84.2","0.85.0","0.85.1","0.86.0","0.86.1","0.86.2","0.86.3","0.86.4","0.87.0","0.87.1","0.87.2","0.88.0","0.88.1","0.88.2","0.88.3","0.89.0","0.90.0","0.90.1","0.90.2","0.91.0","0.91.1","0.91.2","0.91.3","0.92.0","0.92.1","0.93.0","0.94.0","0.94.1","0.95.0","0.96.0","0.97.0","0.98.0","0.98.1","0.99.0"]}],"products":[{"vendor":"cbcoutinho","product":"nextcloud-mcp-server"}],"references":[{"url":"https://github.com/cbcoutinho/nextcloud-mcp-server/security/advisories/GHSA-8vh3-g2qg-2h2c","tags":["x_refsource_CONFIRM","advisory","web"]},{"url":"https://github.com/cbcoutinho/nextcloud-mcp-server/commit/4fc2b10945108cf1008ec9698291de6706ffcb73","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/cbcoutinho/nextcloud-mcp-server/tree/v0.117.2","tags":["x_refsource_MISC","web"]},{"url":"https://github.com/advisories/GHSA-8vh3-g2qg-2h2c","tags":["advisory"]},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/55xxx/CVE-2026-55640.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-55640","tags":["advisory"]},{"url":"https://github.com/cbcoutinho/nextcloud-mcp-server","tags":["package"]},{"url":"https://pypi.org/project/nextcloud-mcp-server","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-55640","title":"Nextcloud MCP Server: Unauthenticated `POST /webhooks/nextcloud` allows arbitrary vector data deletion when `WEBHOOK_SECRET` is unset ( default )","description":"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.","status":"published","published":"2026-08-25T16:03:28.085Z","modified":"2026-08-25T19:20:43.689Z","cvss":[{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H","level":"critical","assessor":"cna"}],"cwes":["CWE-306"],"updated_at":"2026-11-02T14:20:12.260247Z"}],"euvd":[{"id":"EUVD-2026-65596","description":"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.","status":"published","published":"2026-08-25T16:03:28Z","modified":"2026-08-25T19:20:43Z","cvss":[{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H","level":"critical"}],"updated_at":"2026-11-02T18:01:32.174502Z"}],"ghsa":[{"id":"GHSA-8vh3-g2qg-2h2c","title":"nextcloud-mcp-server: Unauthenticated `POST /webhooks/nextcloud` allows arbitrary vector data deletion when `WEBHOOK_SECRET` is unset ( default )","description":"## Summary\nThe `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.\n\n## Details\n**Vulnerable file:** `nextcloud_mcp_server/vector/webhook_receiver.py`, function `handle_nextcloud_webhook()`, **lines 55-67**\n\n**Root cause 1**: Auth check is guarded by `if secret`: - skipped entirely when `WEBHOOK_SECRET` is unset.\n\n**Root cause 2**: `webhook_secret: str | None = None` in config - no startup validator enforces it, even when vector sync is enabled.\n\n**Trusted field**: `payload[\"user\"][\"uid\"]` in `webhook_parser.py` is used as-is for all Qdrant operations - no cross-check against an authenticated session.\n\n`webhook_receiver.py`, **lines 55-67**:\n```python\nsecret = get_settings().webhook_secret  # None by default\nif secret:                           # skipped entirely when unset\n    ... validate Bearer header ...\nelse:\n    _warn_missing_secret_once()     # just logs, still processes\n```\n`webhook_parser.py`, **line 57**:\n```python\nuser_id = payload[\"user\"][\"uid\"]     # attacker-controlled\n```\n## PoC\n**No credentials required**. Works on any deployment where `WEBHOOK_SECRET` is not explicitly set (the default).\n```json\nPOST /webhooks/nextcloud\nContent-Type: application/json\n\n{\n  \"event\": {\n    \"class\": \"OCP\\\\Files\\\\Events\\\\Node\\\\BeforeNodeDeletedEvent\",\n    \"node\": { \"path\": \"/victim/files/Notes/any.md\", \"id\": 12345 }\n  },\n  \"user\": { \"uid\": \"victim\" },\n  \"time\": 0\n}\n```\n**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.\n\n\n## Impact\n+ Anyone on the network with access to port `8000` - no credentials needed.\n+ Attacker can delete or trigger re-index of any user's vector embeddings in Qdrant by spoofing `user.uid` in the payload.\n+ Mass-sending delete events for all doc IDs destroys the entire semantic search index for all users, requiring a full re-scan to recover.\n\n## Recommend Fix\n1. Enforce `WEBHOOK_SECRET` at startup ( file `config_validators.py` )\n```python\nif vector_sync_enabled and not settings.webhook_secret:\n    raise ConfigurationError(\n        \"WEBHOOK_SECRET must be set when vector sync is enabled\"\n    )\n```\n2. Reject requests when secret is unset ( file `webhook_receiver.py` )\n```python\nsecret = get_settings().webhook_secret\nif not secret:\n    return JSONResponse({\"status\": \"unavailable\"}, status_code=503)\nprovided = request.headers.get(\"authorization\", \"\").encode()\nif not hmac.compare_digest(provided, f\"Bearer {secret}\".encode()):\n    return JSONResponse({\"status\": \"unauthorized\"}, status_code=401)\n```","status":"published","published":"2026-08-25T16:04:15Z","modified":"2026-08-25T16:04:17Z","cvss":[{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H","level":"critical"}],"cwes":["CWE-306"],"updated_at":"2026-11-02T14:41:05.994358Z"}],"nvd":[{"id":"CVE-2026-55640","description":"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.","status":"published","published":"2026-08-25T16:16:55.81Z","modified":"2026-09-09T21:07:31.353Z","cvss":[{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H","level":"critical","assessor":"secondary"}],"cwes":["CWE-306"],"updated_at":"2026-11-02T14:12:41.347728Z"}],"osv":[{"id":"CVE-2026-55640","title":"Nextcloud MCP Server: Unauthenticated `POST /webhooks/nextcloud` allows arbitrary vector data deletion when `WEBHOOK_SECRET` is unset ( default )","description":"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.","status":"published","published":"2026-08-25T16:03:28.085Z","modified":"2026-10-28T02:30:22.471672747Z","cvss":[{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H","level":"critical"}],"cwes":["CWE-306"],"updated_at":"2026-11-02T15:45:11.22012Z"},{"id":"GHSA-8vh3-g2qg-2h2c","title":"nextcloud-mcp-server: Unauthenticated `POST /webhooks/nextcloud` allows arbitrary vector data deletion when `WEBHOOK_SECRET` is unset ( default )","description":"## Summary\nThe `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.\n\n## Details\n**Vulnerable file:** `nextcloud_mcp_server/vector/webhook_receiver.py`, function `handle_nextcloud_webhook()`, **lines 55-67**\n\n**Root cause 1**: Auth check is guarded by `if secret`: - skipped entirely when `WEBHOOK_SECRET` is unset.\n\n**Root cause 2**: `webhook_secret: str | None = None` in config - no startup validator enforces it, even when vector sync is enabled.\n\n**Trusted field**: `payload[\"user\"][\"uid\"]` in `webhook_parser.py` is used as-is for all Qdrant operations - no cross-check against an authenticated session.\n\n`webhook_receiver.py`, **lines 55-67**:\n```python\nsecret = get_settings().webhook_secret  # None by default\nif secret:                           # skipped entirely when unset\n    ... validate Bearer header ...\nelse:\n    _warn_missing_secret_once()     # just logs, still processes\n```\n`webhook_parser.py`, **line 57**:\n```python\nuser_id = payload[\"user\"][\"uid\"]     # attacker-controlled\n```\n## PoC\n**No credentials required**. Works on any deployment where `WEBHOOK_SECRET` is not explicitly set (the default).\n```json\nPOST /webhooks/nextcloud\nContent-Type: application/json\n\n{\n  \"event\": {\n    \"class\": \"OCP\\\\Files\\\\Events\\\\Node\\\\BeforeNodeDeletedEvent\",\n    \"node\": { \"path\": \"/victim/files/Notes/any.md\", \"id\": 12345 }\n  },\n  \"user\": { \"uid\": \"victim\" },\n  \"time\": 0\n}\n```\n**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.\n\n\n## Impact\n+ Anyone on the network with access to port `8000` - no credentials needed.\n+ Attacker can delete or trigger re-index of any user's vector embeddings in Qdrant by spoofing `user.uid` in the payload.\n+ Mass-sending delete events for all doc IDs destroys the entire semantic search index for all users, requiring a full re-scan to recover.\n\n## Recommend Fix\n1. Enforce `WEBHOOK_SECRET` at startup ( file `config_validators.py` )\n```python\nif vector_sync_enabled and not settings.webhook_secret:\n    raise ConfigurationError(\n        \"WEBHOOK_SECRET must be set when vector sync is enabled\"\n    )\n```\n2. Reject requests when secret is unset ( file `webhook_receiver.py` )\n```python\nsecret = get_settings().webhook_secret\nif not secret:\n    return JSONResponse({\"status\": \"unavailable\"}, status_code=503)\nprovided = request.headers.get(\"authorization\", \"\").encode()\nif not hmac.compare_digest(provided, f\"Bearer {secret}\".encode()):\n    return JSONResponse({\"status\": \"unauthorized\"}, status_code=401)\n```","status":"published","published":"2026-08-25T16:04:15Z","modified":"2026-09-10T12:26:01.466673851Z","cvss":[{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H","level":"critical"}],"cwes":["CWE-306"],"updated_at":"2026-11-02T15:46:42.78452Z"},{"id":"PYSEC-2026-3866","title":"nextcloud-mcp-server: Unauthenticated `POST /webhooks/nextcloud` allows arbitrary vector data deletion when `WEBHOOK_SECRET` is unset ( default )","description":"## Summary\nThe `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.\n\n## Details\n**Vulnerable file:** `nextcloud_mcp_server/vector/webhook_receiver.py`, function `handle_nextcloud_webhook()`, **lines 55-67**\n\n**Root cause 1**: Auth check is guarded by `if secret`: - skipped entirely when `WEBHOOK_SECRET` is unset.\n\n**Root cause 2**: `webhook_secret: str | None = None` in config - no startup validator enforces it, even when vector sync is enabled.\n\n**Trusted field**: `payload[\"user\"][\"uid\"]` in `webhook_parser.py` is used as-is for all Qdrant operations - no cross-check against an authenticated session.\n\n`webhook_receiver.py`, **lines 55-67**:\n```python\nsecret = get_settings().webhook_secret  # None by default\nif secret:                           # skipped entirely when unset\n    ... validate Bearer header ...\nelse:\n    _warn_missing_secret_once()     # just logs, still processes\n```\n`webhook_parser.py`, **line 57**:\n```python\nuser_id = payload[\"user\"][\"uid\"]     # attacker-controlled\n```\n## PoC\n**No credentials required**. Works on any deployment where `WEBHOOK_SECRET` is not explicitly set (the default).\n```json\nPOST /webhooks/nextcloud\nContent-Type: application/json\n\n{\n  \"event\": {\n    \"class\": \"OCP\\\\Files\\\\Events\\\\Node\\\\BeforeNodeDeletedEvent\",\n    \"node\": { \"path\": \"/victim/files/Notes/any.md\", \"id\": 12345 }\n  },\n  \"user\": { \"uid\": \"victim\" },\n  \"time\": 0\n}\n```\n**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.\n\n\n## Impact\n+ Anyone on the network with access to port `8000` - no credentials needed.\n+ Attacker can delete or trigger re-index of any user's vector embeddings in Qdrant by spoofing `user.uid` in the payload.\n+ Mass-sending delete events for all doc IDs destroys the entire semantic search index for all users, requiring a full re-scan to recover.\n\n## Recommend Fix\n1. Enforce `WEBHOOK_SECRET` at startup ( file `config_validators.py` )\n```python\nif vector_sync_enabled and not settings.webhook_secret:\n    raise ConfigurationError(\n        \"WEBHOOK_SECRET must be set when vector sync is enabled\"\n    )\n```\n2. Reject requests when secret is unset ( file `webhook_receiver.py` )\n```python\nsecret = get_settings().webhook_secret\nif not secret:\n    return JSONResponse({\"status\": \"unavailable\"}, status_code=503)\nprovided = request.headers.get(\"authorization\", \"\").encode()\nif not hmac.compare_digest(provided, f\"Bearer {secret}\".encode()):\n    return JSONResponse({\"status\": \"unauthorized\"}, status_code=401)\n```","status":"published","published":"2026-09-10T09:44:56.031196Z","modified":"2026-09-10T12:15:18.811964337Z","cvss":[{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H","level":"critical"}],"updated_at":"2026-11-02T15:52:57.255153Z"}]}}
