Cybersecurity Risk Assessment with NIST CSF

Build a portfolio-ready GRC risk assessment for a fictional healthcare SaaS startup.

Introduction

30 Second Summary

Every company that handles sensitive data lives with an uncomfortable question: what happens when something goes wrong? A risk assessment is how security teams answer that question before a breach forces them to.

In this project, you will build a complete cybersecurity risk assessment for CloudMedix, a fictional healthcare startup that handles patient data. You will identify threats, score them using an industry-standard matrix, and map everything to the NIST Cybersecurity Framework 2.0.

What You'll Build

Picture opening your GitHub repository and walking someone through a color-coded risk register, a framework-backed control map, and a plain-language gap analysis that together pinpoint exactly where a company's security is exposed.

By the end of this project, you'll have:

  • A scored risk register in Google Sheets with 8-10 threats plotted on a color-coded heat map, showing at a glance which risks demand immediate attention.
  • A NIST CSF 2.0 control mapping that connects each risk to specific framework Functions and Categories, revealing exactly where security controls are missing.
  • A gap analysis written in plain language that a security leader could read and immediately understand where the company is exposed.
  • Secret Mission: A prioritized remediation roadmap with 0-30, 30-90, and 90+ day timelines that turns your findings into a concrete action plan.

Are there any prerequisites?

This project assumes a basic understanding of networking fundamentals, web architecture, and general IT concepts. No prior GRC experience is needed.

Before We Start

Before we dive in, let's lock in what you're about to build and why it matters.

Set Up Your GRC Repository

In a real compliance engagement, every change to a risk document needs an audit trail. When a regulator asks when a particular risk score was last updated, you need a clear answer.

A Git repository provides that audit trail automatically, tracking every edit across every file. In this step, you will create a GitHub repository and set up the folder structure that organizes your GRC deliverables.

In this step, get ready to:
  • Create a GitHub repository and clone it to your machine.
  • Build the folder structure for your GRC artifacts.
  • Write a README that describes the project and links to each deliverable.
Initialize the Git repository and folder structure

Your risk assessment needs a home that tracks every change you make. A GitHub repository gives you version history and a public URL you can share with employers.

  • Open your browser and go to github.com.
  • Sign in with your GitHub account.
  • Click the + icon in the top-right corner.
  • Select New repository.
  • Enter cloudmedix-risk-assessment as the Repository name.
  • Select Public for the repository visibility.
  • Check the Add a README file checkbox.
  • Click Create repository.

GitHub redirects you to your new repository page. You should see a single README.md file with the repository name as its heading.

Now bring this repository to your local machine so you can work on it in VS Code.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Terminal (macOS) or PowerShell (Windows) and press Enter to open it.
  • Move to your Desktop by running this command:
cd ~/Desktop
  • Clone your repository by running this command:
git clone https://github.com/[[GITHUB_USERNAME="your-github-username"]]/cloudmedix-risk-assessment.git

You should see output confirming that Git is cloning the repository and unpacking objects.

Find your clone URL quickly

If you are not sure of the exact URL, click the green Code button on your repository page in GitHub and copy the HTTPS link from there.

Clone command failed?

Make sure the URL matches your GitHub username exactly, including capitalization. Double-check that the repository name is cloudmedix-risk-assessment with hyphens, not underscores or spaces.

Help me troubleshoot my git clone error.

  • Move into your new project folder by running:
cd cloudmedix-risk-assessment

Your GRC artifacts need an organized folder structure. You will create three subdirectories and empty placeholder files for each document you will write throughout this project.

  • Create the folder structure and placeholder files by running these commands:

macOS

mkdir company-profile risk-assessment gap-analysis
touch company-profile/company-overview.md company-profile/asset-inventory.md
touch risk-assessment/threat-analysis.md
touch gap-analysis/gap-analysis.md

Windows

mkdir company-profile
mkdir risk-assessment
mkdir gap-analysis
New-Item company-profile\company-overview.md
New-Item company-profile\asset-inventory.md
New-Item risk-assessment\threat-analysis.md
New-Item gap-analysis\gap-analysis.md

What do these commands do?

mkdir creates directories. You are creating three: company-profile for your company overview and asset inventory, risk-assessment for your threat analysis, and gap-analysis for your final gap analysis document.

touch (macOS) and New-Item (Windows) create empty files. You will fill these in during later steps.

  • Confirm the files exist by running:
ls

You should see README.md, company-profile, gap-analysis, and risk-assessment listed.

Don't see all the folders?

Make sure you ran the commands from inside the cloudmedix-risk-assessment folder. Run pwd to check your current location. The output should end with cloudmedix-risk-assessment.

Help me fix my folder structure.

Create the README with project metadata

A good README acts as a landing page for anyone visiting your repository. It should explain what the project is, which framework it uses, and where to find each artifact.

  • Open your project in VS Code by running this command from inside the cloudmedix-risk-assessment folder:
code .

Command not found?

If code is not recognized, open VS Code manually. Press Cmd+Space (macOS) or the Windows key (Windows), type VS Code, and press Enter. Then click File, select Open Folder, and choose the cloudmedix-risk-assessment folder on your Desktop.

Help me open my project in VS Code.

  • In the VS Code Explorer sidebar on the left, click on README.md to open it.
  • Select all the existing content and replace it with the following:
# CloudMedix Risk Assessment

A portfolio-ready cybersecurity risk assessment for CloudMedix, a fictional cloud-based healthcare SaaS startup, conducted using the NIST Cybersecurity Framework (CSF) 2.0.

## Framework

NIST Cybersecurity Framework 2.0

## Artifacts

- [Company Overview](company-profile/company-overview.md)
- [Asset Inventory](company-profile/asset-inventory.md)
- [Threat Analysis](risk-assessment/threat-analysis.md)
- [Gap Analysis](gap-analysis/gap-analysis.md)

What does this README include?

The heading and opening paragraph tell visitors what this project is. The Framework section names NIST CSF 2.0 as the standard you are assessing against.

The Artifacts section links to each document you will create throughout this project. Once pushed to GitHub, these links become a clickable table of contents for visitors.

  • Save README.md by pressing Cmd+S (macOS) or Ctrl+S (Windows).

✔️ Awesome, I've got everything!

Great. Double check you have saved your file before moving on.

ⓧ I'd like to double check the full code

Here is the complete README.md file. Make sure yours matches exactly:

# CloudMedix Risk Assessment

A portfolio-ready cybersecurity risk assessment for CloudMedix, a fictional cloud-based healthcare SaaS startup, conducted using the NIST Cybersecurity Framework (CSF) 2.0.

## Framework

NIST Cybersecurity Framework 2.0

## Artifacts

- [Company Overview](company-profile/company-overview.md)
- [Asset Inventory](company-profile/asset-inventory.md)
- [Threat Analysis](risk-assessment/threat-analysis.md)
- [Gap Analysis](gap-analysis/gap-analysis.md)
Verify setup and push to GitHub

Your folder structure and README are ready locally. Now commit everything and push it to GitHub so your repository reflects all the work you just did.

  • Switch back to your terminal.
  • Git may open a browser window to authenticate during the push. If that happens, follow the prompts to sign in with your GitHub account.
  • Commit and push your changes by running these commands:
git add .
git commit -m "Add project structure and README"
git push

