Introduction
Over the last few years, GitHub repositories stopped being just source control.
A modern repository is simultaneously a CI system, a deployment pipeline, a software supply-chain entry point, an artifact builder, and increasingly an execution environment for AI-assisted tooling.
That changes the security model significantly.
Over the last two years, supply-chain attacks against npm ecosystems, GitHub Actions, and CI tooling have become increasingly operationalized. Instead of targeting production systems directly, attackers increasingly target developer tooling and build infrastructure because compromising a single package, GitHub Action, or CI workflow can cascade into thousands of downstream systems.
The recent tj-actions compromise was a good example of this shift. A single compromised GitHub Action exposed CI secrets from large numbers of repositories, despite many of those repositories having otherwise mature application security practices.
This is one of the reasons I started treating repository security less like dependency hygiene and more like infrastructure hardening. The controls described in this article form the foundation of the repository security model I currently use across personal and commercial projects.
Repositories as Supply-Chain Entry Points
Repositories are no longer passive storage for source code.
Modern repositories execute code, build artifacts, publish releases, manage credentials, and interact directly with production infrastructure. CI/CD systems have effectively become part of the software supply chain, introducing new trust boundaries that did not exist when Git was primarily used as a version-control system.
This shift has expanded the attack surface significantly. A repository now depends not only on its own codebase, but also on external packages, CI workflows, marketplace actions, and build infrastructure. Each dependency introduces a trust relationship that must be understood and managed.
Recent attacks increasingly reflect this reality. Rather than targeting production systems directly, attackers often focus on build systems, package ecosystems, and developer tooling. Compromising a package, workflow, or CI component can provide access to thousands of downstream systems simultaneously.
The implication is that repository security can no longer focus exclusively on application code. Security controls must also account for the systems that build, validate, package, and distribute that code.
SBOMs as Security Inventory
One lesson I learned from security engineering is that visibility often matters more than scanning.
When a new vulnerability is disclosed, the first question is usually not how to fix it. The first question is whether a project is actually affected.
That becomes increasingly difficult once applications accumulate hundreds of direct and transitive dependencies.
To address this, my pipelines generate a Software Bill of Materials (SBOM) using Syft and store it in CycloneDX format. The SBOM is then scanned with Grype to identify known vulnerabilities before code reaches the main branch.
While vulnerability detection is the immediate value, I have found the inventory itself to be equally important. The SBOM provides a structured record of what actually entered a build. It makes it easier to understand dependency exposure, investigate newly disclosed vulnerabilities, and track how dependency footprints evolve over time.
In practice, the SBOM becomes both a security control and a source of operational visibility.
Repository Controls Before Automation
Before adding more security automation, I believe the repository itself needs clear boundaries.
For me, this means treating the main branch as a protected surface rather than a shared write target. Code enters through pull requests, with required checks for the security layers that already exist, such as SBOM scanning and CodeQL analysis.
This is less about process for its own sake and more about reducing uncontrolled change. If security checks can be bypassed by pushing directly to the main branch, the pipeline becomes advisory rather than enforceable.
Repository controls are often overlooked because they are not particularly sophisticated. However, they establish the governance model that allows other security controls to be effective.
Security automation is valuable, but only when it becomes part of the repository's merge contract rather than an optional report that developers can ignore.
Static Analysis with CodeQL
While SBOMs and vulnerability scanners focus on third-party components, they do not say much about the security of the application itself.
This is where CodeQL fits into my workflow.
CodeQL performs semantic static analysis, examining how data flows through an application rather than simply looking for known patterns. This makes it useful for identifying issues such as injection paths, unsafe execution flows, path traversal vulnerabilities, and other problems that can emerge across multiple functions or files.
To make security checks part of the development process rather than an afterthought, CodeQL runs as part of the pull-request pipeline. Potential issues are identified before code reaches the main branch, allowing them to be reviewed alongside the code changes that introduced them.
What I find most valuable about CodeQL is that it complements dependency scanning rather than replacing it. SBOMs and vulnerability scanners help answer whether a project depends on vulnerable components. CodeQL focuses on vulnerabilities introduced by the application's own logic.
Both perspectives are important because not every security issue originates from a dependency.
AI-Assisted Development and Security Validation
AI-assisted development is changing how code reaches repositories. Features that previously required hours of implementation can now be prototyped in minutes, and routine tasks such as refactoring, boilerplate generation, and dependency integration are increasingly delegated to AI tools.
The security challenge is not that AI generates fundamentally different code. The challenge is that repositories can change much faster than before.
This increases the importance of automated validation. Repository controls, SBOM generation, and static analysis help provide a consistent security baseline regardless of whether code was written manually, generated by an AI assistant, or produced through a combination of both.
Security is not only about the final code. It is also about the process that produced that code.
As AI tooling continues to evolve, repository security will need to account for new trust boundaries and validation requirements. Prompt injection, agent security, and runtime trust boundaries deserve a deeper discussion of their own and will be the subject of a future article.
Conclusion
The biggest shift in my thinking was realizing that repository security is no longer only about protecting source code.
Modern repositories sit at the intersection of software development, supply-chain management, and operational security. They influence what enters a build, how software is validated, and ultimately what reaches production.
The controls described in this article serve different purposes. Some help identify issues before code is merged. Others provide visibility into deployed software long after a release has been shipped. Together, they create a more complete picture of the systems we build and maintain.
As software ecosystems continue to grow in complexity and AI-assisted development accelerates change, repository security is becoming an increasingly important part of software engineering. Not only during development, but throughout the lifecycle of the software itself.
