Skip to content

Sistema de Scoring MSSS v2.0

Documento tecnico para analistas de seguridad


1. Introduccion

MSSS (MCP Server Security Standard) es el sistema de scoring utilizado por mcp-scan para evaluar la postura de seguridad de un servidor MCP. El score va de 0 a 100, donde 100 representa un servidor sin hallazgos de seguridad.

Novedades en v2.0

La version 2.0 introduce un modelo hibrido multiplicativo que resuelve el problema de scores enganosos:

Escenario Score v1.0 Score v2.0
2 findings HIGH ~93 (Level 1) ~49 (Level 0)
1 CRITICAL ~90 ~37

Cambios principales: - Eliminados limites por categoria - Penalizaciones aumentadas (CRITICAL: 25, HIGH: 15, MEDIUM: 5) - Multiplicador de severidad para efecto compuesto - Score alineado con expectativas de Level


2. Arquitectura del Sistema

2.1 Componentes

+------------------+
|    Findings      |  <-- Lista de hallazgos
+------------------+
        |
        v
+------------------+
|   Calculator     |  <-- internal/msss/msss.go
+------------------+
        |
        +---> Direct Penalties (sin limite)
        +---> Severity Multiplier (compuesto)
        |
        v
+------------------+
|      Score       |
| - Total (0-100)  |
| - Level (0-3)    |
| - Categories     |
| - Details        |
+------------------+

2.2 Estructura del Score

type Score struct {
    Total      float64                    `json:"total"`       // 0-100
    Categories map[string]CategoryScore   `json:"categories"`  // Por clase
    Version    string                     `json:"version"`     // "2.0"
    Compliant  bool                       `json:"compliant"`   // >= Level 1
    Level      int                        `json:"level"`       // 0-3
    Details    *ScoreDetails              `json:"details"`     // Desglose
}

type CategoryScore struct {
    Score     float64 `json:"score"`      // Score actual
    MaxScore  float64 `json:"max_score"`  // Maximo posible
    Weight    float64 `json:"weight"`     // Peso en total
    Findings  int     `json:"findings"`   // Numero de hallazgos
    Penalties float64 `json:"penalties"`  // Penalizaciones
}

type ScoreDetails struct {
    BaseScore          float64            `json:"base_score"`           // Siempre 100
    Penalties          float64            `json:"penalties"`            // Total penalizaciones
    SeverityMultiplier float64            `json:"severity_multiplier"`  // Multiplicador compuesto
    CriticalCount      int                `json:"critical_count"`       // Conteo de criticals
    HighCount          int                `json:"high_count"`           // Conteo de highs
    Bonuses            float64            `json:"bonuses"`              // Bonificaciones
    FindingsPenalty    map[string]float64 `json:"findings_penalty"`     // Por finding
}

3. Formula de Scoring v2.0

3.1 Formula Principal

FinalScore = max(0, 100 - DirectPenalties) × SeverityMultiplier

3.2 Pasos del Calculo

  1. Sumar penalizaciones directas (sin limite por categoria)
  2. Calcular multiplicador de severidad (efecto compuesto)
  3. Aplicar formula

4. Penalizaciones Directas

4.1 Penalizacion Base por Severidad (v2.0)

Severidad Penalizacion Base Cambio vs v1.0
Critical 25.0 +150% (era 10.0)
High 15.0 +200% (era 5.0)
Medium 5.0 +150% (era 2.0)
Low 1.0 +100% (era 0.5)
Info 0.2 +100% (era 0.1)

4.2 Multiplicador de Confianza

Confianza Multiplicador
High 1.0 (100%)
Medium 0.7 (70%)
Low 0.4 (40%)

4.3 Multiplicador MCP Context

Contexto Multiplicador
En tool handler 1.3 (+30%)
Fuera de tool 1.0

4.4 Formula de Penalizacion Individual

Penalizacion = Base_Severidad × Factor_Confianza × Factor_MCP

Donde:
- Base_Severidad: {Critical: 25, High: 15, Medium: 5, Low: 1, Info: 0.2}
- Factor_Confianza: {High: 1.0, Medium: 0.7, Low: 0.4}
- Factor_MCP: {En tool: 1.3, Fuera: 1.0}

4.5 Codigo

func (c *Calculator) calculatePenalty(f types.Finding) float64 {
    var base float64
    switch f.Severity {
    case types.SeverityCritical:
        base = 25.0  // Era 10.0
    case types.SeverityHigh:
        base = 15.0  // Era 5.0
    case types.SeverityMedium:
        base = 5.0   // Era 2.0
    case types.SeverityLow:
        base = 1.0   // Era 0.5
    case types.SeverityInfo:
        base = 0.2   // Era 0.1
    }

    // Multiplicador de confianza
    var confMult float64
    switch f.Confidence {
    case types.ConfidenceHigh:
        confMult = 1.0
    case types.ConfidenceMedium:
        confMult = 0.7
    case types.ConfidenceLow:
        confMult = 0.4
    }

    // Multiplicador MCP
    mcpMult := 1.0
    if f.MCPContext != nil {
        mcpMult = 1.3
    }

    return base * confMult * mcpMult
}