What do these Git commands do?

  • git add . stages all new and modified files, telling Git to include them in the next commit.
  • git commit -m saves a snapshot of your staged changes with a message describing what you did.
  • git push uploads your local commits to the remote repository on GitHub.

Push command failed?

If you see a permissions error, make sure you are signed in to the correct GitHub account. If you see a message about the remote branch being ahead, run git pull --rebase first, then try git push again.

Help me troubleshoot my git push error.

Before you check GitHub, what do you expect to see on your repository's main page?

  • Open your browser and go to your cloudmedix-risk-assessment repository page on GitHub.

You should see the company-profile, gap-analysis, and risk-assessment folders listed in the file browser. Below them, your README is rendered with the project description and clickable artifact links.

Don't see your folders on GitHub?

Empty directories do not appear on GitHub. Each folder needs at least one file inside it. If a folder is missing, check that you created the placeholder files (like company-overview.md) inside it. Run git status to see if any files are uncommitted, then add, commit, and push again.

Help me get my folders showing on GitHub.

Your GRC workspace is ready with version-controlled folders for every artifact you will create. Next up, you will define CloudMedix as a company and inventory every asset it needs to protect.

Define the Company and Inventory Assets

Your repository is structured and pushed to GitHub. Now it is time to fill those empty files with the foundation every risk assessment needs: a clear picture of the company you are assessing.

You cannot assess risk in a vacuum. A GRC analyst's first job on any engagement is to understand what the organization does, what sensitive data it handles, and what assets need protection. Without this scoping work, your risk register would be a list of generic threats disconnected from actual business impact.

In this step, get ready to:
  • Write a company profile documenting CloudMedix's business, tech stack, and security posture.
  • Build an asset inventory categorizing everything CloudMedix needs to protect.
  • Verify your documents are complete and push them to GitHub.
Write the CloudMedix company profile

A company profile captures the essential context an assessor needs before identifying risks. It documents what the business does, what technology it runs on, what sensitive data it handles, and how mature its current security posture is.

  • In VS Code, open company-profile/company-overview.md from the Explorer sidebar on the left.
  • Add the company heading, business description, and tech stack by pasting the following content into the file:
# CloudMedix Company Overview

## Business Description
CloudMedix is a 50-person healthcare SaaS startup providing a cloud-based patient portal. Patients can view medical records, message providers, and schedule appointments.

## Tech Stack
- Web application hosted on cloud infrastructure (Linux servers)
- PostgreSQL database
- REST API backend
- React frontend

What does this section document?

The Business Description sets the scope of the assessment. CloudMedix is a healthcare company, which immediately tells you it handles sensitive medical data and faces regulatory requirements.

The Tech Stack identifies the technologies you will evaluate for vulnerabilities. Each component (PostgreSQL database, React frontend, REST API) introduces its own threat surface.

  • Save company-overview.md.
  • You should see the # CloudMedix Company Overview heading followed by the Business Description and Tech Stack sections in your editor.

The business context is set. Now you need to document the data CloudMedix handles, the regulations it must follow, and how much (or little) security it currently has in place.

  • Add the remaining three sections below the Tech Stack list by pasting this content at the bottom of the file:
## Data Handled
- Protected Health Information (PHI): patient names, medical records, insurance details
- Employee PII
- Authentication credentials and API keys

## Regulatory Context
CloudMedix is subject to HIPAA requirements as a Business Associate handling PHI.

## Current Security Posture
The company is early stage. It has basic authentication on its application but no formal security program, no documented policies, and no dedicated security team. The CTO handles security part-time.

Why does the security posture matter?

The Data Handled section reveals the highest-value targets. PHI (Protected Health Information) is one of the most heavily regulated data types in the industry.

The Current Security Posture tells you what defenses already exist. CloudMedix has almost none. That gap between "handles PHI" and "no formal security program" is exactly what your risk assessment will expose.

  • Save company-overview.md.
  • Your file now has five sections: Business Description, Tech Stack, Data Handled, Regulatory Context, and Current Security Posture.

What is HIPAA?

HIPAA is a US federal law that governs how healthcare data must be protected. Any company that handles PHI, even as a third-party service provider (called a Business Associate), must meet HIPAA's security and privacy requirements. Violations can result in significant fines.

File looking wrong in VS Code?

Make sure each ## heading has a blank line before it. Markdown needs blank lines to separate sections properly.

If bullet points are not rendering, check that each line starts with - (a dash followed by a space).

Help me fix my Markdown formatting in company-overview.md

✔️ Awesome, I've got everything!

Double check you have saved company-overview.md with all five sections.

ⓧ I'd like to double check the full code

Here is the complete company-overview.md file. Compare it against yours:

# CloudMedix Company Overview

## Business Description
CloudMedix is a 50-person healthcare SaaS startup providing a cloud-based patient portal. Patients can view medical records, message providers, and schedule appointments.

## Tech Stack
- Web application hosted on cloud infrastructure (Linux servers)
- PostgreSQL database
- REST API backend
- React frontend

## Data Handled
- Protected Health Information (PHI): patient names, medical records, insurance details
- Employee PII
- Authentication credentials and API keys

## Regulatory Context
CloudMedix is subject to HIPAA requirements as a Business Associate handling PHI.

## Current Security Posture
The company is early stage. It has basic authentication on its application but no formal security program, no documented policies, and no dedicated security team. The CTO handles security part-time.
Build the asset inventory

An asset inventory catalogs everything the company needs to protect. Without it, you cannot know what is at risk. Each asset gets classified by category, sensitivity, and ownership so your later threat analysis targets real things, not abstractions.

  • In VS Code, open company-profile/asset-inventory.md from the Explorer sidebar.
  • Add the asset inventory table by pasting the following content into the file:
# CloudMedix Asset Inventory

| Asset Name | Category | Description | Data Sensitivity | Owner |
|---|---|---|---|---|
| Patient Database | Information | PostgreSQL database storing PHI including names, medical records, insurance details | High | CTO |
| Employee Records | Information | HR files containing employee PII | High | HR Lead |
| API Keys and Credentials | Information | Application secrets, third-party integration credentials | High | CTO |
| Application Logs | Information | Web and API access logs | Medium | Engineering Lead |
| Developer Laptops | Hardware | Laptops used by engineering team, may store credentials and code | High | Engineering Lead |
| Cloud Server Instances | Hardware | Linux servers hosting the patient portal and API | High | CTO |
| Patient Portal Web Application | Software | React frontend and REST API backend | High | Engineering Lead |
| PostgreSQL Database Software | Software | Database engine managing PHI storage | High | CTO |
| Third-Party Payment Processor Integration | Software | Integration with external payment provider | High | CTO |
| Engineering Team | People | Developers with access to production systems and PHI | High | Engineering Lead |
| CTO | People | Handles security responsibilities part-time in addition to technical leadership | High | CEO |
| Office Space and Server Room | Physical | Physical office with server room access | Medium | Office Manager |

Why five asset categories?

Assets are not just servers and databases. The five categories ensure nothing gets overlooked:

  • Information covers the data itself (the patient database, credentials, logs).
  • Hardware covers physical and cloud infrastructure that processes or stores data.
  • Software covers applications and integrations that touch sensitive data.
  • People covers anyone with access to sensitive systems. People are often the weakest link.
  • Physical covers locations where unauthorized physical access could lead to data compromise.
  • Save asset-inventory.md.
  • You should see a Markdown table with 12 rows of assets spanning all five categories. Each row has all five columns filled in: Asset Name, Category, Description, Data Sensitivity, and Owner.

