Skip to main content

Buildpacks Is Cutting Kaniko Out of Your git-push Pipeline

9 min readDora NodaDora Noda
Share
On this page

Every pack build you run executes code from a project Google abandoned. The Cloud Native Buildpacks lifecycle — the binary that turns your git push into an OCI image — compiles kaniko's Dockerfile executor directly into itself, and in August 2026 the only reproducible High-severity CVE in a lifecycle release scan arrived through exactly that dependency path. The buildpacks team has a plan to cut kaniko out entirely. Here is where it sits in your trust chain, what the extraction looks like, and what your platform inherits the day it ships.

Where kaniko actually sits: a map of the trust chain​

Kaniko is not a tool your platform shells out to. It is a Go library compiled into the lifecycle binary, reachable through one package: internal/extend/kaniko. That package powers the extender phase, which applies extension Dockerfiles to build and run images — the mechanism behind buildpacks image extensions.

Follow the chain from push to running container:

  1. A tenant pushes source. Your platform invokes the lifecycle (via pack, kpack, or Tekton) inside a builder image.
  2. The lifecycle binary runs its phases. The extender is not even a separate program — in the lifecycle tarball and image it is a symlink pointing back to the same 29 MB lifecycle binary.
  3. For each image extension, the extender hands Dockerfiles to kaniko's executor, which applies them to the build or run image and snapshots the result into new layers.
  4. The exporter writes the final OCI image your scheduler runs.

So kaniko's tar handling, filesystem snapshotting, and registry push code all run with your build's credentials, against both the image your code compiles in and the image your code ships in. When Google archived the project in June 2025 — 15,760 stars, read-only, no more patches — every platform built on buildpacks inherited an unmaintained link in the middle of that chain. Not in some optional plugin, but in the binary that assembles every image.

The August 2026 evidence makes this concrete rather than theoretical. Triaging seven grype findings against a lifecycle release, a maintainer traced each one for actual reachability with go mod why instead of reacting to module versions alone. Six findings turned out to be unreachable or already fixed. The single reproducible High — an infinite loop in golang.org/x/text on invalid UTF-8 input — reached the lifecycle binary through precisely this path: internal/extend/kaniko → kaniko/pkg/executor → spf13/afero. Bumping the transitive dependency cleared the scan from one finding to zero, but the conduit remains: as long as the extender links kaniko, kaniko's dependency tree is your builder's dependency tree.

Two forks and a CVE: how we got here​

Kaniko's afterlife has moved fast. The timeline matters because "unmaintained" now has three different answers depending on which kaniko you mean:

DateEvent
Early 2025Google's kaniko goes effectively unmaintained; issue #3348 tracks the status discussion
June 3, 2025Google archives GoogleContainerTools/kaniko (15,760 stars, read-only, no more patches)
June 26, 2025Buildpacks lifecycle switches its dependency to chainguard-dev/kaniko, three weeks after archival
Oct 2024 – 2026The community fork at osscontainertools/kaniko becomes the maintained continuation: updated dependencies, bug fixes, performance work, public images
Feb 27, 2026CVE-2026-28406: path traversal in kaniko tar extraction (versions 1.25.4–1.25.9), CVSS 8.2, fixed in 1.25.10
2026Lifecycle tracks the community fork via dependabot (v1.28.5 as of late September) and runs grype reachability triage on every release

Two details in that table deserve emphasis. First, lifecycle switched forks within three weeks of archival — the maintainers never let the dependency sit on the dead Google module path. Second, the February 2026 CVE hit the maintained fork line: a ../outside.txt-style escape during build-context extraction that, in environments with registry credentials configured, could be chained with docker credential helpers toward code execution in the executor process. The fix shipped as 1.25.10 with securejoin path resolution, and lifecycle picked it up through its normal dependabot flow.

That is the honest definition of "maintained": not vulnerability-free, but patchable. An unmaintained dependency does not get a 1.25.10. It also does not get the quiet, ongoing work the fork has done since — dependency refreshes, BuildKit-compatibility flags, dead-code removal — all of which flow into your builder images the next time lifecycle cuts a release.

Meanwhile the ecosystem consolidated around two kanikos with different contracts. The community fork publishes public images and keeps adding behavior. Chainguard's fork — now under chainguard-forks/kaniko, run by a company founded by kaniko's original authors — is maintenance-only under its EmeritOSS program: security patches and dependency updates for customers transitioning away, source-only releases, no public images. Lifecycle chose the community line, which is the one that still behaves like an upstream.

What "removal" actually looks like: the extraction plan, stage by stage​

Switching forks bought time; it did not remove the risk. The endgame is the buildpacks RFC to decouple the extend phase from kaniko, drafted in April 2025 and still the operative plan. Its core observation is architectural: kaniko currently does exactly one thing in the lifecycle — the single spec line that says the extender "SHALL apply the Dockerfile to the environment." Everything else in the 29 MB binary has nothing to do with it, yet everything ships together because the extender is a symlink, not a program.

