From f99a57f1eca39c6534c579dbc479641801eadd8c Mon Sep 17 00:00:00 2001 From: Nabil Derouiche Date: Wed, 8 Jul 2026 17:02:28 +0100 Subject: [PATCH] security(mcp-nas): correctifs P0 appliques + piege connecteur claude.ai (auth par chemin secret, pas de header) --- common/mcp-nas-security-audit.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/common/mcp-nas-security-audit.md b/common/mcp-nas-security-audit.md index e5d7de9..fc1e896 100644 --- a/common/mcp-nas-security-audit.md +++ b/common/mcp-nas-security-audit.md @@ -39,11 +39,23 @@ **P2 :** healthcheck ne teste que `/health` pas `/mcp` (connu) ; dérive doc `MCP_MAX_OUTPUT_CHARS` (README dit 2000, défaut code 8000). -## Vérif rapide (depuis un poste externe, doit ÉCHOUER après P0) +## Correctifs APPLIQUÉS le 2026-07-08 + +- **P0 #1 — exposition fermée (nginx).** `/etc/nginx/conf.d/http.mcp-nas.conf` (backup `.bak-audit-20260708`). + - **Piège connecteur claude.ai : il n'accepte PAS de header `Authorization` brut, uniquement OAuth (Client ID/Secret).** Le gate Bearer ne marche donc pas avec le connecteur. → auth par **CHEMIN SECRET** : `location // { proxy_pass http://localhost:3042/; }` (le `/` final strippe le préfixe). Le connecteur utilise l'URL `https://mcp-nas.nd.i234.me//mcp`, champs OAuth **vides**. + - `/mcp` direct reste gaté par `Authorization: Bearer ` (pour scripts/curl). `/health` + stubs OAuth ouverts. + - Le `` (64 hex) N'EST PAS dans ce runbook — il est chez Nabil (mémoire Claude Code + fichier NAS `linux-mcp-nas/` scratch). Rotation = regénérer + MAJ nginx + MAJ URL connecteur. +- **P0 #2 — évasion hôte fermée (compose).** Mount `docker.sock` retiré + `security_opt: no-new-privileges` + `cap_drop: [ALL]` dans `docker-compose.yml` (backup `.bak-audit-20260708`). Recréé, `healthy`, `run_command` OK. + +**Reste (non fait) :** P0 #3 (clés SSH Contabo hors conteneur + pwd sudo), P1 #4 (rédaction audit.log + **rotation credentials**), run non-root (`user:1026:100`), token Gitea repo-scopé. + +## Vérif rapide (depuis un poste externe) ```sh -curl -s https://mcp-nas.nd.i234.me/health # ne doit plus répondre sans auth -curl -s -X POST https://mcp-nas.nd.i234.me/mcp \ +# Doit ÉCHOUER (401) — plus de RCE anonyme : +curl -s -o /dev/null -w "%{http_code}\n" -X POST https://mcp-nas.nd.i234.me/mcp \ -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"x","version":"0"}}}' -# tant que ça renvoie un result MCP sans token → RCE ouverte +# Doit MARCHER (200) via le chemin secret (URL du connecteur) : +curl -s -X POST https://mcp-nas.nd.i234.me//mcp -H 'Content-Type: application/json' \ + -H 'Accept: application/json, text/event-stream' -d '{...initialize...}' ```