Table not rendering correctly?

Markdown tables require a separator row (|---|---|---|---|---|) directly below the header row. If you see plain text instead of a table, check that this row is present.

Each row must have the same number of pipe | characters. A missing pipe will shift all the columns.

Help me fix my Markdown table formatting in asset-inventory.md

✔️ Awesome, I've got everything!

Double check you have saved asset-inventory.md with all 12 assets.

ⓧ I'd like to double check the full code

Here is the complete asset-inventory.md file. Compare it against yours:

# CloudMedix Asset Inventory

| Asset Name | Category | Description | Data Sensitivity | Owner |
|---|---|---|---|---|
| Patient Database | Information | PostgreSQL database storing PHI including names, medical records, insurance details | High | CTO |
| Employee Records | Information | HR files containing employee PII | High | HR Lead |
| API Keys and Credentials | Information | Application secrets, third-party integration credentials | High | CTO |
| Application Logs | Information | Web and API access logs | Medium | Engineering Lead |
| Developer Laptops | Hardware | Laptops used by engineering team, may store credentials and code | High | Engineering Lead |
| Cloud Server Instances | Hardware | Linux servers hosting the patient portal and API | High | CTO |
| Patient Portal Web Application | Software | React frontend and REST API backend | High | Engineering Lead |
| PostgreSQL Database Software | Software | Database engine managing PHI storage | High | CTO |
| Third-Party Payment Processor Integration | Software | Integration with external payment provider | High | CTO |
| Engineering Team | People | Developers with access to production systems and PHI | High | Engineering Lead |
| CTO | People | Handles security responsibilities part-time in addition to technical leadership | High | CEO |
| Office Space and Server Room | Physical | Physical office with server room access | Medium | Office Manager |
Verify your documents and push to GitHub

Before moving on, review both documents for completeness. A real GRC engagement treats scoping documents as deliverables, not scratch notes.

  • Read through company-overview.md from top to bottom.
  • Confirm you can answer three questions from the document alone: What does this company do? What sensitive data does it hold? What is its current security posture?
  • Switch to asset-inventory.md and verify that every row has all five fields completed: Asset Name, Category, Description, Data Sensitivity, and Owner.

Before you check GitHub, think about what you expect to see. Which files should look different from your last push?

  • Commit and push your changes by running these commands in the VS Code terminal:
git add .
git commit -m "Add company profile and asset inventory"
git push
  • Open your cloudmedix-risk-assessment repository on GitHub in your browser.
  • Click into the company-profile folder.
  • Click on company-overview.md. You should see your five sections rendered with formatted headings and bullet lists.
  • Go back to the company-profile folder and click on asset-inventory.md. You should see a formatted table with 12 asset rows and all five columns.

Why push to GitHub after each step?

Version control is not just for code. In real GRC work, maintaining an audit trail of when documents were created and updated is a compliance requirement. Each commit timestamps your work and proves when a risk was identified or a control gap was documented.

Push failed or files not showing on GitHub?

If the push fails with an authentication error, make sure you are signed into Git with the same GitHub account that owns the repository.

If the files appear on GitHub but show no content, check that you saved both files in VS Code before running git add .. Unsaved changes are not picked up by Git.

Help me push my GRC documents to GitHub

You now have a scoped, documented picture of CloudMedix. Next up, you will use this profile to identify specific threats and vulnerabilities that could harm the company and its patients.

Identify Threats and Vulnerabilities

In the last step, you scoped the engagement by documenting who CloudMedix is, what data it handles, and what assets it needs to protect.

An asset inventory tells you what to protect, but not what could go wrong. This step forces you to think like an attacker: for each asset, what threats exist, and what weaknesses could someone exploit?

In this step, get ready to:
  • Identify realistic threats and vulnerabilities for each asset CloudMedix needs to protect.
  • Tag each threat with the NIST CSF 2.0 Function it falls under.
  • Validate that your threat list covers the right range and push it to GitHub.
Identify threats for each asset category

Your tech background is directly applicable here. You know what SQL injection is, you know what an unpatched server means, and you understand what happens when traffic is unencrypted.

For each threat you document, you will capture three things: the threat itself (what could happen), the vulnerability it exploits (what weakness enables it), and the potential impact (what the business consequence would be).

  • Open risk-assessment/threat-analysis.md in VS Code. This file already exists but is empty.
  • Paste the following header and first three threats into the file:
# CloudMedix Threat Analysis

## Threat-Vulnerability Pairs

### T-01: SQL Injection on Patient Portal
- **Threat:** Attacker executes SQL injection against the patient portal search or input fields
- **Vulnerability:** Unsanitized user input in database queries
- **Potential Impact:** Unauthorized access to PHI, HIPAA breach notification required, regulatory fines

### T-02: Credential Stuffing Against User Accounts
- **Threat:** Attacker uses leaked credential lists to gain unauthorized access to patient accounts
- **Vulnerability:** No multi-factor authentication (MFA), no account lockout policy
- **Potential Impact:** Unauthorized PHI access, account takeover, HIPAA violation

### T-03: Phishing Attack Targeting Employees
- **Threat:** Employee clicks malicious link or attachment, leading to credential theft or malware installation
- **Vulnerability:** No security awareness training, no email filtering controls
- **Potential Impact:** Compromised employee credentials, lateral movement to production systems, PHI exposure

What does this format capture?

Each entry follows the Threat + Vulnerability + Potential Impact pattern. The threat names the attack scenario. The vulnerability names the specific weakness that makes the attack possible. The impact names the business consequence, including any regulatory fallout.

Notice how T-01 connects directly to your asset inventory. The Patient Portal Web Application asset from your inventory is the target. T-02 and T-03 connect to the lack of controls you documented in the company overview.

  • Save threat-analysis.md.
  • You should see three numbered threat entries (T-01 through T-03) below the heading.

Those first three threats focus on direct attacks against the application. The next group focuses on data protection and access control gaps.

  • Add the following four threats below T-03 in threat-analysis.md:
### T-04: Unencrypted PHI in Transit
- **Threat:** Network attacker intercepts patient data transmitted between client and server
- **Vulnerability:** Inconsistent or missing TLS enforcement on API endpoints
- **Potential Impact:** PHI exposure, HIPAA violation, patient harm

### T-05: Misconfigured Cloud Storage Exposing PHI
- **Threat:** Cloud storage bucket or database is accidentally made publicly accessible
- **Vulnerability:** No cloud configuration review process, no automated misconfiguration detection
- **Potential Impact:** Mass PHI exposure, regulatory fines, reputational damage

### T-06: Insider Threat - Unauthorized PHI Access
- **Threat:** Employee accesses patient records beyond their job function
- **Vulnerability:** No role-based access control (RBAC), no access review process
- **Potential Impact:** HIPAA violation, patient privacy breach, legal liability

### T-07: Undetected Security Breach
- **Threat:** Attacker maintains persistent access to systems without detection
- **Vulnerability:** No logging, monitoring, or alerting in place
- **Potential Impact:** Prolonged PHI exposure, delayed breach response, increased regulatory penalties

