Control
Biometric templates stored with no retention limit or destruction path
Stored face or voice templates (for example a Rekognition collection or a vector store of face embeddings) are deleted when their purpose ends or within the period the governing law sets.
Informational data, not legal advice. Summaries are TwinEthos's own words and rules have not been reviewed by a lawyer: check the official text before relying on any of it. A guard addresses an item; adding it is not a statement that your code meets any law.
Reach
Law in force in Illinois (US-IL), Texas (US-TX).
The guard to add
Store each face or voice template with its purpose and an expiry, and run a scheduled job that deletes it from every store when the purpose ends or retention lapses.
Each template row or collection entry carries its purpose, last_interaction_at, and an expires_at computed from the written retention schedule. A scheduled deletion job (cron, Celery beat, EventBridge schedule) removes expired templates from every place they live, including the Rekognition collection (delete_faces with the FaceIds) and any vector index, and account closure or the end of the purpose triggers deletion right away. The retention schedule is published (privacy policy or biometric policy page in the site source) and kept in the repo so code and policy match; deletions are logged.
Where it goes: 1 application source code, 2 data models, 4 infrastructure-as-code, 14 user-facing text.
What reviewers look for: an expires_at or TTL on the template store; a deletion job calling delete_faces, a vector-store delete, or a purge that actually runs on a schedule and on account closure; a public biometric retention policy in the site source; deletion logs. A template write with no expiry and no delete path anywhere in the module is the failure.
Example (AWS Rekognition (boto3)), before:
resp = rekognition.index_faces(CollectionId='members', Image={'Bytes': img}, ExternalImageId=user_id)
db.faces.insert(user_id=user_id, face_id=resp['FaceRecords'][0]['Face']['FaceId'])After:
resp = rekognition.index_faces(CollectionId='members', Image={'Bytes': img}, ExternalImageId=user_id)
db.faces.insert(user_id=user_id, face_id=resp['FaceRecords'][0]['Face']['FaceId'],
purpose='door_access', expires_at=retention.expiry_for('door_access', now()))
def purge_expired_faces(): # scheduled daily
expired = db.faces.expired(before=now())
for batch in chunks(expired, 1000):
rekognition.delete_faces(CollectionId='members', FaceIds=[f.face_id for f in batch])
db.faces.delete_ids([f.id for f in batch])
deletion_log.record(len(batch), reason='retention_expired')Engineering guidance, not legal advice. Each provision below may add its own details (a cadence, a deadline, a required notice element): open it for those.
Every rule this guard addresses
Binding law — in force (2)
- Illinois (US-IL)
- Publish a biometric retention schedule and destroy face and voice templates on time (Illinois BIPA) 740 ILCS 14/15(a) · AI-adjacent law
- Texas (US-TX)
- Destroy captured face and voice biometrics within a year after their purpose expires (Texas) Tex. Bus. & Com. Code 503.001(c) · AI-adjacent law