Back to Cheat Sheets

πŸ•΅οΈ Membership Inference Attack

OWASP Machine Learning Security Top 10 - ML04

HIGH RISK

πŸ“‹ What Is It?

Membership Inference (MIA) is a privacy attack that determines whether a specific record was part of the model's training set. The attacker already holds the record; what they learn is a single bit-"was this exact example used to train the model?" That bit is often the disclosure itself: confirming a person's record was in an HIV-study or addiction-cohort dataset reveals they belong to that sensitive population. The signal is behavioural-models are more confident and lower-loss on data they trained on-and it often works with black-box query access alone.

ML04 OWASP Rank
One Bit IN vs OUT
Overfitting Root Driver

⚠️ Common Exploits

  • Confidence-Threshold: High confidence on the true label β‡’ likely member
  • Loss-Threshold: Low per-example loss β‡’ likely member (strong baseline)
  • Shadow-Model (Shokri et al.): Train imitations with known splits, learn a distinguisher
  • Label-Only: Members' labels are more stable under perturbation
  • White-Box Gradient/Activation: Smaller member gradients add signal
  • Calibrated / Likelihood-Ratio: Per-record calibration, reliable at low FPR
  • Outlier Targeting: Rare records are memorised and leak hardest

πŸ”΄ Attack Flow

1. Acquire target access (black-box API or white-box)
↓
2. Calibrate a distinguisher (shadow models / threshold)
↓
3. Query the target with candidate record x
↓
4. Map observed behaviour β†’ IN (member) or OUT
↓
5. IMPACT: "Was this person in the study?" answered!

❌ Vulnerable Code

# Bad: unconstrained forest MEMORISES the training set from sklearn.ensemble import RandomForestClassifier model = RandomForestClassifier( n_estimators=500, max_depth=None, # grow until pure -> ~100% train accuracy min_samples_leaf=1) # single-sample leaves memorise individuals model.fit(X_train, y_train) # Huge train/test gap = a wide-open membership signal # Bad: serving returns raw logits + the full softmax vector def predict(model, x): logits = model(x) return {"logits": logits.tolist(), # exact certainty signal "probs": F.softmax(logits, -1).tolist()} ← entropy/margin leak # Bad: train hard, no privacy mechanism, no early stopping for epoch in range(100): # no (epsilon, delta) -> no formal bound for x, y in train_loader: loss = criterion(model(x), y); loss.backward(); optimizer.step()

βœ… Secure Code

# Good: constrain capacity + gate on the generalisation gap from sklearn.ensemble import RandomForestClassifier model = RandomForestClassifier( n_estimators=300, max_depth=8, # less memorisation min_samples_leaf=20, max_features="sqrt").fit(X_train, y_train) gap = model.score(X_train, y_train) - model.score(X_test, y_test) assert gap < 0.05, "Overfitting gap too large -> membership leak risk" # Good: coarse, temperature-scaled output only - no logits, no full vector TEMPERATURE = 2.0 def predict(model, x): with torch.no_grad(): probs = F.softmax(model(x) / TEMPERATURE, -1) top_p, top_i = probs.max(dim=-1) return {"label": int(top_i), "confidence": round(float(top_p), 1)} # Good: DP-SGD with a MEANINGFUL epsilon is the only formal guarantee from opacus import PrivacyEngine model, optimizer, train_loader = PrivacyEngine().make_private_with_epsilon( module=model, optimizer=optimizer, data_loader=train_loader, epochs=60, target_epsilon=3.0, target_delta=1e-5, max_grad_norm=1.0)

βœ“ Prevention Checklist

  • Reduce overfitting (dropout, weight decay, early stopping, more data)
  • Track train βˆ’ validation gap as a privacy metric, and gate on it
  • Train with DP-SGD and a meaningful epsilon (the formal defence)
  • Report (epsilon, delta) with the accounting method
  • Return coarse labels; temperature-scale and clip confidences
  • Never expose logits or per-example loss
  • Authenticate, rate-limit, and monitor for perturbation-probing
  • Prefer black-box over white-box exposure for sensitive models
  • Minimise data; handle rare/outlier records deliberately
  • Audit with a loss-based MIA (measure AUC) before release

πŸ” Detection & Tools

Privacy Tooling:

Opacus (DP-SGD) TensorFlow Privacy IBM ART ML Privacy Meter scikit-learn AUC

Defensive Techniques:

Regularisation Temperature Scaling Output Clipping Rate Limiting Data Minimisation

How to Test:

  • Run a loss/confidence MIA on your own model; compute ROC AUC
  • AUC β‰ˆ 0.5 means no leak; near 1.0 means strong membership inference
  • Gate release on AUC below an agreed threshold
  • Test label-only attacks (perturbation-robustness probing)
  • Focus probes on rare/outlier records where the signal is strongest

🌍 Real-World

  • Shokri et al. Membership-Inference Work: Formalised MIA as a practical black-box attack against classification models, including models served by real ML-as-a-service platforms, using only prediction outputs and shadow models
  • Confidence-Free / Label-Only Attacks: Follow-on research showed hiding confidence scores is insufficient - membership leaks through how robust a predicted label is to small perturbations
  • DP / Privacy–Utility Tradeoff: Research established DP-SGD as a formal upper bound on membership inference, at a stated cost to accuracy
  • These are documented classes of published research; exact accuracy figures vary by dataset, model, and paper and are treated as illustrative.

πŸ“Œ Quick Tips

  • DO NOT assume anonymisation stops membership disclosure
  • DO NOT return raw logits or full softmax vectors
  • DO NOT call ad-hoc noise "differential privacy"
  • DO reduce overfitting and track the train/test gap
  • DO train with DP-SGD and a meaningful epsilon
  • DO rate-limit, authenticate, and monitor queries
  • DO audit the MIA AUC before you ship