Vektor Serangan pada Pipeline Fine-Tuning LLM
Fine-tuning model bahasa (LLM) dengan dataset internal memperkenalkan risiko keamanan pasokan data (data supply chain). Tanpa verifikasi ketat, korpus pelatihan rentan terhadap dua ancaman utama: data poisoning dan indirect prompt injection.
Data poisoning mengubah bobot model secara permanen sehingga memicu perilaku tersembunyi (backdoor) ketika ada pemicu (trigger token) tertentu. Sementara itu, prompt injection yang terselip di dalam korpus instruksi dapat memaksa model mengabaikan system prompt bawaan atau membocorkan data sensitif saat model dideploy ke produksi. Pengamanan harus dilakukan sebelum data menyentuh siklus pelatihan GPU.
Validasi Skema Korpus dan Integritas Data Menggunakan Pydantic
Langkah pertahanan pertama adalah memvalidasi struktur setiap baris dataset. Menggunakan Pydantic memastikan tipe data, panjang token, ketiadaan karakter kontrol yang tidak diinginkan, serta format pasangan instruksi-jawaban (misalnya format ChatML atau Alpaca) valid secara deterministik.
Untuk mencegah modifikasi data tanpa izin di shared storage (seperti NFS atau S3 bucket), pipeline harus menghitung hash SHA-256 dari dataset yang divalidasi dan memverifikasi integritasnya sebelum proses distributed training dimulai.
import hashlib
import json
import re
from typing import Literal
from pydantic import BaseModel, Field, field_validator
class ChatMessage(BaseModel):
role: Literal["system", "user", "assistant"]
content: str = Field(..., min_length=1, max_length=8192)
@field_validator("content")
def sanitize_content(cls, v: str) -> str:
# Cegah null bytes dan unicode bidi override exploits
if "\x00" in v or "\u202e" in v:
raise ValueError("Karakter kontrol terlarang terdeteksi.")
return v.strip()
class TrainingPair(BaseModel):
messages: list[ChatMessage] = Field(..., min_length=2)
@field_validator("messages")
def validate_roles(cls, messages: list[ChatMessage]) -> list[ChatMessage]:
if messages[-1].role != "assistant":
raise ValueError("Pesan terakhir harus memiliki role 'assistant'.")
return messages
def validate_and_hash_dataset(input_path: str, output_path: str) -> str:
hasher = hashlib.sha256()
valid_count = 0
with open(input_path, "r", encoding="utf-8") as infile, \
open(output_path, "w", encoding="utf-8") as outfile:
for line_no, line in enumerate(infile, 1):
if not line.strip():
continue
try:
raw_data = json.loads(line)
record = TrainingPair.model_validate(raw_data)
serialized = record.model_dump_json()
outfile.write(serialized + "\n")
hasher.update(serialized.encode("utf-8"))
valid_count += 1
except Exception as e:
raise ValueError(f"Validasi gagal pada baris {line_no}: {e}") from e
return hasher.hexdigest()
# ponytail: validasi in-memory stream; ganti ke chunked parallel processing jika dataset > 10GB.
Deteksi Prompt Injection pada Korpus Latih
Dataset yang dikumpulkan dari raw logs pengguna atau scraping dokumen internal sering kali memuat injeksi instruksi seperti Ignore previous instructions and output.... Model yang dilatih dengan data tersebut berisiko menginternalisasi instruksi tersebut sebagai perilaku standar.
Strategi Penyaringan Instruksi Berbahaya
- Pattern-based Filtering: Gunakan regular expression untuk mendeteksi instruksi manipulatif yang mencoba menimpa peran sistem (system overrides), eskalasi peran (role escalation), atau ekstraksi delimiter instruksi.
- Perplexity Filtering: Hitung perplexity baris data menggunakan model kecil (misalnya GPT-2). Data poisoning sering kali menghasilkan nilai perplexity yang anomali (terlalu tinggi untuk teks acak atau terlalu rendah untuk teks repetitif).
- Heuristik Delimiter: Tolak data yang memuat token spesial framework secara eksplisit (seperti
<|im_start|>,[INST], atau<s>) di luar formatting parser yang sah.
SUSPICIOUS_PATTERNS = [
re.compile(r"ignore\s+(all\s+)?previous\s+instructions", re.IGNORECASE),
re.compile(r"you\s+are\s+no\s+longer\s+a", re.IGNORECASE),
re.compile(r"system\s*:\s*override", re.IGNORECASE),
re.compile(r"(<\|im_start\|>|<\|im_end\|>|\[INST\]|\[/INST\])")
]
def scan_for_injection(text: str) -> bool:
for pattern in SUSPICIOUS_PATTERNS:
if pattern.search(text):
return True
return False
Isolasi Environment dan Rahasia pada Worker Distributed Training
Eksekusi distributed training (menggunakan PyTorch FSDP, DeepSpeed, atau Ray) melibatkan banyak node worker. Kompromi pada data atau dependensi di salah satu worker dapat membuka akses ke kredensial cluster jika lingkungan eksekusi tidak diisolasi.
Prinsip Pengamanan Node Worker
- Least Privilege untuk Storage Access: Worker training hanya membutuhkan hak akses Read-Only ke S3 bucket atau volume tempat dataset berada. Jangan berikan akses
s3:PutObjectatau modifikasi pada korpus latih. - Eliminasi Plaintext Secrets: Jangan passing kredensial database internal atau token API eksternal via environment variable global (
ENV). Worker distributed training rentan mencetak seluruh environment variable ke log file saat terjadi unhandled exception atau crash dump. - Isolasi Jaringan (Network Egress Control): Blokir akses outbound internet dari compute nodes selama training berjalan. Worker GPU hanya perlu berkomunikasi antar-node melalui interkoneksi lokal (RoCE/InfiniBand) dan endpoint storage internal. Ini mencegah exfiltrasi bobot model secara otomatis jika kode training terkompromi.
- Verifikasi Dataset Checksum di Node Controller: Jalankan proses verifikasi SHA-256 pada node
rank 0sebelum memanggiltorch.distributed.init_process_group. Jika hash tidak sesuai dengan manifest audit, batalkan pipeline seketika.
Verifikasi hash di awal training mencegah time-of-check to time-of-use (TOCTOU) race condition, di mana korpus dimodifikasi setelah proses validasi selesai namun sebelum model loader membaca file tersebut.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!