Story Time:
You're deep in the trenches, hunting down the source of a critical vulnerability. After hours of investigation, you finally pinpoint the source. The culprit is a snippet of code so poorly written it makes you shudder. Now comes the fun part: finding out who is responsible for this time bomb.
You run git blame, expecting a quick resolution. Instead, you're greeted with a name that makes your heart sink. Jeff "the jerk" - the brilliant but eccentric engineer who jumped ship last year to chase his GenAI gold rush dreams at some startup.
This code has been abandoned ever since. No owner, no oversight, just a ticking time bomb in your otherwise perfect codebase.
You rub your bloodshot eyes and wonder: how many more time bombs did Jeff leave behind? And more importantly, how can you prevent this from happening again?
In security, tracking down ownership can often be one of the most time-consuming tasks. But there's a good reason to invest in defining it early: you can’t protect what you don’t know, and the most crucial element of asset inventory is identifying ownership.
One of the primary reasons to implement CODEOWNERS is to ensure the right people review critical code changes. It supports code review processes and provides additional benefits:
Moving from unclear ownership to well-defined roles may seem daunting, but here’s a simple, three-step process to get there.
Let's dive in.
Start by identifying repositories without a CODEOWNERS file and encourage the teams responsible to create one. On GitHub, the CODEOWNERS
file can be located in any of these spots:
While GitHub doesn’t allow you to search for repositories that don't have this file, you can use a simple Python script to list repositories and check for the presence of CODEOWNERS. Here's a script you are free to use: check_codeowners.py
Below is a basic CODEOWNERS file template. The syntax is straightforward: list a wildcard, directory, or filetype, followed by the user or group responsible for that code. Note that order matters: later matches take precedence over earlier ones.
# These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence,
# @global-owner1 and @global-owner2 will be requested for
# review when someone opens a pull request.
* @global-owner1 @global-owner2
# Order is important; the last matching pattern takes the most
# precedence. When someone opens a pull request that only
# modifies JS files, only @js-owner and not the global
# owner(s) will be requested for a review.
*.js @your-org/frontend
# Assign a specific team to a directory
/login @your-org/iam @your-org/security
Pro Tip: It’s a good practice to set a global owner for each repository. Even if they aren’t the "best" fit, this encourages them to identify and document the right owner. They are the owner until they find a better owner.
Changing security-sensitive code without proper review can have serious repercussions. It’s essential to identify these sections and require approvals
from specific code owners.
What qualifies as security-sensitive code? Start with anything that requires deep cross-functional knowledge or subject-matter expertise to implement securely. This typically includes:
Once you've secured these areas, expand to cover additional sensitive sections of your codebase.
Studies, like the one by Steve McConnell, reveal that code reviews catch 80% of defects—far more than unit, functional, or integration testing alone.
That study identified the following average defect detection rates:
If your organization isn’t already enforcing code reviews, now’s the time to start.
Here's how to enable CODEOWNER approval enforcement in GitHub:
Defining ownership for your codebases isn’t just about enabling code reviews—it’s a critical security practice that provides clarity and accountability. By making the effort to define CODEOWNERS for all critical code sections, especially the security-sensitive ones, you empower your teams to work more efficiently and securely.
Here are some resources to help you dive deeper: