1-SEC contributors · Reviewed · Module: data_poisoning
Training Dataset Integrity: Hash Changes and Bulk-Update Signals
Data Poisoning Guard compares each reported dataset hash with the previous nonempty hash for the same dataset ID.
What 1-SEC checks
Data Poisoning Guard compares each reported dataset hash with the previous nonempty hash for the same dataset ID. The first event establishes local state; a later unequal nonempty hash produces an integrity alert, including for an authorized change. After more than three earlier updates, a reported change percentage above both three times the historical average and 10 percent produces a bulk-change signal. The rolling average and last hash update after each event. Dataset events can also flag supplied template-execution or remote-loader configuration strings.
Required telemetry and context
Relevant input events: training_update, training_data_update, dataset_update, dataset_change, data_ingestion. Use a trusted producer at the real application boundary.
dataset_idsourcehashrecord_count (number)change_percent (number)dataset_config / loader_config / content (optional configuration text)
Field names above describe relevant context, not a complete API request. Consult the current event contract for envelope and detail requirements. Preserve booleans, numbers, and strings as the receiving handler expects them. Agent-provided text cannot independently verify identity or authorization.
Deployment, prevention, and response
Have a trusted ingestion pipeline compute and report dataset identifiers, digests, record counts and change percentages consistently. Keep approved version manifests and a durable change history outside this tracker. Review the producing job, authorization and intended data revision before quarantining a training run. Do not automatically bless a new source or hash because it appeared in an event. Test first-update and legitimate-change behavior alongside an unexpected change, and keep remote dataset code disabled in the actual loader.
Record the source event, affected agent/host, actual target, policy decision, and response result. Review enforcement configuration separately from detection. A recommendation, selected action, dry-run record, and completed action are different outcomes.
Reproduce the source fixtures
From a checkout of the linked 1-SEC source revision, run the selected fixtures with the repository's Go toolchain. These commands run tests; they do not execute a real attack against your systems.
go test ./internal/modules/datapoisoning -run '^(TestDataIntegrityTracker_FirstUpdate|TestDataIntegrityTracker_IntegrityViolation|TestDataIntegrityTracker_AnomalousChange|TestGuard_HandleEvent_DatasetUpdate_CleanConfig)$' -count=1The fixtures establish first-event behavior, unequal-hash reporting, the bulk-update threshold and an inert dataset configuration. They use synthetic reported hashes rather than hashing or authenticating a real training corpus. No production provenance or immutable-history integration was tested.
TestDataIntegrityTracker_FirstUpdate
Full fixture and assertions — run in its original package with its helpers.
func TestDataIntegrityTracker_FirstUpdate(t *testing.T) {
dt := NewDataIntegrityTracker()
result := dt.RecordUpdate("dataset-1", "trusted-source", "abc123", 1000, 5.0)
if result.IntegrityViolation {
t.Error("first update should not trigger IntegrityViolation")
}
if result.AnomalousChange {
t.Error("first update should not trigger AnomalousChange")
}
if result.UntrustedSource {
t.Error("first update should not trigger UntrustedSource (no trusted sources configured)")
}
}TestDataIntegrityTracker_IntegrityViolation
Full fixture and assertions — run in its original package with its helpers.
func TestDataIntegrityTracker_IntegrityViolation(t *testing.T) {
dt := NewDataIntegrityTracker()
dt.RecordUpdate("dataset-1", "source-a", "hash-v1", 1000, 5.0)
result := dt.RecordUpdate("dataset-1", "source-a", "hash-v2", 1000, 5.0)
if !result.IntegrityViolation {
t.Error("expected IntegrityViolation when hash changes")
}
if result.PreviousHash != "hash-v1" {
t.Errorf("PreviousHash = %q, want %q", result.PreviousHash, "hash-v1")
}
}TestDataIntegrityTracker_AnomalousChange
Full fixture and assertions — run in its original package with its helpers.
func TestDataIntegrityTracker_AnomalousChange(t *testing.T) {
dt := NewDataIntegrityTracker()
// Build up a baseline with small changes (need >3 updates)
dt.RecordUpdate("dataset-2", "src", "h1", 1000, 2.0)
dt.RecordUpdate("dataset-2", "src", "h2", 1000, 3.0)
dt.RecordUpdate("dataset-2", "src", "h3", 1000, 2.5)
dt.RecordUpdate("dataset-2", "src", "h4", 1000, 3.0)
// Now a large change: >3x average and >10%
result := dt.RecordUpdate("dataset-2", "src", "h5", 1000, 50.0)
if !result.AnomalousChange {
t.Error("expected AnomalousChange when change rate exceeds 3x average")
}
}TestGuard_HandleEvent_DatasetUpdate_CleanConfig
Full fixture and assertions — run in its original package with its helpers.
func TestGuard_HandleEvent_DatasetUpdate_CleanConfig(t *testing.T) {
cp := makeCapturingPipeline()
g := startedModuleWithPipeline(t, cp)
defer g.Stop()
ev := core.NewSecurityEvent("test", "dataset_update", core.SeverityInfo, "dataset update")
ev.Details["dataset_id"] = "clean-dataset"
ev.Details["source"] = "internal-curated"
ev.Details["hash"] = "sha256:trusted"
ev.Details["dataset_config"] = `{"format":"parquet","split":"train","streaming":false}`
if err := g.HandleEvent(ev); err != nil {
t.Fatalf("HandleEvent() error: %v", err)
}
if cp.hasAlertType("dataset_config_execution") {
t.Fatal("did not expect executable dataset configuration alert")
}
}Tuning, evaluation, and coverage limits
This is last-hash comparison, not a persistent dataset hash history, provenance ledger or proof of tampering. The module does not read the dataset and authenticate its digest for you. Missing IDs skip the handler; missing or empty hashes cannot establish a mismatch. Legitimate retraining and ingestion can trigger alerts. The internal trusted-source map is empty by default and has no demonstrated public provisioning path, so these events do not establish verified training-data provenance. State resets with the module; fixed heuristics are not exposed as tuning knobs.
Evaluate this behavior with representative authorized activity and a controlled known-positive case. Investigate the exact rule, inputs, and state before suppressing an alert. Do not assume a hard-coded heuristic is a configurable setting. Measure your own deployment; the source fixtures do not establish a benchmark, detection rate, compliance certification, or incident-prevention claim.
Protocol and format references
These references describe the underlying format or protocol. The implementation and fixtures above define the subset 1-SEC actually checks.
Related implemented controls
- RAG Document Poisoning: Retrieved-Content Verification
- Model Confidence Drift: Low-Confidence Signals and Distribution Windows
- Model Weight Integrity: Comparing Reported and Expected Hashes
- Model Registry Review: Missing Integrity Metadata and Lookalike Names
- Model Artifact Inspection: Pickle Indicators and SafeTensors Bounds