Skip to content

Instantly share code, notes, and snippets.

@sozercan
Created April 10, 2026 18:14
Show Gist options
  • Select an option

  • Save sozercan/28bee05499cdad1db6215b2d1dee199c to your computer and use it in GitHub Desktop.

Select an option

Save sozercan/28bee05499cdad1db6215b2d1dee199c to your computer and use it in GitHub Desktop.
copa threat model
Overview
Project Copacetic (copa) is a Go CLI and optional BuildKit frontend that patches existing container images directly. It parses vulnerability scan reports (Trivy or a custom copa-<scanner> plugin), builds an update manifest, downloads OS and language package updates, and applies those updates via BuildKit to produce a patched image. It can patch single or multi-arch images, push to registries or export OCI layouts, and generate VEX documents (pkg/generate, pkg/vex). The tool is typically run in CI/CD or by security operators with registry credentials and access to a trusted BuildKit daemon. It is not a network service and does not include user authentication or multi-tenant isolation by itself.
Threat model, Trust boundaries and assumptions
Trust boundaries
Host environment: the machine running copa holds filesystem access, registry credentials, and executes helper binaries (docker, podman, tar, copa-<scanner>). Compromise here is severe.
BuildKit daemon/worker: executes update commands inside containerized build steps (pkg/buildkit, pkg/patch). It is assumed trusted and isolated from untrusted tenants.
Container registries and package repositories: external services used to pull images, push patched images, and download updates.
Scanner reports and plugins: JSON report files and optional external scanner binaries (pkg/report/report.go) feed the update manifest.
Output artifacts: patched images, OCI layouts, and VEX files are written to operator-chosen locations.
Attacker-controlled inputs (in realistic deployments)
Container images and image metadata pulled from registries (filesystem contents, package metadata, manifest annotations).
Vulnerability reports (JSON) or plugin output, which influence package names, versions, and paths.
Network responses from registries, package repositories (apt/yum/apk, npm/pypi/go), and the optional EOL API (pkg/utils/eol.go).
If copa is wrapped as a service, untrusted users may also control CLI flags, report paths, and target registries.
Operator-controlled inputs
CLI flags and environment variables: image reference, report path, buildkit address/TLS certs, loader choice, output paths, proxies, timeouts (pkg/cmd/cmd.go).
Bulk patch YAML configuration and tag templates (pkg/bulk).
Selection of scanner plugins (--scanner) and enabling experimental options.
Registry credentials sourced from local Docker/Podman configuration.
Developer-controlled inputs
Test fixtures, mock data, integration tests, and build tooling.
Assumptions
BuildKit daemon and container runtime are trusted and are not shared with untrusted tenants.
Scanner plugins installed on the host are trusted by the operator.
Package repositories and registries use HTTPS and standard signature verification; integrity checking beyond that is out of scope.
The tool is run in a trusted CI/ops context; if exposed as a service, additional sandboxing and policy controls are required.
Attack surface, mitigations and attacker stories
CLI/configuration handling
Entry points (pkg/cmd/cmd.go, cmd/frontend/main.go) parse flags, configure timeouts, and support both single-image and bulk mode. Bulk YAML parsing (pkg/bulk/config.go) validates apiVersion, kind, and tag strategies, and tag templates are evaluated with text/template (no custom functions).
Attacker story: In a multi-tenant wrapper, a malicious config could request patching or pushing to arbitrary registries. This is operator-controlled in normal use but becomes high risk if untrusted users supply configs. Mitigate with policy enforcement outside copa.
Report parsing and scanner plugins
pkg/report/report.go validates scanner names using a strict regex before executing a copa-<scanner> binary and parses JSON into an update manifest. pkg/report/trivy.go handles Trivy output parsing.
Mitigations: scanner name validation prevents shell injection; parsing errors surface early. Updates are later re-validated by package managers.
Attacker story: A malicious report tries to inject shell metacharacters in package names or versions. OS package names are validated in pkg/pkgmgr/pkgmgr.go and language package names/versions are validated in pkg/langmgr/python.go and pkg/langmgr/nodejs.go, reducing this risk. Remaining risk is DoS from huge reports or untrusted plugin output.
OS package manager execution
pkg/pkgmgr/* builds update graphs for apt/dpkg, rpm/yum, apk, and pacman. Updates are executed inside BuildKit containers, sometimes via embedded scripts (e.g., pkg/pkgmgr/scripts/apt_get_download.sh).
Mitigations: ValidateOSPackageNames enforces strict naming patterns and forbids shell metacharacters; versions are checked via package-manager-specific comparers; scripts use controlled arguments.
Attacker story: If validation is bypassed or a new manager omits checks, report data could lead to command injection in BuildKit workers. Because BuildKit typically runs with elevated privileges, this could become a host compromise (critical) if the worker is not isolated.
Language package managers and tool containers
pkg/langmgr/* updates Python, Node.js, Go, and .NET dependencies. Many operations use sh -c but pass untrusted values as positional arguments or validate them (validatePythonPackageName, validateNodePackageName, path safety checks).
Tooling containers (e.g., docker.io/library/node, docker.io/library/golang) are used when runtime tools are missing.
Mitigations: strict validation for names/versions; careful argument passing; reusable update manifest validation; fallbacks when tools missing.
Attacker story: Malicious PkgPath or package names try to escape paths or modify unexpected locations. These changes are confined to the image filesystem but could still produce a poisoned image. If a tooling image or package registry is compromised, the patched image inherits that risk.
BuildKit integration and image export
pkg/buildkit/buildkit.go resolves images, constructs LLB graphs, and exports to tar/OCI layouts. Tar extraction uses filepath.Clean and checks for regular files.
Mitigations: BuildKit capability checks (pkg/buildkit/drivers.go), controlled extraction paths, and explicit platform handling reduce accidental misuse.
Attacker story: A malicious image exploits BuildKit or package manager vulnerabilities during patching, potentially escaping the build sandbox. This is a fundamental risk of processing untrusted container images and should be mitigated by hardening the BuildKit daemon and using rootless or isolated workers.
Registry and network interactions
pkg/utils/utils.go and pkg/bulk use go-containerregistry with the default keychain to access registries; pkg/utils/eol.go performs HTTP requests to the EOL API when enabled.
Attacker story: If an untrusted user can control image references or EOL API base URL, they could force outbound requests (SSRF-like behavior) or trigger use of credentials against unintended registries. This is low risk in normal operator-driven usage but high in a multi-tenant service.
External command execution
pkg/utils, pkg/imageloader, and pkg/buildkit/connhelpers invoke docker, podman, tar, and copa-<scanner> via exec.Command with argument arrays (no shell).
Mitigations: Avoids shell interpolation; logs errors; uses PATH lookup. pkg/provenance/rebuilder.go uses validateShellSafe/validateShellSafeStrict before constructing shell commands.
Attacker story: A compromised PATH or malicious helper binary could run arbitrary code. This is a local environment trust issue rather than a remote vulnerability.
Output artifacts and VEX generation
pkg/generate and pkg/vex serialize VEX/OpenVEX documents and write to operator-specified paths.
Attacker story: In a service context, untrusted output paths could overwrite files. In normal usage, these paths are operator-controlled and not considered attacker input.
Non-applicable vulnerability classes
The project is not a web service; classic web vulnerabilities (XSS, CSRF, session fixation) and multi-tenant authz issues do not apply unless copa is embedded into a service layer.
Criticality calibration (critical, high, medium, low)
Critical
Remote code execution or privilege escalation on the host or BuildKit worker triggered by untrusted reports, package names, or image contents (e.g., command injection bypassing ValidateOSPackageNames or validateNodePackageName).
Arbitrary file write outside the intended working directory on the host via path traversal in export/extraction logic or unsafe output path handling in a service wrapper.
Leakage of registry credentials leading to broad registry compromise when untrusted inputs can influence registry access.
High
Supply-chain compromise of patched images (e.g., attacker-controlled package repositories or tooling images causing malicious updates) that leads to production image backdooring.
Ability for an untrusted user to push images to arbitrary registries or overwrite tags in bulk mode when copa is used as a service without policy controls.
SSRF-like outbound requests to internal registries/EOL API endpoints if untrusted users control image references or base URLs in a shared environment.
Medium
Denial-of-service from large or malformed reports/images that exhaust CPU, memory, or disk, despite timeouts (--timeout) and error handling.
Incorrect patch selection or VEX generation that misrepresents vulnerability status, causing operational risk but not direct exploitation.
Limited information exposure through verbose logs (e.g., image names, report paths) in shared CI systems.
Low
Minor crashes or validation errors that only affect a local patching run.
Cosmetic issues in progress output or summary reporting.
Security issues in test-only code or documentation content (e.g., website assets) that do not affect runtime behavior.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment