AID-H-029.003: Consent Scope Tracking, Expiry Enforcement & Withdrawal Response
Pillars: data
Lifecycle: operation
Scope boundary
Owns propagation of consent expiry or withdrawal through active AI stages and operational removal, quarantine, index or memory purge, and impact flagging for affected data and derived artifacts. It does not perform model-level influence removal or poisoned-artifact remediation.
AID-R-001.002: AID-H-029.003 propagates the withdrawal event and identifies affected model use; AID-R-001.002 performs retraining or approximate unlearning to remove that data's model-level influence. Operational data purge does not prove influence removal from trained parameters.
AID-E-003: AID-H-029.003 responds to changed consent or authorized-use state; AID-E-003 removes poisoned data and backdoor artifacts during incident remediation. The trigger and success criteria differ even when both workflows delete data.
AID-I-004.005: AID-H-029.003 performs policy-triggered withdrawal response across lifecycle stages; AID-I-004.005 performs retention-expiry and forced-forgetting enforcement for memory state. Consent withdrawal can require immediate action before the normal retention deadline.
Implementation guidance
- AID-H-029.003-G001: Subscribe to consent grant, expiry, and withdrawal events and propagate those events to all relevant AI stage gates and data stores.
- AID-H-029.003-G002: Run a withdrawal-response workflow that quarantines the source asset and purges or redacts reachable online derived artifacts discovered through lineage.
- AID-H-029.003-G003: Trigger trained-model impact assessment for withdrawn data and route affected models into remediation or unlearning review.
- AID-H-029.003-G004: Produce consent compliance reports that compare current consent state to actual stage presence and derived-artifact presence for each tracked asset.
AID-H-029.003-G001
Concept:
Treat consent as a live signal, not a one-time database field. When consent changes, publish an event and make every downstream stage reevaluate its authorization.
Example Kafka event
{
"event_type": "consent_withdrawn",
"asset_id": "asset-123",
"subject_id": "user-456",
"timestamp": "2026-03-17T12:05:00Z"
}
Operational notes: Resolve the propagation SLO from the verified consent policy and measure every event against that bound. Measure that SLO because it becomes compliance evidence.
Production implementation
At the consent event consumer, verify issuer signature, event order/idempotency, subject/asset/scope and policy freshness, atomically update authoritative consent state, invalidate affected stage-gate caches and deny use until every required consumer acknowledges within the policy bound.
Independent verification
A separately credentialed verifier independently reads back or replays event log, consent state, consumer acknowledgements and gate decisions with replay, reorder, duplicate, late, missing-consumer and signature-failure fixtures, runs positive, negative, boundary, stale-policy, partial-population and dependency-failure fixtures, and reconciles the complete eligible population without trusting a component-supplied verdict.
AID-H-029.003-G002
Concept:
Consent withdrawal should immediately stop new use and then clean up every online derivative that can still influence model behavior or user-visible output. Keep this workflow focused on live stores such as RAG indexes, embeddings, memory, caches, and trace or redaction queues. Model-level remediation belongs to a separate downstream review step.
Example cleanup planner
# File: consent/withdrawal_online_cleanup.py
from dataclasses import dataclass
from typing import Literal
ActionType = Literal[
"quarantine_source",
"purge_rag_index",
"purge_embeddings",
"purge_memory",
"purge_cache",
"open_redaction_ticket",
]
@dataclass(frozen=True)
class CleanupAction:
asset_id: str
action: ActionType
target: str
def build_online_cleanup_actions(asset_id: str, lineage_view: dict) -> list[CleanupAction]:
actions = [CleanupAction(asset_id, "quarantine_source", "metadata_store")]
if lineage_view.get("rag_indexes", []):
for index_name in lineage_view["rag_indexes"]:
actions.append(CleanupAction(asset_id, "purge_rag_index", index_name))
actions.append(CleanupAction(asset_id, "purge_embeddings", index_name))
if lineage_view.get("memory_stores", []):
for store_name in lineage_view["memory_stores"]:
actions.append(CleanupAction(asset_id, "purge_memory", store_name))
if lineage_view.get("cache_prefixes", []):
for cache_prefix in lineage_view["cache_prefixes"]:
actions.append(CleanupAction(asset_id, "purge_cache", cache_prefix))
if lineage_view.get("trace_systems", []):
for system_name in lineage_view["trace_systems"]:
actions.append(CleanupAction(asset_id, "open_redaction_ticket", system_name))
return actions
def execute_cleanup_action(action: CleanupAction, clients: dict) -> dict:
if action.action == "quarantine_source":
clients["metadata"].mark_withdrawn(action.asset_id)
elif action.action == "purge_rag_index":
clients["rag"].delete_by_asset_id(index_name=action.target, asset_id=action.asset_id)
elif action.action == "purge_embeddings":
clients["embeddings"].delete_by_asset_id(index_name=action.target, asset_id=action.asset_id)
elif action.action == "purge_memory":
clients["memory"].delete_by_asset_id(store_name=action.target, asset_id=action.asset_id)
elif action.action == "purge_cache":
clients["cache"].delete_prefix(action.target)
elif action.action == "open_redaction_ticket":
clients["tickets"].create(
queue="privacy-redaction",
title=f"Redact withdrawn asset {action.asset_id} from {action.target}",
payload={"asset_id": action.asset_id, "system": action.target},
)
else:
raise ValueError(f"Unsupported action: {action.action}")
return {
"asset_id": action.asset_id,
"action": action.action,
"target": action.target,
"status": "completed",
}
Operational requirements
- Make every action idempotent so retries are safe.
- Record per-target evidence so partial completion is visible.
- Execute this workflow immediately after the consent event propagates through
AID-H-029.003 #1.
Action: Treat online cleanup as complete only when every reachable live store is either purged, quarantined, or routed into an approved redaction queue with evidence attached.
Production implementation
At withdrawal execution, freeze new use, traverse the authoritative lineage snapshot, quarantine the source, purge or redact each eligible online derivative through its owning store, verify post-action read denial/content state and record unresolved/offline derivatives as insufficient rather than complete.
Independent verification
A separately credentialed verifier independently reads back or replays the lineage closure, per-store action receipt and independent post-action read/probe across source, cache, feature, embedding, index, replica, retry and partial-failure fixtures, runs positive, negative, boundary, stale-policy, partial-population and dependency-failure fixtures, and reconciles the complete eligible population without trusting a component-supplied verdict.
AID-H-029.003-G003
Concept:
Online artifact cleanup does not answer the separate question of whether the withdrawn asset influenced a trained model. Handle that as a dedicated review workflow: identify the impacted models, capture why each model is affected, and route each one into the appropriate remediation or unlearning queue. Do not silently mix this with RAG or memory cleanup evidence.
Example impact assessment script
# File: consent/model_impact_review.py
from dataclasses import dataclass
from typing import Literal
ReviewAction = Literal["remediation_review", "unlearning_review", "promotion_hold"]
@dataclass(frozen=True)
class ModelImpactFinding:
model_id: str
asset_id: str
lifecycle_stage: str
action: ReviewAction
reason: str
def find_impacted_models(asset_id: str, training_runs: list[dict]) -> list[ModelImpactFinding]:
findings = []
for run in training_runs:
if asset_id not in run.get("source_asset_ids", []):
continue
stage = run.get("lifecycle_stage", "training")
if stage in {"training", "fine_tuning", "retraining"}:
action = "unlearning_review"
else:
action = "remediation_review"
findings.append(
ModelImpactFinding(
model_id=run["model_id"],
asset_id=asset_id,
lifecycle_stage=stage,
action=action,
reason=f"Asset {asset_id} appears in {stage} lineage for model {run['model_id']}",
)
)
return findings
def route_findings(findings: list[ModelImpactFinding], ticket_client) -> None:
for finding in findings:
ticket_client.create(
queue="model-remediation",
title=f"Review withdrawn data impact for {finding.model_id}",
payload={
"model_id": finding.model_id,
"asset_id": finding.asset_id,
"lifecycle_stage": finding.lifecycle_stage,
"recommended_action": finding.action,
"reason": finding.reason,
},
)
Evidence to persist
- The impacted model list and the lineage basis for each finding
- The ticket or workflow ID created for each model
- The current decision state for each model, such as
under_review,promotion_hold, orapproved_after_review
Action: Route every impacted model into a tracked remediation or unlearning workflow and keep that status separate from online-store purge evidence so reviewers can prove both obligations were handled.
Production implementation
At withdrawal impact assessment, join the exact withdrawn asset closure to model training manifests, classify exposure under signed policy, block affected promotion or continued use when required and issue a digest-bound remediation/unlearning review ticket; never claim the model was remediated from assessment alone.
Independent verification
A separately credentialed verifier independently reads back or replays training manifests, lineage join, model inventory, exposure decision and promotion/runtime hold with known-hit, no-hit, incomplete-manifest, stale-model and changed-artifact fixtures, runs positive, negative, boundary, stale-policy, partial-population and dependency-failure fixtures, and reconciles the complete eligible population without trusting a component-supplied verdict.
AID-H-029.003-G004
Concept:
A useful report shows what is authorized, where the asset actually exists now, and whether remediation is still pending.
Example report row
{
"asset_id": "asset-123",
"consent_state": "withdrawn",
"authorized_stages": [],
"actual_stages_present": ["rag_indexing", "memory_write"],
"pending_actions": ["purge_rag_index", "purge_memory_entries"]
}
Operational notes: Generate this report on a schedule and on demand for DPO or compliance review. It becomes much easier to defend your process when you can show both authorization intent and operational enforcement status side by side.
Production implementation
At report generation, independently snapshot authoritative consent, lineage, stage-gate and store inventories, reconcile the complete denominator, distinguish compliant, breach, insufficient, not-applicable and error states, sign the report and block a green assertion when any required source or population is missing.
Independent verification
A separately credentialed verifier independently reads back or replays source snapshots, joins, counts and sampled asset readbacks by recomputing the report with expired, withdrawn, orphan-derived, source-gap and clock-boundary fixtures, runs positive, negative, boundary, stale-policy, partial-population and dependency-failure fixtures, and reconciles the complete eligible population without trusting a component-supplied verdict.
Open-source tools
- Open Policy Agent (OPA)
- Apache Kafka
- NATS (event propagation)
- Temporal
- Celery (withdrawal-response orchestration)
- OpenMetadata
- DataHub
Commercial / hosted tools
- OneTrust Consent & Preferences
- BigID Consent & Preferences
- Securiti Consent Management Platform
- Collibra Data Lineage (lineage/reporting only; not consent authority)
- Privacera Platform (downstream policy enforcement only; consent source/events external)
Threat mappings
MITRE ATLAS
- AML.T0057 LLM Data Leakage (withdrawn or expired-consent data remains exposable)
MAESTRO
- Data Leakage (Cross-Layer) (withdrawn data remains in derived artifacts)
- Regulatory Non-Compliance by AI Security Agents (L6) (consent-withdrawal or expiry violations)
OWASP LLM Top 10 2026
- LLM02:2026 Sensitive Information Disclosure
OWASP ML Top 10 2023
- N/A
OWASP Top 10 for Agentic Applications 2026
- N/A
NIST Adversarial Machine Learning 2025
- NISTAML.036 Leaking information from user interactions (interaction data retained after consent withdrawal)
Cisco Integrated AI Security and Safety Framework
- AISubtech-8.3.3 Personally Identifiable Information Exposure (purges withdrawn data from active online use; model unlearning remains separate)
- AITech-8.2 Data Exfiltration / Exposure (purges withdrawn data from active online use; model unlearning remains separate)
- AITech-8.3 Information Disclosure (purges withdrawn data from active online use; model unlearning remains separate)
- AISubtech-14.1.2 Insufficient Access Controls (withdrawal freezes online use and independently verifies denied reads)
Google Secure AI Framework 2.0 - Risks
- UTD: Unauthorized Training Data (consent withdrawal must trigger removal from training pipelines)
- EDH: Excessive Data Handling (consent-expired data retained in AI systems is excessive handling)
- SDD: Sensitive Data Disclosure (withdrawn-consent data that persists remains exposable through model queries)
Databricks AI Security Framework 3.0
- Raw Data 1.8: Legality of data
- Platform 12.6: Lack of compliance
- Model Serving - Inference requests 9.10: Accidental exposure of unauthorized data to models