Why these four threats?

T-04 and T-05 target data at rest and in transit. Your networking knowledge tells you that unencrypted traffic and misconfigured storage are two of the most common causes of data breaches.

T-06 covers insider threats, which are especially dangerous in a small company where developers may have broad access to production data. T-07 covers the inability to detect a breach. Without monitoring, an attacker could sit inside CloudMedix's systems for months.

  • Save threat-analysis.md.
  • You should now see seven threat entries (T-01 through T-07) in the file.

The final three threats address what happens when things go wrong and the organization has no way to respond, recover, or govern itself.

  • Add the last three threats below T-07 in threat-analysis.md:
### T-08: No Incident Response Capability
- **Threat:** A security incident occurs with no documented process to contain or recover from it
- **Vulnerability:** No incident response plan exists
- **Potential Impact:** Extended downtime, uncontrolled breach spread, failure to meet HIPAA breach notification timelines

### T-09: Data Loss Due to Missing Backups
- **Threat:** Ransomware or accidental deletion destroys patient data with no recovery path
- **Vulnerability:** No documented backup or disaster recovery process
- **Potential Impact:** Permanent PHI loss, inability to restore services, HIPAA violation

### T-10: No Formal Security Governance
- **Threat:** Security decisions are made ad hoc with no policy framework, leading to inconsistent controls
- **Vulnerability:** No security policies, no risk management program, no defined security roles
- **Potential Impact:** Systemic control failures across all risk areas, inability to demonstrate HIPAA compliance

Why include governance and process failures?

T-08, T-09, and T-10 are not technical attacks. They are organizational failures. A real risk assessment covers more than just hacking scenarios.

Without an incident response plan, even a minor breach can spiral into a company-ending event. Without backups, ransomware becomes fatal. Without governance, every other control is inconsistent. These are the threats that separate a surface-level assessment from a professional one.

  • Save threat-analysis.md.
  • Scroll through the file from top to bottom. You should see 10 threat entries (T-01 through T-10), each with a Threat, Vulnerability, and Potential Impact field.

Missing entries or formatting looks off?

Make sure each entry heading uses ### (three hashes) and each field line starts with - **. A missing hash or asterisk can break the Markdown formatting.

Check that there is a blank line between each threat entry. Without the blank line, Markdown will merge entries together.

Help me fix formatting issues in my threat-analysis.md file.

✔️ Awesome, I've got everything!

Great. Make sure you have saved threat-analysis.md with all 10 entries.

ⓧ I'd like to double check the full code

Your file is longer than a quick glance can cover. Scroll through threat-analysis.md and confirm each of these sections is present, in order:

  • File header: # CloudMedix Threat Analysis and ## Threat-Vulnerability Pairs.
  • Chunk 1 (T-01 to T-03): SQL Injection, Credential Stuffing, and Phishing entries.
  • Chunk 2 (T-04 to T-07): Unencrypted PHI, Misconfigured Cloud Storage, Insider Threat, and Undetected Breach entries.
  • Chunk 3 (T-08 to T-10): No Incident Response, Missing Backups, and No Formal Security Governance entries.
  • Each entry should have exactly three fields: Threat, Vulnerability, and Potential Impact.
Categorize threats by NIST CSF 2.0 Function

You have 10 threats documented, but right now they are just a flat list. Tagging each threat with its NIST CSF 2.0 Function turns that flat list into a structured map of where CloudMedix's security program has gaps.

The NIST Cybersecurity Framework 2.0 organizes cybersecurity activities into six Functions. Each Function covers a different aspect of a security program.

  • Govern (GV): Governance and policy failures, such as having no security policy at all.
  • Identify (ID): Asset and risk management gaps, such as unknown assets on the network or missing configuration reviews.
  • Protect (PR): Missing safeguards, such as no encryption, no MFA, or no access controls.
  • Detect (DE): Inability to notice attacks, such as no logging or monitoring.
  • Respond (RS): No plan for handling incidents when they occur.
  • Recover (RC): No backup or recovery capability to restore operations after an incident.

What is the Govern Function?

Govern is new in CSF 2.0. It was not present in the original framework (CSF 1.1). NIST added it to recognize that governance is a peer concern to the five operational functions, not something separate from them.

For CloudMedix, Govern covers the fact that no security policies exist and no one has defined security roles. Without governance, every other control is ad hoc.

Now add a fourth field to each threat entry. The field is called NIST CSF 2.0 Function and names which of the six Functions the threat primarily relates to.

  • In threat-analysis.md, find the T-01 entry. It currently ends with the Potential Impact line.
  • Find this line:
- **Potential Impact:** Unauthorized access to PHI, HIPAA breach notification required, regulatory fines
  • Add the following line directly below it:
- **NIST CSF 2.0 Function:** Protect (PR)

Why Protect for SQL injection?

SQL injection exploits a missing safeguard: input sanitization. The Protect Function covers the controls that should prevent this kind of attack from succeeding. Ask yourself: "Is this threat about a missing safeguard, a detection gap, a response gap, or a governance gap?" That question points you to the right Function.

Now add the Function tag to the remaining nine entries. Use the reference table below to determine which Function each threat maps to.

✔️ I'll give it a go!

For each threat (T-02 through T-10), add a line below the Potential Impact field:

- **NIST CSF 2.0 Function:** [Function Name] ([Abbreviation])

Think about each threat and decide: is the core problem a missing safeguard (Protect), an inability to detect (Detect), a response gap (Respond), a recovery gap (Recover), a governance failure (Govern), or an identification/asset management gap (Identify)?

ⓧ Maybe a little help...

Here is the Function mapping for each threat. Add the corresponding - **NIST CSF 2.0 Function:** line below the Potential Impact line of each entry.

  • T-02 (Credential Stuffing): Protect (PR). Missing MFA is a safeguard gap.
  • T-03 (Phishing): Protect (PR). Missing training and email filtering are safeguard gaps.
  • T-04 (Unencrypted PHI in Transit): Protect (PR). Missing TLS enforcement is a safeguard gap.
  • T-05 (Misconfigured Cloud Storage): Identify (ID). No configuration review is an asset/risk management gap.
  • T-06 (Insider Threat): Protect (PR). Missing RBAC and access reviews are safeguard gaps.
  • T-07 (Undetected Breach): Detect (DE). No monitoring or alerting is a detection gap.
  • T-08 (No Incident Response): Respond (RS). No incident response plan is a response gap.
  • T-09 (Missing Backups): Recover (RC). No backup process is a recovery gap.
  • T-10 (No Formal Security Governance): Govern (GV). No policies or defined roles is a governance failure.
  • Save threat-analysis.md.
  • Scroll through the file. Each of the 10 entries should now have four fields: Threat, Vulnerability, Potential Impact, and NIST CSF 2.0 Function.

What pattern do you see?

Notice how most threats map to Protect (PR). That makes sense for an early-stage startup with no formal security program. The safeguards are where the biggest gaps are. But you also have threats in Identify, Detect, Respond, Recover, and Govern. That spread across all six Functions is exactly what a thorough assessment looks like.

Not sure if your Function tags are right?

