GRC Security Program: Burn and Churn Coffee

Simulation

A full security program for a fictional coffee shop: risk register, 15 NIST 800-53 controls crosswalked to PCI DSS 4.0.1, an evidence pack with automated checks, a vendor risk assessment, and quarterly access reviews.

Verified Confirmed in the repo 2026-10-20. 15 controls, recounted row-by-row 2026-10-25: 3 implemented, 5 partial, 7 not yet, every open gap tracked to a POA&M item.

grc iam

At a glance

Problem
A small card-accepting business has no documented security program — no risk register, no mapped controls, no way to prove anything to an auditor or a partner.
What I built
A complete program for a fictional coffee shop — asset inventory, risk register, a 15-control matrix mapped to NIST SP 800-53 and crosswalked to PCI DSS 4.0.1, policies and procedures, an evidence pack with automated checks, a POA&M, a vendor risk assessment, and a quarterly access review.
Evidence
4 policies, 4 procedures, 4 incident-response playbooks, 15 controls (3 implemented, 5 partially, 7 not — every gap tracked to a POA&M item), a companion vendor assessment with 4 tracked findings, and an access review across 5 systems — all present in the repo.
Status
Simulation, for a fictional business ("Burn and Churn Coffee").

Verified Control matrix, policies, evidence pack, and POA&M confirmed present in the repo as of 2026-10-20. Control count recounted row-by-row from control-matrix.md on 2026-10-25: 15 controls — 3 Implemented, 5 Partially Implemented, 7 Not Implemented, each open gap tracked to a POA&M item. An earlier pass said 11, taken from the repo README's summary line, which is stale relative to the matrix it describes. The evidence-check fix described below was merged to main on 2026-10-21 and re-confirmed on 2026-10-25: the three scripts are now byte-distinct on the default branch. The 30-day login-staleness threshold in access_review_check.py is still a judgment call pending a check against PR-003's stated cadence — see 'What went wrong' below.

The problem

Most small businesses that take card payments have no formal security program — not because they don't care, but because building one from scratch (a risk register, a control matrix mapped to a real framework, evidence that controls are actually followed) is a specialized skill most owners don't have and can't easily hire for at a small scale. I built this project to practice that whole arc end to end, for a fictional business, so I could show the complete shape of the work: not just a policy document, but a program with evidence behind it.

What I built

Risk to evidence flow Risk leads to a control, which produces evidence, which is validated, and tracked in a POA&M. A separate vendor risk assessment feeds into the same POA&M as item POAM-013. Risk Control Evidence Validation POA&M Vendor risk assessment POAM-013
Risk leads to a control, which produces evidence, which is validated and tracked in a POA&M. A separate vendor risk assessment feeds into the same POA&M as POAM-013.

The program has five pieces that connect to each other rather than standing alone:

  1. Risk register and asset inventory — what the business has, what could go wrong.
  2. A 15-control matrix, mapped to NIST SP 800-53 and crosswalked to PCI DSS 4.0.1, so the controls answer to two audiences at once: a general security framework and the card-payment standard that actually applies to this business.
  3. Policies, procedures, and playbooks — 4 of each, the documents a control matrix needs to actually mean something.
  4. An evidence pack — Python scripts that read the business's real operational data (an access-review CSV, an incident log) and flag exceptions automatically, instead of someone eyeballing a spreadsheet once a quarter.
  5. A POA&M that tracks every open gap, including the companion vendor risk assessment of a simulated payroll vendor (inherent risk High, 4 findings, approved with conditions at Moderate residual risk) rolled in as POAM-013.

Decisions and trade-offs

What went wrong, and what I changed

When I was fact-checking this case study against the actual repo, I found something I'd gotten wrong: the evidence pack claims four distinct automated checks, including one that flags accounts missing MFA. Looking at the actual code, three of the four scripts — mfa_review_check.py, access_review_check.py, and privileged_access_review_check.py — are byte-for-byte identical. All three check privileged-access approval status against user-access-review.csv. None of them actually reads mfa-status.csv, even though that file exists in the evidence folder with real exception data in it (two accounts with MFA disabled).

This is exactly the kind of gap the program is supposed to catch — a control that exists on paper (four named checks) but isn't actually doing four different things. I'm leaving it visible here rather than quietly fixing the repo and pretending it was always right: the honest version of this project includes catching my own mistake.

The fix turned out to be simpler than expected: the scripts' own README already documented what each check was supposed to do — the code had just never caught up. mfa_review_check.py now reads mfa-status.csv and correctly flags both accounts with MFA disabled. access_review_check.py now checks all accounts (not just privileged ones) for incomplete review sign-off and stale login activity, instead of repeating the privileged-access logic. privileged_access_review_check.py turned out to be the one that was already correct — it's what got copy-pasted into the other two. All three were re-tested against the repo's real evidence data and produced the expected flags. The fix was merged to main on 2026-10-21, and the three scripts are byte-distinct on the default branch — re-confirmed 2026-10-25. One question it raised is still open: the staleness threshold access_review_check.py uses for login activity (30 days) isn't specified anywhere in the project's own procedures, so it remains a judgment call pending a check against PR-003-quarterly-access-review.md's actual cadence.

What's verified, and what isn't

What I'd do next

Links

Keep reading

Next: Workspace: A SharePoint-Style Intranet on Three Backends