Security & ML
PythonMachine LearningCybersecurityFederated Learning

Defending Federated Learning Against Byzantine Attacks with Multi-Krum

Sathya Seelan
Sathya Seelan
Full-Stack Developer
December 14, 2024•10 min read

“An in-depth exploration of differential privacy (DP-SGD) and Byzantine-robust aggregation algorithms in distributed cyber threat intelligence.”

In collaborative cyber threat detection, multiple organizations benefit from sharing network intrusion models without revealing raw telemetry, internal IP addresses, or proprietary payloads.

However, standard Federated Averaging (FedAvg) is extremely vulnerable to data-poisoning and gradient-inversion attacks. A single malicious client can corrupt the global model weights or reverse-engineer private network flows.

In this article, we examine how combining Differential Privacy (DP-SGD) with the Multi-Krum aggregation algorithm delivers Byzantine-resilient collaborative learning.


1. Threat Vectors in Federated Threat Detection#

When training across heterogeneous corporate networks (using datasets such as CICIDS2017):

  • Byzantine (Poisoning) Attacks: Malicious nodes submit artificially skewed gradient vectors to create backdoors or suppress detection for specific attack signatures (e.g., hiding brute-force SSH attacks).
  • Gradient Inversion: A curious aggregator reconstructs exact client training samples from transmitted gradient updates.
code
[ Client 1 (Benign) ]   ──►  Δw1 ──┐
[ Client 2 (Benign) ]   ──►  Δw2 ──┼──► [ Multi-Krum Filter ] ──► [ Global Aggregator ]
[ Client 3 (Malicious)] ──►  Δw3* ─┤        (Discards Δw3*)               │
[ Client 4 (Benign) ]   ──►  Δw4 ──┘                                      ▼
                                                                  [ Updated Global Model ]

2. Implementing Multi-Krum Aggregation#

Standard FedAvg computes the simple weighted arithmetic mean:

code
Δw_global = Σ (n_k / n) * Δw_k

In contrast, Krum evaluates the geometric distance between all submitted client updates. A malicious update that diverges significantly from the benign cluster is penalized and filtered out.

python
import torch
from typing import List

def multi_krum(updates: List[torch.Tensor], num_malicious: int, num_to_select: int) -> torch.Tensor:
    """
    Selects and averages the most representative updates using Multi-Krum.
    
    n: total clients
    f: tolerated malicious clients (assumes n >= 2f + 3)
    m: number of updates to average
    """
    n = len(updates)
    assert n >= 2 * num_malicious + 3, "Krum requirement n >= 2f + 3 violated"
    
    # Flatten updates into 1D vectors
    flat_updates = [torch.flatten(u) for u in updates]
    distances = torch.zeros((n, n))
    
    # Compute pairwise Euclidean distances
    for i in range(n):
      for j in range(i + 1, n):
        d = torch.norm(flat_updates[i] - flat_updates[j]) ** 2
        distances[i, j] = d
        distances[j, i] = d
        
    # Calculate Krum score for each client
    # Score = sum of squared distances to the (n - f - 2) closest neighbors
    scores = []
    num_neighbors = n - num_malicious - 2
    
    for i in range(n):
      sorted_dists, _ = torch.sort(distances[i])
      # Exclude distance to itself (0)
      score = torch.sum(sorted_dists[1:num_neighbors + 1])
      scores.append((score.item(), i))
      
    # Sort by lowest score (closest to cluster consensus)
    scores.sort(key=lambda x: x[0])
    selected_indices = [idx for _, idx in scores[:num_to_select]]
    
    # Average selected trusted updates
    stacked_selected = torch.stack([flat_updates[i] for i in selected_indices])
    aggregated = torch.mean(stacked_selected, dim=0)
    
    return aggregated.view_as(updates[0])

3. Bounding Privacy Leakage with Opacus DP-SGD#

To safeguard against gradient-inversion attacks on the client side, each client executes Differentially Private Stochastic Gradient Descent (DP-SGD) using Opacus:

python
from opacus import PrivacyEngine

privacy_engine = PrivacyEngine()

model, optimizer, train_loader = privacy_engine.make_private(
    module=model,
    optimizer=optimizer,
    data_loader=train_loader,
    max_grad_norm=1.2,       # Gradient clipping threshold
    noise_multiplier=0.8,     # Gaussian noise scale
)

# After training round
epsilon = privacy_engine.get_epsilon(delta=1e-5)
print(f"Privacy guarantee: (ε = {epsilon:.2f}, δ = 1e-5)")

4. Key Takeaways#

  1. 01Multi-Krum effectively defends against up to f adversarial nodes as long as n >= 2f + 3.
  2. 02Pairing DP-SGD clipping with Krum limits both individual gradient magnitude manipulation and reconstruction attacks.
  3. 03Real-time telemetry streaming via WebSockets allows threat analysts to visualize client participation and outlier scores live during FL training rounds.