The key question for each threat is: "What is the core failure?" If the problem is that a safeguard is missing (no encryption, no MFA, no training), it maps to Protect. If the problem is that the organization cannot see an attack happening, it maps to Detect. If the problem is that there is no plan for when something goes wrong, it maps to Respond.

Help me verify my NIST CSF 2.0 Function mappings for my threat analysis.

Review and validate your threat list

Before you commit, review each entry against a simple test: "Is this realistic for a 50-person healthcare SaaS startup with no formal security program?"

  • Read through each of the 10 entries. Confirm that every entry has all four fields filled in: Threat, Vulnerability, Potential Impact, and NIST CSF 2.0 Function.
  • Check that your threats cover multiple CSF Functions, not just Protect. You should see at least one threat in Govern, Identify, Detect, Respond, and Recover.
  • Commit and push your changes by running these commands in your terminal:
git add .
git commit -m "Add threat analysis with 10 threat-vulnerability pairs and CSF Function tags"
git push

Seeing a push error?

Make sure you are in the cloudmedix-risk-assessment folder in your terminal. Run pwd to check your current location.

Help me troubleshoot a git push error in my risk assessment project.

Before you check GitHub, what do you expect to see on the repository page? Think about which file should have changed and what it should contain.

  • Open your cloudmedix-risk-assessment repository on GitHub in your browser.
  • Click into the risk-assessment folder, then click threat-analysis.md.

You should see all 10 threat entries (T-01 through T-10) rendered with their four fields. Each entry has a heading, and the Threat, Vulnerability, Potential Impact, and NIST CSF 2.0 Function fields are displayed as bold-labeled bullet points.

You now have a structured threat analysis that connects directly to your asset inventory and maps to the NIST CSF 2.0 framework. In the next step, you will turn these threats into a scored risk register so you can compare them side by side and decide which ones to worry about first.

Build and Score Your Risk Register

Your threat analysis gives you a clear picture of what could go wrong at CloudMedix. But with 10 threat-vulnerability pairs on the table, a natural question emerges: which ones should CloudMedix worry about first?

A risk register answers that question by scoring each risk with numbers you can compare side by side. In this step, you will build a register in Google Sheets, score every risk using a 5x5 Likelihood x Impact matrix, and plot the results on a color-coded heat map.

In this step, get ready to:
  • Create a risk register spreadsheet in Google Sheets with defined scoring criteria.
  • Score each threat-vulnerability pair using a 5x5 Likelihood x Impact matrix.
  • Build a color-coded heat map and review what the scores reveal about prioritization.
Create the risk register spreadsheet

The 5x5 Likelihood x Impact matrix is the standard semi-quantitative scoring approach referenced in NIST SP 800-30 Rev. 1. It is also aligned with NIST CSF 2.0's guidance on risk assessment. Before you start scoring, you need to define exactly what each number on the scale means.

  • Open Google Sheets in your browser by going to sheets.google.com.
  • Sign in with your Google account if prompted.
  • Click the + button (or Blank spreadsheet) to create a new spreadsheet.
  • Click the title at the top left (it says Untitled spreadsheet) and rename it to CloudMedix Risk Register.

The default sheet tab at the bottom is your Risk Register. You need to set up columns that capture everything about each risk.

  • Double-click the sheet tab at the bottom (it says Sheet1) and rename it to Risk Register.
  • In row 1, type the following column headers across cells A1 through M1:
  • A1: Risk ID.
  • B1: Risk Title.
  • C1: Threat.
  • D1: Vulnerability.
  • E1: Asset Affected.
  • F1: Likelihood (1-5).
  • G1: Impact (1-5).
  • H1: Inherent Risk Score.
  • I1: Risk Level.
  • J1: Risk Owner.
  • K1: Existing Controls.
  • L1: Control Gaps.
  • M1: Risk Response.
  • Select row 1, then click Format in the top menu and choose Bold to make the headers stand out.

You should now see 13 bold column headers spanning from A1 to M1. This is the structure where every risk will live.

Now create the Scoring Criteria tab to define what each number on the Likelihood and Impact scales actually means.

  • Click the + icon next to the Risk Register tab at the bottom to add a new sheet.
  • Double-click the new tab and rename it to Scoring Criteria.

In this tab, create three sections that define your entire scoring system. Start with the Likelihood scale.

  • In cell A1, type Likelihood Scale and bold it.
  • Starting in row 2, enter the five Likelihood levels with their definitions:
  • 1 - Rare: Highly unlikely to occur.
  • 2 - Unlikely: Could occur but not expected.
  • 3 - Possible: May occur at some point.
  • 4 - Likely: Expected to occur.
  • 5 - Almost Certain: Expected to occur frequently.
  • Below the Likelihood scale, add the Impact Scale heading and enter these five levels:
  • 1 - Negligible: Minimal effect on operations.
  • 2 - Minor: Small disruption, easily recoverable.
  • 3 - Moderate: Noticeable business impact.
  • 4 - Significant: Major operational or financial impact.
  • 5 - Critical: Severe impact, potential business failure or major regulatory action.
  • Below the Impact scale, add a Risk Levels heading and define the four threshold ranges:
  • Low: Score 1-4.
  • Medium: Score 5-9.
  • High: Score 10-14.
  • Critical: Score 15-25.
  • At the bottom of the Scoring Criteria tab, add a Formula note: Inherent Risk Score = Likelihood x Impact.

Switch back to the Scoring Criteria tab and review it. You should see three clearly defined sections: a 5-level Likelihood scale, a 5-level Impact scale, and four Risk Level thresholds.

Why define scoring criteria first?

Without shared definitions, "Likely" could mean "once a year" to one person and "once a week" to another. Writing the criteria down before scoring ensures consistency. This is the same principle behind NIST CSF 2.0 subcategory ID.RA-04, which calls for business leaders and risk practitioners to estimate likelihood and impact together using agreed-upon definitions.

Tabs not showing at the bottom?

If you do not see sheet tabs along the bottom of your spreadsheet, look for a small arrow icon in the bottom-left corner and click it to expand the tab bar.

Help me set up my Google Sheets tabs for the risk register.

Populate and score each risk

Now for the core exercise. You will transfer each threat-vulnerability pair from your threat-analysis.md into the risk register and assign scores based on CloudMedix's specific context.

  • Switch to the Risk Register tab in your spreadsheet.
  • Return to VS Code and open risk-assessment/threat-analysis.md so you can reference it side by side with Google Sheets.
  • Start with T-01. In row 2, enter the Risk ID, Risk Title, Threat, and Vulnerability from your threat analysis document.
  • In the Asset Affected column, identify which asset from your inventory this risk targets (for example, T-01 SQL Injection affects the Patient Portal Web Application).

Before you score T-01, think about what "Likelihood" and "Impact" mean in CloudMedix's context. This is a 50-person startup with no formal security program, handling PHI under HIPAA requirements.

  • Assign a Likelihood score (1-5) based on how probable this threat is given CloudMedix's current security posture. Refer to the definitions in your Scoring Criteria tab.
  • Assign an Impact score (1-5) based on the business consequence if this threat materializes. Remember that PHI exposure triggers HIPAA breach notification.
  • In the Inherent Risk Score column, multiply Likelihood by Impact. You can type a formula like =F2*G2 to calculate it automatically.
  • In the Risk Level column, enter the level that matches the score: Low (1-4), Medium (5-9), High (10-14), or Critical (15-25).