5. Multiplicador de Severidad

5.1 Concepto

El multiplicador de severidad proporciona un efecto compuesto para multiples hallazgos HIGH/CRITICAL. Esto asegura que 2 HIGHs tengan un impacto mucho mayor que 1 HIGH.

5.2 Valores del Multiplicador

Para CRITICAL findings:

Criticals Multiplicador Formula
1 0.50 0.50 - 0×0.15
2 0.35 0.50 - 1×0.15
3+ 0.25 min(0.25)

Para HIGH findings (si no hay CRITICAL):

Highs Multiplicador Formula
1 0.85 1.0 - 1×0.15
2 0.70 1.0 - 2×0.15
3 0.55 1.0 - 3×0.15
4+ 0.45 min(0.45)

Sin HIGH/CRITICAL: multiplicador = 1.0

5.3 Codigo

func (c *Calculator) calculateSeverityMultiplier(criticalCount, highCount int) float64 {
    if criticalCount >= 1 {
        // Critical: 0.50, 0.35, 0.25 (min)
        return math.Max(0.25, 0.50-float64(criticalCount-1)*0.15)
    }
    if highCount >= 1 {
        // High: 0.85, 0.70, 0.55, 0.45 (min)
        return math.Max(0.45, 1.0-float64(highCount)*0.15)
    }
    return 1.0
}

6. Niveles de Certificacion

6.1 Tabla de Niveles

Nivel Nombre Requisitos Target
0 No Certified < 60 OR criticals > 0 OR highs > 3 -
1 Basic >= 60, 0 critical, <= 3 high OSS
2 Secure >= 80, 0 high, 0 critical PRO
3 Certified >= 90, 0 high, 0 critical Enterprise

6.2 Algoritmo de Nivel

func (c *Calculator) determineLevel(total float64, findings []types.Finding) int {
    criticalCount := countBySeverity(findings, types.SeverityCritical)
    highCount := countBySeverity(findings, types.SeverityHigh)

    // Level 0: cualquier critical, score < 60, o > 3 high
    if criticalCount > 0 || total < 60 || highCount > 3 {
        return 0
    }

    // Level 2/3: requiere 0 high
    if highCount == 0 {
        if total >= 90 {
            return 3
        }
        if total >= 80 {
            return 2
        }
    }

    // Level 1: >= 60, no critical, 1-3 high
    return 1
}

6.3 Diagrama de Decision

                    +----------------+
                    | criticals > 0? |
                    +----------------+
                      |yes        |no
                      v           v
                 Level 0    +----------------+
                            | score < 60?    |
                            +----------------+
                              |yes       |no
                              v          v
                         Level 0   +----------------+
                                   | highs > 3?     |
                                   +----------------+
                                     |yes       |no
                                     v          v
                                Level 0   +----------------+
                                          | highs == 0?    |
                                          +----------------+
                                            |no        |yes
                                            v          v
                                       Level 1   +----------------+
                                                 | score >= 90?   |
                                                 +----------------+
                                                   |no        |yes
                                                   v          v
                                              Level 2    Level 3

7. Ejemplos de Calculo

7.1 Ejemplo 1: Servidor Limpio

Findings: Ninguno

Penalizaciones = 0
Multiplicador = 1.0
Score = (100 - 0) × 1.0 = 100
Level = 3

7.2 Ejemplo 2: Un HIGH Finding

Findings: 1 HIGH, High confidence

Penalizacion = 15.0 × 1.0 × 1.0 = 15.0
Multiplicador = 0.85 (1 high)
Score = (100 - 15) × 0.85 = 72.25
Level = 1 (>= 60, 1 high <= 3)

7.3 Ejemplo 3: Dos HIGH Findings

Findings: 2 HIGH, High confidence

Penalizaciones = 15.0 + 15.0 = 30.0
Multiplicador = 0.70 (2 high)
Score = (100 - 30) × 0.70 = 49.0
Level = 0 (score < 60)

7.4 Ejemplo 4: Un CRITICAL Finding

Findings: 1 CRITICAL, High confidence

Penalizacion = 25.0 × 1.0 × 1.0 = 25.0
Multiplicador = 0.50 (1 critical)
Score = (100 - 25) × 0.50 = 37.5
Level = 0 (critical presente)

7.5 Ejemplo 5: Cinco MEDIUM Findings

Findings: 5 MEDIUM, High confidence

Penalizaciones = 5.0 × 5 = 25.0
Multiplicador = 1.0 (no high/critical)
Score = (100 - 25) × 1.0 = 75.0
Level = 1 (>= 60, < 80, no high)

7.6 Ejemplo 6: Mixto (2 HIGH + 3 MEDIUM)

Findings: 2 HIGH + 3 MEDIUM, High confidence

Penalizaciones = (15.0 × 2) + (5.0 × 3) = 45.0
Multiplicador = 0.70 (2 high)
Score = (100 - 45) × 0.70 = 38.5
Level = 0 (score < 60)

8. Pesos por Categoria