The plan has four stages, and they are not all done. Here is the honest status board:

StageWorkStatus
0. Stop depending on the dead upstreamFork-hop Google → chainguard-dev → osscontainertools; dependabot trackingDone
1. Prove the rest of the tree is cleanGrype scans with go list -deps reachability analysis; migrate docker/docker to moby/moby packages; toolchain bumps for stdlib CVEsIn flight through 2026
2. Split the binarySeparate extender binary with its own go.mod, shipped alongside the lifecycle; optionally a slim lifecycle without itPlanned (RFC Draft)
3. Replace the applierBuildah- or BuildKit-based Dockerfile application; rename <kaniko-dir> to <extend-dir> in the platform specPlanned (RFC Draft)

Stage 1 is where the 2026 action is, and it reads like a supply-chain hygiene checklist any platform could copy. Beyond the August reachability triage, the project migrated off the deprecated docker/docker module in favor of moby/moby packages — unblocking the docker upgrade that kaniko's pinned dependencies had been holding back — and has been bumping the Go toolchain and x/crypto promptly as grype flags stdlib and SSH findings. Each fix documents which CVEs reproduce against a binary built from current main and which are scanner noise, with non-exploitable findings recorded as suppressions in .grype.yaml rather than chased blindly.

Stage 2 is the structural payoff. Giving the extender its own go.mod means kaniko's dependency tree stops being every lifecycle consumer's dependency tree. Platforms that never use image extensions could eventually ship a slim lifecycle with no kaniko code at all, and vulnerability scanners would stop flagging every builder image for CVEs in an executor most builds never invoke.

Stage 3 replaces kaniko's one job with a maintained Dockerfile applier. The RFC already records a completed spike: a Docker-daemon-based extender worked and even improved build-image extension performance, but the maintainers judged the added complexity too much to support. Buildah and BuildKit are the remaining candidates. Note what the RFC is candid about in its drawbacks section — until stage 3 lands, splitting the binary does not silence scanners, because the extender still ships in builders. Isolation first, replacement second, quiet scanners last.

To be explicit about what has not happened: as of late September 2026, lifecycle's go.mod still requires the kaniko fork at v1.28.5, and there is no separate extender binary. The removal is a plan with two stages complete, not a shipped release. Anyone telling you buildpacks already removed kaniko is reading the RFC's title instead of its status field.

What your platform inherits the day it ships — and what to do Monday morning​

When stage 3 lands, a platform built on buildpacks inherits three things without changing its own code. First, a slimmer CVE surface in every builder image: the executor, its filesystem snapshotting, and its transitive tree (afero, credential helpers, compression libraries) either leave the lifecycle entirely or shrink to a maintained applier with a smaller footprint. Second, quieter scanners: builder images stop attracting findings for code paths most builds never execute, which is the difference between a security review that takes an afternoon and one that takes a sprint. Third, a provenance story that finally describes a fully maintained builder — lifecycle releases already ship SBOMs in CycloneDX, SPDX, and Syft formats, and kpack can attach SLSA attestations to the app and builder images it produces, but those documents are only as reassuring as the least-maintained component they list.

None of that requires waiting. The operator checklist for Monday morning:

  1. Track lifecycle releases, not just builder releases. The kaniko fork version, the grype triage, and the eventual extraction all land in lifecycle first. If your platform pins builders, know which lifecycle is inside them.
  2. Scan your builder images with reachability, not just versions. The August triage is the template: go list -deps and go mod why distinguish the one reachable High from six lines of scanner noise. Expect kaniko-adjacent findings until stage 3 ships.
  3. Never pin the archived Google module path. Any Dockerfile, Tekton task, or script still referencing GoogleContainerTools/kaniko is frozen at v1.24.0 with no patches coming. The maintained lines are the community fork's public images or Chainguard's fork for customers.
  4. Watch for the Platform API bump. When <kaniko-dir> becomes <extend-dir>, platforms that perform run-image extension will need to follow the spec change. It will be the clearest signal that stage 2 has actually shipped.

Audit the builder, not just the build​

The general lesson survives any single dependency. Your SBOMs, SLSA attestations, and image scans all describe artifacts the builder produced — but the builder itself is software with its own dependency tree, its own unmaintained corners, and its own CVEs that arrive through it rather than in your code. The buildpacks project modeling this honestly — publishing reachability analysis, naming the unmaintained link, planning its removal in public — is what a healthy upstream looks like. Return the favor: run go mod why on the thing that turns your tenants' source into images, not just on the images it emits.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Buildpacks-style git-push builds are the interface developers expect; owning the machines underneath is what makes the supply chain yours to audit. Star the repo on GitHub or deploy your first app today.

Related articles

Run this on infrastructure you own

bex is the open-source, AI-native Render alternative — push a git repo and get a running HTTPS service on your own machines.

Get started with bex