Check your first row. You should see T-01 with a complete set of values from Risk ID through Risk Level. The Inherent Risk Score cell should show a calculated number.

How do I decide scores for an early-stage startup?

Think about what CloudMedix is missing. There is no MFA, no security awareness training, no encryption policy, no monitoring, and no incident response plan. For threats that exploit these gaps, Likelihood skews higher (3-5) because the controls that would prevent them do not exist.

For Impact, any risk that leads to PHI exposure triggers HIPAA breach notification and potential fines, so Impact for those risks also skews higher (4-5). A risk with high Likelihood and high Impact is exactly the kind of situation a risk register is built to surface.

  • Repeat the scoring process for T-02 through T-10. For each row, fill in Risk ID, Risk Title, Threat, Vulnerability, Asset Affected, Likelihood, Impact, Inherent Risk Score, and Risk Level.

Now fill in the ownership and controls columns for all 10 risks.

  • In the Risk Owner column, assign the person at CloudMedix responsible for managing each risk. Refer to the Owner column in your asset inventory for guidance (CTO, Engineering Lead, HR Lead, etc.).
  • In the Existing Controls column, note whatever basic controls CloudMedix already has. For most risks, the only existing control is "basic application authentication." Many rows will say "None."
  • In the Control Gaps column, describe what is missing. For example, T-01 (SQL Injection) has a Control Gap of "No input validation or parameterized queries."
  • Leave the Risk Response column blank for all 10 risks. You will fill it in after the control mapping in the next step.

Scroll across your Risk Register tab. You should now see 10 fully populated rows (T-01 through T-10) with every column filled in except Risk Response.

Scores not calculating?

If your Inherent Risk Score column shows an error or zero, check that your Likelihood and Impact cells contain plain numbers (not text). Click a Likelihood cell and confirm the value is a number like 4, not text like 4 - Likely. The formula =F2*G2 multiplies the raw numbers.

Help me fix my risk score formula in Google Sheets.

Create a risk heat map and review scoring

A heat map is a visual snapshot that lets you see at a glance where your risks cluster. It plots every risk on a 5x5 grid based on its Likelihood and Impact scores, with colors showing severity.

  • Click the + icon at the bottom of your spreadsheet to create a third tab.
  • Double-click the new tab and rename it to Heat Map.

Build the 5x5 grid. Impact runs across the top (columns) and Likelihood runs down the side (rows).

  • In cell A1, type Likelihood / Impact.
  • In cells B1 through F1, type the Impact values: 1, 2, 3, 4, 5.
  • In cells A2 through A6, type the Likelihood values top to bottom: 5, 4, 3, 2, 1 (highest Likelihood at the top).
  • In each cell of the 5x5 grid (B2 through F6), type the product of that row's Likelihood and that column's Impact. For example, cell B2 (Likelihood 5, Impact 1) is 5. Cell F2 (Likelihood 5, Impact 5) is 25.

You should see a 5x5 grid filled with numbers from 1 to 25. Now add the color coding.

  • Select all cells that show a score of 1-4 (the Low range). Click the fill color button in the toolbar and choose green.
  • Select all cells that show a score of 5-9 (Medium). Fill them with yellow.
  • Select all cells that show a score of 10-14 (High). Fill them with orange.
  • Select all cells that show a score of 15-25 (Critical). Fill them with red.

Your grid should now show a gradient from green in the bottom-left corner to red in the top-right corner.

  • Plot your risks on the heat map. For each risk in your Risk Register tab, find the cell that matches its Likelihood row and Impact column, then type the Risk ID (e.g. T-01) into that cell. If multiple risks land in the same cell, list them together (e.g. T-01, T-06).

What does the heat map show?

The heat map gives you a single picture of your entire risk landscape. Risks in the red and orange zones need immediate attention. Risks in the green zone can be monitored with less urgency.

Professional GRC analysts present heat maps to leadership because they communicate risk posture faster than a spreadsheet of numbers. One glance at a mostly-orange map tells a CISO more than a table of scores.

Before you review the full picture, take a moment to predict. Do you think the raw scores alone give you a clear priority order for which risks to fix first?

Now look at your completed heat map and Risk Register side by side. Count how many risks fall in the High range (scores of 10-14).

You should see several risks clustered together in the orange zone. Multiple risks share scores of 10, 12, or similar values. With just these numbers, it is hard to tell which of those similarly-scored risks deserves attention first. Should CloudMedix fix the SQL injection vulnerability before the missing incident response plan? Both score in the same range, but raw scores alone do not answer that question.

Why can't I just sort by score?

Sorting by Inherent Risk Score is a reasonable starting point. The problem is that it treats all equally-scored risks as equally urgent. In practice, a risk that maps to a security area where CloudMedix has zero controls is far more urgent than a risk in an area where partial controls already exist.

The next step solves this by mapping each risk to specific NIST CSF 2.0 Functions and assessing control maturity. That mapping reveals which areas of the security program are completely empty, giving you a framework-backed way to differentiate priority among risks that score the same.

Heat map colors look wrong?

Double-check that the score in each cell matches the product of its row's Likelihood and its column's Impact. A misplaced number throws off the color assignment for that cell.

If all your risks cluster in one zone (all orange, all red), revisit your Likelihood and Impact scores. For a startup with no security program, some threats are more probable than others. A phishing attack (common, exploits human error) is more likely than a targeted nation-state attack.

Help me review my risk scoring and heat map placement.

Your risk register captures the full picture of what threatens CloudMedix, and the heat map makes it visual. But you have also spotted a real limitation: scores alone are not enough to prioritize. Next up, you will map these risks to NIST CSF 2.0 and reveal exactly where CloudMedix's security program has the deepest gaps.

Map Controls to NIST CSF 2.0 and Analyze Gaps

Your risk register is scored and plotted, but you noticed a problem at the end of the last step. Several risks cluster in the High range (10-14), making it hard to tell which ones deserve attention first.

Raw scores alone cannot answer that question. Two risks can both score 12, but one might sit in a NIST CSF 2.0 Function where you have zero controls, while the other maps to a Function where partial controls already exist. In this step, you will map every risk to the CSF framework and write a gap analysis that reveals the structural weaknesses in CloudMedix's security program.

In this step, get ready to:
  • Build a CSF Control Mapping tab in Google Sheets that ties each risk to a specific NIST CSF 2.0 Function and Category.
  • Write a gap analysis document in Markdown organized by CSF Function, explaining each gap in plain language.
  • Fill in risk response strategies for all 10 risks in the register.
Build the NIST CSF 2.0 control mapping matrix

The preliminary Function tags you added in Step 3 were a starting point. Now you will map each risk to a specific CSF Category, which gives you the precision to see exactly where controls are missing.

  • Switch back to your CloudMedix Risk Register spreadsheet in Google Sheets.
  • Click the + button at the bottom of the spreadsheet to create a new tab.
  • Rename the new tab to CSF Control Mapping.
  • In row 1, add these column headers: Risk ID, Risk Title, CSF Function, CSF Category, CSF Category ID, Current State, Evidence / Notes.

What is the Current State column?

For each mapping, you will assess whether CloudMedix currently has a control in place. Use one of three values:

  • None means the company has no control addressing this Category at all.
  • Partial means some basic control exists but it is incomplete or informal.
  • Implemented means a documented, effective control is in place.

