Answer an access request and an erasure request from real data

applied · 80 min · Objective 5.4

Task

Build a small synthetic estate, then answer a subject access request and an erasure request against it, discovering in the process that you cannot answer either without an inventory, that deletion has more places to reach than anyone expects, and that erasure is not absolute.

Steps

  1. Build the estate: a user database, an application log containing the same identifiers, a backup archive of the database taken yesterday, a directory of exported reports, and an email-like mailbox directory. One synthetic person, identifier SUBJ-0007, appears in all five, and the backup store's name contains backup.
  2. Answer the access request: write /tmp/sar.sh which, given an identifier, locates and extracts every piece of data about that person across all five stores, and produces a single report with one line per store that holds them, store: <store name> ..., which is the line the Verify reads.
  3. Check it found all five. If it found four, the missing store is the one a real organisation also forgets.
  4. Now the erasure request. Write /tmp/erase.sh to remove the person from the live stores, then re-run the access script.
  5. Note what came back: the backup still holds them, and so may a record you are legally required to keep, such as an invoice. Record how you would handle each: erasure is not absolute where the law requires retention, and most regimes accept a documented retention period for backups provided the data is not restored into use.
  6. Write /tmp/privacy.md with both responses, the stores each reached, the backup position, what was retained and under which obligation, and the deadline each request carries.

Verify

bash /tmp/sar.sh SUBJ-0007 | grep -c "store:"
python3 - <<'PY'
import subprocess
def stores(ident):
    out=subprocess.run(['bash','/tmp/sar.sh',ident],capture_output=True,text=True).stdout
    return {l.split('store:')[1].strip().split()[0] for l in out.splitlines() if 'store:' in l}
before=stores('SUBJ-0007')
print('found in:',sorted(before))
assert len(before)>=5, 'the access request reached only %d store(s) - one is being missed' % len(before)
subprocess.run(['bash','/tmp/erase.sh','SUBJ-0007'],capture_output=True)
after=stores('SUBJ-0007')
print('after erasure, still present in:',sorted(after) or 'nowhere live')
assert after!=before, 'erasure removed nothing'
assert any('backup' in s.lower() for s in after), \
    'the backup no longer holds them - either it was wrongly modified, or it was never searched'
PY
grep -ciE "deadline|backup|retention|retain" /tmp/privacy.md

The last assertion is the interesting one and it asserts something surviving rather than disappearing. Erasure should NOT have reached into the backup: you do not rewrite backups to satisfy a deletion request, you document the retention period and ensure the data is not restored into use. A lab where the backup was edited has done the wrong thing correctly.

Notes

The store your script missed on the first attempt is the finding. In real estates it is usually the logs or the exports: data that was copied out of the system of record and is not in anybody's inventory, which is exactly why the data inventory is a privacy control. And the data you never collected is the data no request can reach, which is the argument for minimisation.

This is an independent study companion for CompTIA Security+ SY0-801 and is not produced by or endorsed by CompTIA.