RepoPilotOpen in app →

opencontainers/runc

CLI tool for spawning and running containers according to the OCI specification

Healthy

Healthy across the board

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 1d ago
  • 10 active contributors
  • Distributed ownership (top contributor 33% of recent commits)
Show all 6 evidence items →
  • Apache-2.0 licensed
  • CI configured
  • Tests present

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/opencontainers/runc)](https://repopilot.app/r/opencontainers/runc)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/opencontainers/runc on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: opencontainers/runc

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/opencontainers/runc shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit 1d ago
  • 10 active contributors
  • Distributed ownership (top contributor 33% of recent commits)
  • Apache-2.0 licensed
  • CI configured
  • Tests present

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live opencontainers/runc repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/opencontainers/runc.

What it runs against: a local clone of opencontainers/runc — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in opencontainers/runc | Confirms the artifact applies here, not a fork | | 2 | License is still Apache-2.0 | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 31 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>opencontainers/runc</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of opencontainers/runc. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/opencontainers/runc.git
#   cd runc
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of opencontainers/runc and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "opencontainers/runc(\\.git)?\\b" \\
  && ok "origin remote is opencontainers/runc" \\
  || miss "origin remote is not opencontainers/runc (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
  && ok "license is Apache-2.0" \\
  || miss "license drift — was Apache-2.0 at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "libcontainer/container_linux.go" \\
  && ok "libcontainer/container_linux.go" \\
  || miss "missing critical file: libcontainer/container_linux.go"
test -f "libcontainer/configs/config.go" \\
  && ok "libcontainer/configs/config.go" \\
  || miss "missing critical file: libcontainer/configs/config.go"
test -f "create.go" \\
  && ok "create.go" \\
  || miss "missing critical file: create.go"
test -f "libcontainer/configs/namespaces_linux.go" \\
  && ok "libcontainer/configs/namespaces_linux.go" \\
  || miss "missing critical file: libcontainer/configs/namespaces_linux.go"
test -f "libcontainer/apparmor/apparmor_linux.go" \\
  && ok "libcontainer/apparmor/apparmor_linux.go" \\
  || miss "missing critical file: libcontainer/apparmor/apparmor_linux.go"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 31 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~1d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/opencontainers/runc"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

runc is a lightweight CLI tool that spawns and runs containers on Linux according to the Open Container Initiative (OCI) runtime specification. It directly executes container processes using Linux namespaces, cgroups, and seccomp, serving as the low-level runtime engine that container orchestrators like Docker and Kubernetes invoke to actually start containers. Monolithic single-binary structure: root level contains command handlers (create.go, exec.go, delete.go, events.go, checkpoint.go, init.go) that dispatch to internal/linux for Linux-specific syscalls and namespace manipulation. contrib/completions provides shell completions. docs/ holds architecture guides (cgroup-v2.md, systemd.md, checkpoint-restore.md). internal/pathrs and internal/cmsg isolate Rust FFI and cross-process message handling respectively.

👥Who it's for

Container platform engineers, Linux system administrators, and runtime maintainers who need a spec-compliant, production-grade container runtime. Specifically: developers building container orchestration systems (Docker, Kubernetes, containerd) and security teams auditing container isolation mechanisms.

🌱Maturity & risk

Production-ready and actively maintained. The repo has a Cure53 security audit (docs/Security-Audit.pdf), follows CII Best Practices, uses comprehensive GitHub Actions CI (test.yml, validate.yml, scheduled.yml), maintains a SECURITY.md disclosure policy, and the codebase is 902KB+ of Go with extensive test coverage. This is a critical infrastructure project trusted by major container ecosystems.

Low risk overall, but Linux-specific (no Windows/macOS support per go.mod header requirement). Dependency risk is minimal—core deps are mature (libseccomp, systemd, cgroups). The main risk is the heavy security surface area: container escapes, privilege escalation, and namespacing bugs are high-impact. Single-maintainer risk exists (see MAINTAINERS file), and C integration (46KB in codebase) adds complexity. Breaking changes are documented in docs/deprecated.md.

Active areas of work

Active development visible in versioning (VERSION file updated regularly), ongoing security work (SECURITY.md maintained), and feature additions (experimental.md, docs/cgroup-v2.md for v2 support). The .github/workflows setup shows continuous validation and testing on every commit. Check CHANGELOG.md and RELEASES.md for current focus areas.

🚀Get running

git clone https://github.com/opencontainers/runc.git
cd runc
make

Prerequisites (Ubuntu/Debian): apt install -y make gcc linux-libc-dev libseccomp-dev pkg-config git. On Alpine: apk add bash make gcc libseccomp-dev musl-dev linux-headers git. Binary output: ./runc

Daily commands:

make -j$(nproc)  # Build runc binary
./runc --version  # Verify
./runc list      # List containers (requires Linux + root/CAP_SYS_ADMIN)

Development: make test runs Go tests. make validate runs linting (golangci-lint, clang-format for C). See Makefile for full targets.

🗺️Map of the codebase

  • libcontainer/container_linux.go — Core container lifecycle management; implements the Container interface for Linux systems, handling creation, execution, and state tracking.
  • libcontainer/configs/config.go — Central configuration structure for containers; all runtime spec parsing and container configuration flows through this file.
  • create.go — Entry point for the runc create command; orchestrates container creation by coordinating spec parsing and libcontainer initialization.
  • libcontainer/configs/namespaces_linux.go — Linux namespace setup and management; critical for container isolation (PID, Network, IPC, UTS, User, Cgroup namespaces).
  • libcontainer/apparmor/apparmor_linux.go — AppArmor security profile enforcement; essential for container security policy application on AppArmor-enabled systems.
  • go.mod — Dependency manifest defining OCI runtime-spec, cgroups, seccomp, and system capability bindings critical to OCI compliance.
  • libcontainer/container.go — Abstract Container interface definition; all container operations are defined here, making it essential for understanding the codebase's plugin architecture.

🛠️How to make changes

Add a new container command (e.g., runc pause)

  1. Create new top-level command file (pause.go) following the pattern of create.go/exec.go (create.go)
  2. Register command in main CLI parser by adding urfave/cli Action handler (Makefile)
  3. Implement operation in libcontainer/container_linux.go (e.g., Pause() method on Container interface) (libcontainer/container.go)
  4. Add tests in command file matching existing test patterns (create.go)

Add support for a new Linux security mechanism

  1. Extend libcontainer/configs/config_linux.go with new config fields (libcontainer/configs/config_linux.go)
  2. Add validation rules in libcontainer/configs/validate/validator.go (libcontainer/configs/validate/validator.go)
  3. Implement enforcement in libcontainer/container_linux.go's newProcess() or applySecurityContext() (libcontainer/container_linux.go)
  4. Update OCI spec parsing to handle new field from runtime.json bundle (create.go)

Add a new cgroup v2 feature or controller

  1. Define config struct in libcontainer/configs/config_linux.go (libcontainer/configs/config_linux.go)
  2. Add validation logic in libcontainer/configs/validate/validator.go (libcontainer/configs/validate/validator.go)
  3. Implement cgroup application in container_linux.go's applyCgroups() flow (delegates to github.com/opencontainers/cgroups) (libcontainer/container_linux.go)
  4. Document in docs/cgroup-v2.md (docs/cgroup-v2.md)

Add path security hardening for a new attack vector

  1. Identify vulnerable file operation in libcontainer code (libcontainer/container_linux.go)
  2. Replace with pathrs wrapper from internal/pathrs/path.go (e.g., Securejoin for symlink-safe resolution) (internal/pathrs/path.go)
  3. Add unit tests validating symlink attack prevention (internal/pathrs/path_test.go)

🔧Why these technologies

  • Go — Cross-platform, single-binary deployment; fast execution critical for container operations; strong stdlib for syscalls (golang.org/x/sys/unix).
  • Linux syscalls (clone, unshare, prctl, seccomp) — Direct kernel API necessary for namespace creation, security policy enforcement, and process isolation without overhead.
  • OCI Runtime Specification (v1.3.0) — Standardized container format enabling interoperability with Docker, Kubernetes, containerd, and other OCI-compliant runtimes.
  • Cgroups (v1 & v2) — Kernel mechanism for resource limits (CPU, memory, I/O); abstracted via github.com/opencontainers/cgroups library.
  • seccomp + AppArmor/SELinux — Defense-in-depth security: restrict syscalls and enforce MAC policies to contain container breakout risks.
  • pathrs (safe path resolution) — Prevents TOCTOU and symlink-attack exploits during rootfs setup; critical for unprivileged container creation.

⚖️Trade-offs already made

  • Linux-only implementation (no Windows/macOS container support)

    • Why: OCI spec requires Linux-specific kernel features (namespaces, cgroups, seccomp). Porting is infeasible.
    • Consequence: runc cannot run natively on non-Linux; users on macOS/Windows must use VM-based solutions (Docker Desktop, Lima).
  • Rootless container mode is opt-in and limited

    • Why: User namespaces require kernel support (CONFIG_USER_NS) and introduce UID/GID mapping complexity. Full parity with root mode is impractical.
    • Consequence: Some advanced features (device mounts, network interfaces) unavailable or degraded in rootless mode.
  • Single-process container

    • Why: undefined
    • Consequence: undefined

🪤Traps & gotchas

Linux-only: Code will not build/run on macOS or Windows (internal/linux is Linux-only, go.mod header enforces this). Root/capabilities required: Most runc operations require CAP_SYS_ADMIN or root; testing in unprivileged containers fails silently. libseccomp-dev must be present at build time: Disabling requires build tags (see README); default expects it. libpathrs build tag: Rust library adds build complexity; off by default but optional enabled breaks if libpathrs 0.2.4+ not in system LD_LIBRARY_PATH. OCI spec version lock: runtime-spec dependency version gates spec features (go.mod pins 1.3.0); upgrading can change container behavior. Seccomp profile path assumptions: Some code may assume /etc/seccomp or similar paths exist; differs per distro. C extension compatibility: cgroup and namespace syscalls are version-dependent (kernel 4.x+); older kernels fail. CRIU availability not required but checkpoint.go silently degrades: Feature detection is soft; checkpoint/restore silently fails if CRIU not installed.

🏗️Architecture

💡Concepts to learn

  • Linux namespaces (pid, mnt, net, ipc, uts, user) — Core isolation primitive runc uses to create container boundaries; understanding namespace types (unshare syscalls) is essential to grasp how containers achieve process/network/filesystem isolation.
  • opencontainers/runtime-spec — The authoritative OCI runtime specification that runc implements; sync issues and feature requests here when spec conformance gaps appear.
  • containerd/containerd — Container daemon that wraps runc as its runtime—primary user and integration point; file issues here if runc breaks containerd workflows.
  • containers/crun — Alternative OCI runtime written in C (vs runc's Go); solves same problem with different tradeoffs (smaller memory footprint, different security audit). Users choose between runc and crun.
  • moby/moby — Docker Desktop/Engine uses runc as default low-level runtime; bug reports and feature requests flow through moby if affecting Docker users.
  • kata-containers/kata-containers — Uses runc as shimmed runtime for VM-based containers; depends on runc's stability and spec compliance for hypervisor-backed isolation.

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive unit tests for internal/pathrs package

The internal/pathrs directory contains critical path resolution and security utilities (mkdirall.go, path.go, retry.go, root_pathrslite.go) but internal/pathrs/path_test.go appears to be the only test file. Given that pathrs handles secure path operations crucial for container isolation and security, expanding test coverage for edge cases (symlink attacks, race conditions, permission errors) would significantly improve robustness and reduce security regressions.

  • [ ] Review internal/pathrs/mkdirall.go and internal/pathrs/retry.go for untested functions
  • [ ] Create internal/pathrs/mkdirall_test.go with tests for directory creation edge cases, permission denials, and symlink scenarios
  • [ ] Create internal/pathrs/root_test.go to test root path operations and privilege boundary conditions
  • [ ] Add integration tests demonstrating secure path operations under concurrent access

Add GitHub Actions workflow for Go dependency vulnerability scanning

The repo has validate.yml, test.yml, and scheduled.yml workflows, but no dedicated dependency security scanning. With 20+ direct dependencies (systemd, seccomp, cgroups, etc.) that touch kernel interfaces and system security, a workflow using tools like 'go list -json -m all | nancy' or 'trivy' in CI would catch CVEs early and prevent supply chain attacks affecting container runtime security.

  • [ ] Review .github/workflows/ to confirm no existing vulnerability scanning workflow exists
  • [ ] Create .github/workflows/security-scan.yml with nancy or trivy for Go dependency checks
  • [ ] Configure the workflow to run on pull requests and scheduled basis (weekly)
  • [ ] Add failure conditions to block merges on critical/high severity findings
  • [ ] Document the new workflow in CONTRIBUTING.md

Add unit tests for internal/sys package system call utilities

The internal/sys directory contains Linux-specific system utilities (opath_linux.go for O_PATH flag handling, sysctl_linux.go for kernel parameter access, verify_inode_unix.go for inode verification) but has no visible test files. These are low-level syscall wrappers critical for container sandboxing and namespace isolation. Adding comprehensive tests would catch platform-specific bugs and prevent regressions across kernel versions.

  • [ ] Create internal/sys/opath_linux_test.go testing O_PATH flag behavior, symlink resolution bypassing, and error handling
  • [ ] Create internal/sys/sysctl_linux_test.go for kernel parameter reads with mocked procfs values and error conditions
  • [ ] Create internal/sys/verify_inode_unix_test.go for inode verification logic with various filesystem scenarios
  • [ ] Add build constraints (+build linux) and document any root/capability requirements for tests

🌿Good first issues

  • Add integration tests for runc events command (events.go exists but events_test.go may be sparse)—test that container lifecycle events (create, start, exit, delete) are properly emitted and parseable.
  • Improve error messages when libseccomp is unavailable at runtime—currently fails cryptically; add friendly error pointing users to docs/experimental.md and build tag instructions.
  • Document cgroup v2 systemd integration in docs/systemd.md with a concrete example—explain how runc negotiates cgroup delegation with systemd in modern distros (Ubuntu 21.10+, Fedora 34+).

Top contributors

Click to expand

📝Recent commits

Click to expand
  • eb7eaf1 — Merge pull request #5256 from kolyshkin/int-hook (rata)
  • 543ef45 — Merge pull request #5254 from AkihiroSuda/ci-rawhide (lifubang)
  • 1d12f98 — tests/int: fix TestHook flakiness (kolyshkin)
  • 905958e — tests/int: show stderr if command failed part II (kolyshkin)
  • f19a9e0 — CI: lima: add fedora-rawhide (AkihiroSuda)
  • 4ccedcb — Merge pull request #5250 from AkihiroSuda/ci-cache-lima (kolyshkin)
  • ff44701 — CI: lima: add template name to cache key (AkihiroSuda)
  • 51d0c94 — Merge pull request #5239 from AkihiroSuda/lima-actions (rata)
  • c5077eb — merge #5243 into opencontainers/runc:main (cyphar)
  • 748af2e — libct/test: Disable GC on test run to catch leaking fds (rata)

🔒Security observations

The runc codebase demonstrates good security hygiene with proper dependency management, signed repository verification, and a responsible disclosure policy. Dependencies are relatively up-to-date with no immediately critical known vulnerabilities. However, there are opportunities for improvement: (1) consider urfave/cli v2 migration for long-term support, (2) implement version pinning for build dependencies in Docker, (3) add SBOM generation for supply chain transparency, and (4) strengthen error handling in repository setup. The project follows CII Best Practices and maintains active security monitoring through CI/CD workflows.

  • Medium · Outdated Go Version in Dockerfile — Dockerfile, go.mod. The Dockerfile specifies Go 1.25 which may contain known vulnerabilities. While this is a recent version, it's important to ensure this is intentionally set and regularly updated. The go.mod also specifies go 1.25.0. Fix: Regularly monitor Go security advisories and update to the latest stable version. Consider implementing automated dependency scanning in CI/CD pipeline.
  • Medium · Dependency on github.com/urfave/cli v1.22.17 — go.mod. The urfave/cli v1 package is in maintenance mode. While v1.22.17 is relatively recent, the project should consider migrating to v2 which has better security updates and active development. Fix: Plan migration to github.com/urfave/cli/v2 to ensure long-term security support and feature updates.
  • Low · Multiple Indirect Dependencies from Cilium eBPF — go.mod (indirect dependency). The indirect dependency github.com/cilium/ebpf v0.17.3 is a complex package dealing with kernel interfaces. While no immediate vulnerability is evident, eBPF code requires careful security review. Fix: Monitor cilium/ebpf security advisories and consider adding additional security testing for eBPF-related functionality.
  • Low · Build Dependencies Not Pinned in Dockerfile — Dockerfile (apt-get install section). The Dockerfile installs packages via apt-get without specific version pinning (e.g., build-essential, cargo, clang). This could lead to unexpected updates with breaking changes or vulnerabilities. Fix: Pin versions of critical build dependencies: 'apt-get install -y build-essential=12.X clang=X.Y.Z' to ensure reproducible and secure builds.
  • Low · External Repository Added Without Signature Verification Hardening — Dockerfile (CRIU_REPO setup). While the Dockerfile does verify the CRIU repository signature, the gpg command pipes directly without additional error handling. If the key retrieval fails silently, apt could fall back to unsigned packages. Fix: Add explicit error checking: '|| exit 1' after gpg command. Consider pre-staging the GPG key rather than downloading it during build.
  • Low · Missing SPDX License Identifier — Repository root, source files. While a LICENSE file exists, there are no SPDX license identifiers in source files or go.mod metadata for clear license compliance tracking. Fix: Add SPDX-License-Identifier comments to source files and ensure go.mod license metadata is properly configured.
  • Low · No SBOM (Software Bill of Materials) Generation — .github/workflows/. The project lacks an automated SBOM generation process in CI/CD, making it harder for users to track dependencies and apply security patches. Fix: Integrate SBOM generation tools (cyclonedx, syft) into the build pipeline and publish SBOMs with releases.
  • Low · Permissive Multi-Platform Architecture Support — Dockerfile (dpkg --add-architecture). The Dockerfile adds support for 9 different CPU architectures (i386, armel, armhf, arm64, ppc64el, s390x, riscv64). While valuable for compatibility, this increases the attack surface and testing burden. Fix: Document which architectures are officially tested and supported. Consider security-focused testing for less common architectures.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · opencontainers/runc — RepoPilot