CODEOWNERS Is Not Access Control (What It Actually Does)
GitHub CODEOWNERS requests reviews and can require approvals, but it doesn't stop anyone reading or cloning code. What it does, what it doesn't, and fixes.
Short answer: CODEOWNERS controls who is asked to review changes to a path, and with branch protection, whose approval is required to merge them. It doesn't restrict who can read, clone or even push to that path on other branches. If someone can read the repository, they can read every file listed in CODEOWNERS. To hide code you need a separate repository or a filtered view.
What CODEOWNERS does
A CODEOWNERS file maps path patterns to people or teams. GitHub's documentation describes the core behavior in one sentence: "Code owners are automatically requested for review when someone opens a pull request that modifies code that they own."
# .github/CODEOWNERS
* @acme/eng-leads
/core/ @acme/core
/core/pricing/ @alice @acme/pricing
/infra/ @acme/platform
*.sql @acme/data
/.github/ @acme/platform
Facts from the docs worth knowing:
- Location. GitHub looks in
.github/, the repository root, thendocs/, and uses the firstCODEOWNERSit finds. - Base branch. "For code owners to receive review requests, the CODEOWNERS file must be on the base branch of the pull request," so different branches can have different owners.
- Last match wins. Later patterns override earlier ones, so put general rules first.
- Syntax. Mostly
gitignore-style patterns, with exceptions: "Using!to negate a pattern doesn't work." - Errors are visible. Open the CODEOWNERS file on GitHub to see errors highlighted; a user or team "that doesn't exist or has insufficient access" isn't assigned.
- Owners need write access. "The people you choose as code owners must have write permissions for the repository. When the code owner is a team, that team must be visible and it must have write permissions."
- Size limit. Files over 3 MB aren't loaded.
Making it mandatory
On its own, CODEOWNERS only requests reviews. To make owner approval a requirement, enable Require review from Code Owners in a branch protection rule or ruleset for the target branch. Then a pull request touching /core/pricing/ can't merge into main until an owner approves. Per GitHub, "an approval from any of the owners is sufficient."
What CODEOWNERS does not do
| Common assumption | Reality |
|---|---|
Non-owners can't see /core/ |
Anyone with Read access can clone the whole repository |
Non-owners can't change /core/ |
They can commit and push to their own branches; only merging into protected branches needs approval |
| Owners are the only people who can approve | Any reviewer can approve; the rule requires at least one owner approval |
| It applies everywhere | Only to branches with a rule requiring code owner review |
| It restricts AI agents | Agents with repository access read everything like anyone else |
| It protects secrets | A secret in /infra/ is readable by every collaborator |
It's a review routing and merge-approval tool. That's useful, but it's about integrity (what gets merged), not confidentiality (who can see).
Related GitHub controls, and what they cover
Branch protection and rulesets set merge requirements per branch: required reviews, status checks, signed commits, linear history, who can push.
Push rulesets add path rules. "Restrict file paths" will "prevent commits that include changes in specified file paths from being pushed to the repository", for private and internal repositories and their fork networks. That's closer to path-level write control than CODEOWNERS, but it's still write-only.
Repository roles (Read, Triage, Write, Maintain, Admin) control what someone can do with the entire repository. There's no path-level read role on any plan.
Putting it together:
| Goal | Tool |
|---|---|
| Route reviews to the right team | CODEOWNERS |
| Require an owner's approval to merge | CODEOWNERS + "Require review from Code Owners" |
| Block pushes touching a path | Push ruleset: restrict file paths |
| Stop someone from reading a path | Not available on GitHub; separate repo or filtered view |
Common CODEOWNERS mistakes
- Unprotected CODEOWNERS file. If anyone can change
CODEOWNERSin a PR, they can add themselves. Own/.github/(or wherever the file lives) with a trusted team, and require code owner review on the default branch. - Owners without write access. Individuals or teams lacking write permission are not requested for review. Check the CODEOWNERS errors shown on the file in GitHub.
- Order mistakes. A catch-all
*at the bottom overrides everything above it. - Assuming it hides code from contractors. This is the big one. If you added a contractor to the repository because "CODEOWNERS will protect
/core/", they can read/core/.
If you need to restrict reading
The options are covered in depth in can you restrict access to folders in a GitHub repository?. In brief:
- Split the code into its own repository, so GitHub's repository permissions apply.
- Submodule the sensitive part, so people without access get an empty folder.
- Publish a filtered mirror with Copybara or
git filter-repo. - Serve filtered views with a proxy.
Not options: sparse checkout (why), .gitignore, or editor ignore files.
How Gitfence complements CODEOWNERS
Gitfence handles the part CODEOWNERS can't: who can see what. It sits in front of GitHub and gives each restricted person or AI agent a clone that contains only what they're allowed to see, with per-folder or per-file levels: No access, Types only, Can read, Can edit.
Their pushes are checked path by path and arrive in GitHub as ordinary pull requests, so your CODEOWNERS file, branch protection and rulesets apply to them exactly as before. The two work together:
- CODEOWNERS and branch protection decide who approves what gets merged.
- Gitfence decides who can see and change which paths in the first place, before a PR exists.
Gitfence also adds a Gitfence check to each PR from a restricted person. It identifies the human and agent behind the change and scans added lines for fingerprints of hidden code, failing without quoting the hidden source. That helps catch hidden code copied into a visible file. It's a deterrent, not proof: transformed or encoded code can evade fingerprinting.
A practical way to start: the paths your CODEOWNERS file assigns to a core team are usually the same paths contractors and agents don't need to see.
For teams sharing a monorepo, the two combine as described in monorepo permissions for per-team access, and for AI agents in least-privilege repo access for Claude Code, Codex and Cursor.
Today Gitfence works with GitHub only. See how it works and Gitfence for contractors.
FAQ
Can CODEOWNERS prevent someone from viewing files?
No. It only affects review requests and, with branch protection, merge approvals. Anyone with read access to the repository can view every file.
Can someone push changes to code they don't own?
Yes, to branches without protection. CODEOWNERS approval is enforced when merging into branches with "Require review from Code Owners" enabled. Push rulesets can block pushes that touch specific paths.
Why is my code owner not being requested for review?
Most often the user or team lacks write permission, the team isn't visible, or a later pattern in the file overrides the one you expected. GitHub shows errors on the CODEOWNERS file when it can't resolve an owner.
Can a code owner have read-only access?
No. GitHub requires code owners to have write permission. This is a long-standing community request.
Does CODEOWNERS work on GitHub Free?
Code owners can be used on public repositories with GitHub Free, and on private repositories with paid plans. Requiring code owner review uses branch protection or rulesets, whose availability for private repositories also depends on your plan; check GitHub's current plan documentation.