CloudMedix is an early-stage startup with no formal security program. Most categories will be None or Partial.

Now map each of your 10 risks to the specific CSF Category it falls under. Use the preliminary Function tags from your threat analysis as a starting point, then get more specific with the Category.

NIST CSF 2.0 Functions and Categories reference

  • Govern (GV): GV.OC (Organizational Context), GV.RM (Risk Management Strategy), GV.RR (Roles and Responsibilities), GV.PO (Policy), GV.OV (Oversight), GV.SC (Supply Chain Risk Management).
  • Identify (ID): ID.AM (Asset Management), ID.RA (Risk Assessment), ID.IM (Improvement).
  • Protect (PR): PR.AA (Identity Management, Authentication, and Access Control), PR.AT (Awareness and Training), PR.DS (Data Security), PR.PS (Platform Security), PR.IR (Technology Infrastructure Resilience).
  • Detect (DE): DE.CM (Continuous Monitoring), DE.AE (Adverse Event Analysis).
  • Respond (RS): RS.MA (Incident Management), RS.AN (Incident Analysis), RS.CO (Incident Response Reporting and Communication), RS.MI (Incident Mitigation).
  • Recover (RC): RC.RP (Incident Recovery Plan Execution), RC.CO (Incident Recovery Communication).
  • Start with risk T-01 (SQL Injection on Patient Portal). Its preliminary tag was Protect (PR). The specific Category is PR.PS (Platform Security), because the vulnerability is an unpatched application input handling issue. Set the Current State to None and add a note explaining why.
  • Continue mapping each risk from T-02 through T-10. For each row, pull the Risk ID and Risk Title from your Risk Register tab, select the CSF Function and Category from the reference above, and assess the Current State based on CloudMedix's company overview.

After filling in all 10 rows, your CSF Control Mapping tab should have 10 rows of data (plus the header row). Most Current State values should be None or Partial.

Not sure which Category to pick?

Focus on the vulnerability, not the threat. Ask yourself: "What kind of safeguard is missing?" If the gap is about access controls, it maps to PR.AA. If it is about the inability to detect an attack, it maps to DE.CM. The vulnerability description in your threat analysis tells you exactly what is missing.

Help me map my risks to NIST CSF 2.0 Categories

Write the gap analysis document

The control mapping tab shows you the raw data. The gap analysis document translates that data into a narrative a CISO can read and act on. You will organize it by CSF Function, documenting which Categories have gaps and what each gap means in plain language.

  • Switch back to VS Code and open gap-analysis/gap-analysis.md.
  • Add the file header and the Govern section by pasting the following content:
# CloudMedix Gap Analysis

Framework: NIST Cybersecurity Framework 2.0

## Govern (GV)

### Gaps
- **GV.RM (Risk Management Strategy):** No risk management program exists. Current State: None.
- **GV.PO (Policy):** No security policies are documented. Current State: None.
- **GV.RR (Roles and Responsibilities):** Security responsibilities are informally assigned to the CTO with no formal role definition. Current State: None.

### Plain Language
CloudMedix has no formal security governance. There are no written policies, no defined security roles, and no risk management process. This means every other control gap is compounded — without governance, there is no mechanism to detect or fix problems systematically.

### Affected Risks: T-10
### Severity: Critical

---

What does this structure do?

Each CSF Function section follows the same four-part pattern. Gaps lists the specific Categories with missing or partial controls. Plain Language translates the gap into business impact a non-technical reader can understand.

Affected Risks ties back to your risk register by Risk ID. Severity (Critical, High, or Medium) is based on how many high-scoring risks touch this Function.

  • Save gap-analysis.md.
  • You should see the Govern section with three Category gaps listed, all with a Current State of None. The Severity is Critical because T-10 (No Formal Security Governance) underpins every other control gap.
  • Add the Identify and Protect sections below the --- divider by pasting this content:

## Identify (ID)

### Gaps
- **ID.AM (Asset Management):** No formal asset inventory process exists beyond this assessment. Current State: None.
- **ID.RA (Risk Assessment):** No ongoing risk assessment process. Current State: None.

### Plain Language
CloudMedix does not have a repeatable process for tracking its assets or assessing risk. Without this, new assets or threats can appear without anyone noticing.

### Affected Risks: T-05
### Severity: High

---

## Protect (PR)

### Gaps
- **PR.AA (Identity Management and Access Control):** No MFA, no RBAC, no access review process. Current State: Partial (basic authentication only).
- **PR.AT (Awareness and Training):** No security awareness training program. Current State: None.
- **PR.DS (Data Security):** TLS enforcement is inconsistent; no encryption at rest policy. Current State: Partial.
- **PR.PS (Platform Security):** No patch management or configuration hardening process. Current State: None.

### Plain Language
CloudMedix's protective controls are the weakest area. Employees have no security training, access controls are minimal, and data protection is inconsistent. This is where most of the highest-scoring risks originate.

### Affected Risks: T-01, T-02, T-03, T-04, T-06
### Severity: Critical

---

Why is Protect the weakest area?

Five of CloudMedix's ten risks map to the Protect Function. PR.AA (access control) and PR.DS (data security) both show a Current State of Partial rather than None, because the company does have basic authentication and some TLS. But partial controls with four Category gaps still make this the most exposed Function overall.

  • Save gap-analysis.md.
  • You should now see three CSF Function sections: Govern, Identify, and Protect. Notice how Protect has the most gaps and the most affected risks.
  • Add the Detect and Respond sections below the last --- divider:

## Detect (DE)

### Gaps
- **DE.CM (Continuous Monitoring):** No logging, monitoring, or alerting infrastructure. Current State: None.
- **DE.AE (Adverse Event Analysis):** No capability to analyze security events. Current State: None.

### Plain Language
CloudMedix has no ability to detect an attack in progress. If a breach occurs, the company would likely discover it through external notification rather than internal detection.

### Affected Risks: T-07
### Severity: Critical

---

## Respond (RS)

### Gaps
- **RS.MA (Incident Management):** No incident response plan exists. Current State: None.
- **RS.CO (Incident Response Reporting and Communication):** No breach notification process. Current State: None.

### Plain Language
CloudMedix has no incident response plan. If a data breach occurs, there is no documented process for containment, notification, or recovery. This directly violates HIPAA breach notification requirements.

### Affected Risks: T-08
### Severity: Critical

---

Why are Detect and Respond both Critical?

Even though each Function only has one affected risk, those risks (T-07 and T-08) both have zero controls. A company that cannot detect attacks and has no incident response plan faces compounding damage. Under HIPAA, the inability to detect and respond to a breach can trigger additional regulatory penalties.

  • Add the final Recover section below the last --- divider:

## Recover (RC)

### Gaps
- **RC.RP (Incident Recovery Plan Execution):** No backup or disaster recovery process. Current State: None.

### Plain Language
CloudMedix has no backup or recovery capability. A ransomware attack or accidental deletion could result in permanent loss of patient data with no path to restoration.

### Affected Risks: T-09
### Severity: High

Why is Recover rated High instead of Critical?