8.1 Tabla de Pesos

Los pesos suman 100% y reflejan el impacto relativo de cada clase:

Clase Nombre Peso Justificacion
A RCE 22.0% Maximo impacto - compromiso total
B Filesystem 13.0% Acceso a datos sensibles
C SSRF 10.0% Puede escalar a RCE interno
D SQLi 10.0% Compromiso de base de datos
E Secrets 10.0% Credenciales comprometen todo
F Auth 8.0% Bypass de autenticacion
G Tool Poisoning 8.0% Especifico de MCP
H Declaration Mismatch 5.0% Engano al usuario
I Multi-Tool Flow 4.0% Requiere combinacion
J Memory Injection 3.0% Impacto diferido
K Task Queue 3.0% Impacto diferido
N Supply Chain 4.0% Riesgo externo
Total 100.0%

9. Output del Score

9.1 JSON Output

{
  "total": 49.0,
  "level": 0,
  "compliant": false,
  "version": "2.0",
  "categories": {
    "A": {
      "score": 7.0,
      "max_score": 22.0,
      "weight": 22.0,
      "findings": 1,
      "penalties": 15.0
    },
    "B": {
      "score": 0.0,
      "max_score": 13.0,
      "weight": 13.0,
      "findings": 1,
      "penalties": 15.0
    }
  },
  "details": {
    "base_score": 100.0,
    "penalties": 30.0,
    "severity_multiplier": 0.70,
    "critical_count": 0,
    "high_count": 2,
    "bonuses": 0,
    "findings_penalty": {
      "finding-1": 15.0,
      "finding-2": 15.0
    }
  }
}

9.2 Uso en CLI

$ mcp-scan scan ./server.py

MSSS Score: 49.0 / 100
Level: 0 (Not Certified)

Score Breakdown:
  Base Score:          100.0
  Total Penalties:     -30.0
  Severity Multiplier: ×0.70 (2 HIGH findings)
  Formula: (100 - 30) × 0.70 = 49.0

Category Breakdown:
  A (RCE):         7.0 / 22.0  [1 finding, -15.0]
  B (Filesystem):  0.0 / 13.0  [1 finding, -15.0]
  C (SSRF):       10.0 / 10.0  [0 findings]
  ...

Findings:
  [HIGH] MCP-A001: Tool input flows to command execution
    Location: server.py:15
    Penalty: -15.0
  [HIGH] MCP-B001: Path traversal in file read
    Location: server.py:42
    Penalty: -15.0

10. Comparacion v1.0 vs v2.0

Aspecto v1.0 v2.0
Formula Suma por categorias Hibrido multiplicativo
Limites por categoria Si No
Penalizacion HIGH 5.0 15.0
Penalizacion CRITICAL 10.0 25.0
Efecto compuesto Debil (0.1/critical) Fuerte (multiplicador)
2 HIGH findings ~93 (enganoso) ~49 (preciso)
Alineacion score-level Pobre Fuerte

11. Interpretacion para Analistas

11.1 Score Alto (90-100)

  • Servidor muy seguro
  • Solo hallazgos informativos o low
  • Candidato a Level 3
  • Accion: Mantenimiento

11.2 Score Medio-Alto (70-89)

  • Buena postura de seguridad
  • Maximo 1 HIGH
  • Candidato a Level 1-2
  • Accion: Remediar HIGH para Level 2+

11.3 Score Medio (50-69)

  • Problemas de seguridad moderados
  • 1-2 HIGH o varios MEDIUM
  • Level 1 o 0
  • Accion: Priorizar remediacion

11.4 Score Bajo (< 50)

  • Problemas serios de seguridad
  • 2+ HIGH o CRITICAL presente
  • Level 0
  • Accion: Atencion urgente

11.5 Prioridad de Remediacion

  1. Primero: Eliminar CRITICAL (multiplicador 0.50)
  2. Segundo: Reducir HIGH a <= 1 (multiplicador 0.85)
  3. Tercero: Abordar MEDIUM en categorias de alto peso
  4. Ultimo: LOW e informativos

12. Helpers del Calculator

12.1 GetCriticalClasses

Obtiene las clases con hallazgos criticos:

func (c *Calculator) GetCriticalClasses(findings []types.Finding) []string

12.2 GetTopFindings

Obtiene los N hallazgos mas severos:

func (c *Calculator) GetTopFindings(findings []types.Finding, n int) []types.Finding

13. Limitaciones

13.1 Limitaciones del Scoring

  1. No considera contexto de negocio: Un SQLi en datos publicos vs privados tiene mismo peso
  2. Pesos fijos: No se ajustan por tipo de aplicacion
  3. No considera mitigaciones externas: Un hallazgo con WAF cuenta igual
  4. Multiplicador simplificado: No distingue entre tipos de HIGH

13.2 Recomendaciones

  1. Usar como guia, no como unica metrica
  2. Revisar hallazgos HIGH/CRITICAL manualmente
  3. Considerar contexto del servidor MCP
  4. Trackear mejora con scans regulares

Siguiente documento: superficie-mcp.md