GitHub Packages has evolved from an afterthought into a legitimate artifact registry. It supports Docker images, npm packages, Maven artifacts, NuGet packages, and RubyGems, all tightly integrated with GitHub's repository and Actions infrastructure. For teams already on GitHub, the convenience factor is hard to beat.
But convenience and security are different things. GitHub Packages has real security features, and it has real gaps. Knowing the difference is essential for making informed decisions about your artifact supply chain.
Access Control Model
GitHub Packages ties access control to GitHub's existing permission model. This is both its strength and its limitation.
Repository-Linked Packages
Packages linked to a repository inherit the repository's visibility and access settings. A package in a private repository is only accessible to users who have at least read access to that repository. This is straightforward but means package access is coupled to code access, which may not match your organizational needs.
A developer who needs to pull a package dependency should not necessarily have read access to the source repository that produced it. GitHub Packages does not provide a clean separation between "can use this package" and "can read the source code."
Organization-Level Packages
GitHub Container Registry (ghcr.io) supports packages scoped to an organization rather than a specific repository. These packages have their own access settings independent of any repository. This provides more flexibility but requires manual access management.
Personal Access Tokens vs. GITHUB_TOKEN
For CI/CD pipelines in GitHub Actions, the automatically provided GITHUB_TOKEN is the right choice. It is scoped to the repository running the workflow and automatically expires when the workflow completes.
For external access, personal access tokens (PATs) or fine-grained tokens are required. Fine-grained tokens are preferable because they can be scoped to specific repositories and specific permissions. Classic PATs grant broader access and should be avoided.
Vulnerability Scanning
Dependabot and Security Advisories
GitHub automatically scans package manifests in repositories and generates Dependabot alerts for known vulnerabilities. This covers npm, Maven, pip, NuGet, and other package types.
However, Dependabot scans the dependency manifests in your source code, not the artifacts stored in GitHub Packages. If someone publishes a vulnerable package to GitHub Packages, Dependabot alerts the consumers of that package through their dependency files, not through the package registry itself.
Container Image Scanning
For Docker images stored in ghcr.io, GitHub does not provide built-in vulnerability scanning comparable to AWS ECR or Azure ACR. You need to integrate a third-party scanner into your GitHub Actions workflow to scan images before or after pushing them.
- name: Scan container image
uses: aquasecurity/trivy-action@master
with:
image-ref: ghcr.io/${{ github.repository }}:${{ github.sha }}
format: table
exit-code: 1
severity: CRITICAL,HIGH
This is a gap. Other registry providers scan images automatically. With GitHub Packages, you build the scanning pipeline yourself.
Code Scanning and SARIF
GitHub's code scanning feature accepts SARIF results from any security tool. You can upload vulnerability scan results for packages and view them in the repository's Security tab. This provides a unified view of security findings but requires explicit integration work.
Supply Chain Security Features
Artifact Attestations
GitHub supports artifact attestations through the attest-build-provenance action, which generates SLSA provenance attestations for your build artifacts. These attestations are stored alongside the artifact and can be verified with GitHub's gh attestation verify command.
This is a strong feature for establishing build provenance. It proves that a specific artifact was built by a specific GitHub Actions workflow from a specific commit. Consumers can verify these attestations before using the package.
Sigstore Integration
GitHub Actions workflows generate Sigstore-compatible signing certificates automatically through the sigstore/cosign-installer action. Combined with keyless signing, this provides strong integrity guarantees for container images pushed to ghcr.io.
Dependency Review
The dependency review action scans pull requests for dependency changes and blocks merging if new dependencies introduce known vulnerabilities. This is a proactive control that prevents vulnerable dependencies from entering your codebase.
What GitHub Packages Does Not Provide
No Built-In Content Trust
GitHub Packages does not have a Docker Content Trust equivalent. There is no registry-level enforcement that prevents pulling unsigned images. You can sign images with Cosign and verify in your deployment pipeline, but the registry itself does not enforce signing.
No Download Prevention Based on Vulnerabilities
Unlike Harbor or Artifactory, GitHub Packages cannot block the download of packages that have known vulnerabilities. You can fail your CI/CD pipeline, but the package remains pullable by anyone with access.
Limited Audit Logging
GitHub's audit log covers organization-level events but provides limited visibility into individual package pull events. You know when packages are published and when permissions change, but tracking who pulled what package and when is more difficult.
No Repository Proxy/Cache
GitHub Packages does not function as a proxy cache for upstream registries. You cannot use it to cache Docker Hub images or npm packages locally. This means you remain dependent on upstream registry availability and are subject to their rate limits.
Best Practices
Use Fine-Grained Tokens
Replace any classic PATs used for package access with fine-grained tokens. Scope them to the minimum repositories and permissions needed.
Sign Your Container Images
Integrate Cosign signing into your GitHub Actions workflow. Even though ghcr.io does not enforce signing, establishing the practice now prepares you for enforcement later.
Scan Before Publishing
Add vulnerability scanning as a required step before publishing packages. Fail the workflow if critical vulnerabilities are found. Do not publish vulnerable artifacts to your registry.
Monitor Package Access
Use GitHub's audit log API to track package-related events. Alert on unexpected package publications, permission changes, and access from new IP ranges.
How Safeguard.sh Helps
Safeguard.sh fills the security gaps in GitHub Packages by providing continuous vulnerability scanning for container images and packages stored in ghcr.io, generating comprehensive SBOMs that go beyond what Dependabot tracks, and enforcing security policies that GitHub Packages does not natively support. When you need to know which of your GitHub Packages contain a newly disclosed vulnerability, Safeguard.sh provides that answer across your entire artifact inventory.