Recover has only one Category gap (RC.RP) affecting one risk (T-09). While data loss is severe, the Govern, Protect, and Detect Functions have more gaps touching more risks, which makes those structural weaknesses more urgent to address first.

  • Save gap-analysis.md.
  • Scroll through the full file. You should see six sections (Govern, Identify, Protect, Detect, Respond, Recover), each with Gaps, Plain Language, Affected Risks, and Severity filled in.

Seeing formatting issues in the Markdown?

Make sure each section has a blank line before and after the heading lines (lines starting with ##). Markdown requires blank lines around headings to render correctly. Also confirm the --- dividers have a blank line above and below them.

Help me fix Markdown formatting in my gap analysis

✔️ Awesome, I've got everything!

Great. Double check you have saved gap-analysis.md before moving on.

ⓧ I'd like to double check the full code

Scroll through your gap-analysis/gap-analysis.md and confirm these sections are present, in order:

  • File header with the title and framework name.
  • Govern (GV) section with three gaps (GV.RM, GV.PO, GV.RR), Affected Risks: T-10, Severity: Critical.
  • Identify (ID) section with two gaps (ID.AM, ID.RA), Affected Risks: T-05, Severity: High.
  • Protect (PR) section with four gaps (PR.AA, PR.AT, PR.DS, PR.PS), Affected Risks: T-01, T-02, T-03, T-04, T-06, Severity: Critical.
  • Detect (DE) section with two gaps (DE.CM, DE.AE), Affected Risks: T-07, Severity: Critical.
  • Respond (RS) section with two gaps (RS.MA, RS.CO), Affected Risks: T-08, Severity: Critical.
  • Recover (RC) section with one gap (RC.RP), Affected Risks: T-09, Severity: High.
  • Commit and push the gap analysis to GitHub by running these commands in your terminal:
git add gap-analysis/gap-analysis.md
git commit -m "Add gap analysis organized by CSF Function"
git push
Update risk responses in the register

With your control mapping and gap analysis complete, you can now make an informed decision about how to respond to each risk. The CSF mapping reveals which risks sit in Functions with zero controls, making the response choice clear.

What are the four risk response strategies?

  • Mitigate: Implement controls to reduce the likelihood or impact of the risk.
  • Accept: Acknowledge the risk and choose not to act, typically because the cost of mitigation exceeds the potential impact.
  • Avoid: Eliminate the risk entirely by removing the activity or asset that creates it.
  • Transfer: Shift the risk to a third party, such as through insurance or outsourcing.

For risks that map to Categories with a Current State of None, the response should almost always be Mitigate. You cannot accept a gap when there are zero controls in place, especially for a healthcare company handling PHI.

  • Switch back to your CloudMedix Risk Register spreadsheet and click the Risk Register tab.
  • Find the Risk Response column (currently blank for all 10 risks).
  • For each risk from T-01 through T-10, enter Mitigate as the Risk Response. Every risk maps to a CSF Category where CloudMedix has None or Partial controls, so mitigation is the appropriate response for all of them.

Why Mitigate for every risk?

In a mature organization, you might Accept a low-scoring risk or Transfer it through cyber insurance. CloudMedix has no controls in most CSF Categories. Accepting gaps with zero controls while handling PHI would be a compliance failure. Mitigation is the only responsible choice at this stage.

Before you review the results, think about this: which NIST CSF 2.0 Functions do you expect to have the biggest gaps, and why?

Open your gap-analysis.md in VS Code and your Risk Register tab in Google Sheets side by side. You should now be able to answer: "Which NIST CSF 2.0 Functions have the biggest gaps, and which specific risks drive those gaps?"

The prioritization that was unclear after Step 4 should now be obvious. Govern, Protect, Detect, and Respond all have Critical severity gaps with zero controls. Risks mapping to those Functions are your highest priority, regardless of whether their raw scores are identical to risks in partially-controlled areas.

Still not seeing a clear priority difference?

Compare two risks that scored the same in your heat map. Check their CSF Control Mapping rows. If one maps to a Category with Current State "None" and the other maps to "Partial," the one with zero controls is the higher priority. The gap analysis severity (Critical vs. High) should reflect this difference.

Help me understand how CSF mapping changes risk prioritization

You have mapped every risk to the NIST CSF 2.0 framework and uncovered where CloudMedix's security program is structurally weakest. Next up, you will take on a Secret Mission to turn those gaps into a concrete remediation roadmap with time horizons and action owners.

Secret mission

Create a Prioritized Remediation Roadmap

Your risk assessment identified the gaps. Now build a remediation roadmap that tells a CISO exactly what to fix, in what order, and who owns each action. This is the deliverable that separates analysis from action.

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project uses free tools and static files, so there are no ongoing costs.

Resources you used:

  • GitHub repository cloudmedix-risk-assessment.
  • Google Sheets spreadsheet "CloudMedix Risk Register" with four tabs (Risk Register, Scoring Criteria, Heat Map, CSF Control Mapping).
  • Local project folder cloudmedix-risk-assessment on your Desktop.

Keep everything running

No action needed. Choose this if you want to keep your portfolio-ready risk assessment available for future reference or to share with employers.

  • Your GitHub repository stays public and accessible as a portfolio piece.
  • Your Google Sheets spreadsheet remains in your Google Drive.
  • Your local folder stays on your Desktop for easy editing.
  • Git remains installed on your machine for future projects.

Pause - I'll come back to this later

This project has no running processes or active services, so there is nothing to shut down. Your files and repository will stay exactly as you left them.

  • Close any open VS Code windows and browser tabs to free up memory.
  • Your GitHub repository and Google Sheets spreadsheet will be waiting when you come back.

Delete - I don't want to use this again

Remove all project resources and start fresh. Follow each group of steps below to clean up completely.

Delete the GitHub repository:

  • Open your cloudmedix-risk-assessment repository page on GitHub.
  • Click Settings in the top navigation bar of the repository.
  • Scroll to the bottom of the page to the Danger Zone section.
  • Click Delete this repository and follow the confirmation prompts.

Delete the Google Sheets spreadsheet:

  • Open Google Drive at drive.google.com.
  • Find the "CloudMedix Risk Register" spreadsheet.
  • Right-click the file and select Move to trash.

Delete the local project folder:

macOS

  • Delete the local folder by running this command in your terminal:
rm -rf ~/Desktop/cloudmedix-risk-assessment

Windows

  • Delete the local folder by running this command in your terminal:
rmdir /s /q %USERPROFILE%\Desktop\cloudmedix-risk-assessment

Nice Work!

Nice Work!

You just built a complete cybersecurity risk assessment for a fictional healthcare SaaS startup. From company scoping to gap analysis, you followed the same methodology a professional GRC analyst uses on real engagements.

You've learned how to:

  • Scope a risk assessment by building a company profile and asset inventory for a healthcare SaaS company, then identify realistic threats and vulnerabilities tied to each asset using your knowledge of networking and web security.
  • Score risks using a 5x5 Likelihood x Impact matrix in a risk register, producing a color-coded heat map that visualizes where the highest risks cluster.
  • Map risks to the six NIST CSF 2.0 Functions and 22 Categories, then perform a gap analysis that transforms raw scores into actionable prioritization based on control maturity.
  • Secret Mission: Build a prioritized remediation roadmap with 0-30, 30-90, and 90+ day time horizons that a CISO could use to allocate budget and assign work.

Ready to quiz yourself?