Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build-and-upload.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
- name: Authenticate gooci cli
run: gooci login ghcr.io --username ${{ github.actor }} --password ${{ secrets.GITHUB_TOKEN }}
- name: gooci Upload Version
run: gooci upload dist/ ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{github.ref_name}}
run: gooci upload dist/ ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{github.ref_name}} --annotate="org.ccf.plugin.protocol.version=2
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚖️ Poor tradeoff

Potential template injection via GitHub context variables.

The workflow uses unsanitized GitHub context variables (github.repository_owner, github.event.repository.name, github.ref_name) in shell commands. In certain scenarios (e.g., workflow running from a fork or with crafted repository names), these could inject arbitrary commands.

For a plugin template used in a trusted context, this risk may be acceptable. However, if this workflow will run on pull requests from forks or in untrusted environments, consider sanitizing the inputs or using environment variables instead.

🛡️ Defensive alternatives

Option 1: Use environment variables

- name: gooci Upload Version
  env:
    REPO_OWNER: ${{ github.repository_owner }}
    REPO_NAME: ${{ github.event.repository.name }}
    REF_NAME: ${{ github.ref_name }}
  run: gooci upload dist/ "ghcr.io/${REPO_OWNER}/${REPO_NAME}:${REF_NAME}" --annotate="org.ccf.plugin.protocol.version=2"

Option 2: Add input validation

- name: Validate inputs
  run: |
    if [[ ! "${{ github.ref_name }}" =~ ^[a-zA-Z0-9._-]+$ ]]; then
      echo "Invalid ref name"
      exit 1
    fi

Also applies to: 28-28

🧰 Tools
🪛 zizmor (1.25.2)

[warning] 25-25: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 25-25: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 25-25: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-and-upload.yml at line 25, The workflow run command
embeds unsanitized GitHub context variables (github.repository_owner,
github.event.repository.name, github.ref_name) into the shell invocation which
can lead to template/shell injection; fix by moving those contexts into
environment variables and using the env names in the run step (or
validate/sanitize them before use) so the invocation uses safe values (e.g., set
REPO_OWNER, REPO_NAME, REF_NAME from the contexts and reference those in the
gooci upload command), or add an input-validation step that rejects unexpected
characters in github.ref_name before running the upload.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Missing closing quote in annotation argument.

Both gooci upload commands have unterminated strings in the --annotate parameter. The opening quote for the annotation value is never closed, which will cause shell syntax errors.

🐛 Proposed fix
       - name: gooci Upload Version
-        run: gooci upload dist/ ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{github.ref_name}} --annotate="org.ccf.plugin.protocol.version=2
+        run: gooci upload dist/ ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{github.ref_name}} --annotate="org.ccf.plugin.protocol.version=2"
       - name: gooci Upload Latest
         if: "!github.event.release.prerelease"
-        run: gooci upload dist/ ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:latest --annotate="org.ccf.plugin.protocol.version=2
+        run: gooci upload dist/ ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:latest --annotate="org.ccf.plugin.protocol.version=2"

Also applies to: 28-28

🧰 Tools
🪛 zizmor (1.25.2)

[warning] 25-25: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 25-25: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 25-25: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-and-upload.yml at line 25, The --annotate argument
in the gooci upload commands has an unterminated string; update both occurrences
of the gooci upload invocation so the annotation value is properly quoted (e.g.
close the opening double quote after the annotation like
--annotate="org.ccf.plugin.protocol.version=2") ensuring each gooci upload
command’s --annotate parameter ends with a matching closing quote.

- name: gooci Upload Latest
if: "!github.event.release.prerelease"
run: gooci upload dist/ ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:latest
run: gooci upload dist/ ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:latest --annotate="org.ccf.plugin.protocol.version=2
37 changes: 37 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# The help target prints out all targets with their descriptions organized
# beneath their categories. The categories are represented by '##@' and the
# target descriptions by '##'. The awk commands is responsible for reading the
# entire set of makefiles included in this invocation, looking for lines of the
# file as xyz: ## something, and then pretty-format the target and help. Then,
# if there's a line with ##@ something, that gets pretty-printed as a category.
# More info on the usage of ANSI catalog characters for terminal formatting:
# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
# More info on the awk command:
# http://linuxcommand.org/lc3_adv_awk.php

# Check if OPA CLI is installed
OPA := $(shell command -v opa 2> /dev/null)
ifeq ($(OPA),)
$(error "opa CLI not found. Please install it: https://www.openpolicyagent.org/docs/latest/cli/")
endif

##@ Help
help: ## Display this concise help, ie only the porcelain target
@awk 'BEGIN {FS = ":.*##"; printf "\033[1mUsage\033[0m\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-30s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)

help-all: ## Display all help items, ie including plumbing targets
@awk 'BEGIN {FS = ":.*#"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?#/ { printf " \033[36m%-25s\033[0m %s\n", $$1, $$2 } /^#@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)


test:
@go test ./...

clean: # Cleanup build artifacts
@rm -rf dist/*

build: clean ## Build the plugin package
@mkdir -p dist/
@go build -o dist/plugin main.go
Comment on lines +26 to +34
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Declare non-file targets as .PHONY.

Targets that don't produce files (help, help-all, test, clean, build, run) should be declared .PHONY to prevent make from treating them as file targets. Without this, make will skip the target if a file with that name exists in the directory.

♻️ Proposed fix

Add this line near the top of the Makefile, after the OPA check:

 endif
 
+.PHONY: help help-all test clean build run
+
 ##@ Help
 help: ## Display this concise help, ie only the porcelain target
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` around lines 26 - 34, Add a .PHONY declaration for non-file targets
to prevent Make from treating them as actual files: declare .PHONY with the list
of targets (help, help-all, test, clean, build, run) near the top of the
Makefile (e.g., after the OPA check), so targets like test, clean, build, run
are always executed regardless of same-named files.


run: build ## Execute the Concom agent with the built plugin
@../agent/dist/./concom agent --config ./.config/config.yaml
Comment on lines +36 to +37
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Consider making the agent path configurable.

The hardcoded relative path ../agent/dist/./concom assumes a specific directory structure. While documented in the README, this makes the target fragile and less portable.

♻️ Proposed improvements

Option 1: Add a configurable variable

+# Path to the Concom agent binary (override with: make run AGENT_PATH=/custom/path)
+AGENT_PATH ?= ../agent/dist/concom
+
 ##@ Help
 run: build ## Execute the Concom agent with the built plugin
-	@../agent/dist/./concom agent --config ./.config/config.yaml
+	@$(AGENT_PATH) agent --config ./.config/config.yaml

Option 2: Add an existence check

 run: build ## Execute the Concom agent with the built plugin
+	`@test` -f ../agent/dist/concom || (echo "Error: agent not found at ../agent/dist/concom" && exit 1)
 	@../agent/dist/./concom agent --config ./.config/config.yaml
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
run: build ## Execute the Concom agent with the built plugin
@../agent/dist/./concom agent --config ./.config/config.yaml
run: build ## Execute the Concom agent with the built plugin
`@test` -f ../agent/dist/concom || (echo "Error: agent not found at ../agent/dist/concom" && exit 1)
@../agent/dist/./concom agent --config ./.config/config.yaml
🧰 Tools
🪛 checkmake (0.3.2)

[warning] 36-36: Required target "all" is missing from the Makefile.

(minphony)


[warning] 36-36: Required target "clean" must be declared PHONY.

(minphony)


[warning] 36-36: Required target "test" must be declared PHONY.

(minphony)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` around lines 36 - 37, The run target currently uses a hardcoded
agent path "../agent/dist/./concom"; make this configurable by introducing a
Makefile variable (e.g., AGENT_BIN or AGENT_PATH) with a sensible default and
replace the literal path in the run recipe with that variable, and also add an
existence check for $(AGENT_BIN) before executing (print an error and exit
non‑zero if missing) so the target is portable and fails fast when the binary is
not found.

46 changes: 34 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,45 @@ goreleaser release --snapshot --clean

## Usage

You can use this plugin by passing it to the compliiance agent
You can use this plugin by passing it to the compliance agent or by specifying it in the agent config

```shell
agent --plugin=[PATH_TO_YOUR_BINARY]
```

## Releasing
```yaml
# AGENT CONFIG

verbosity: 2

api:
url: http://localhost:8080

plugins:
# Plugin execution identifier
myplugin:
# Config mapping passed through to Configure lifecycle event
config:
anykey: "anyval"
policy_labels: "{\"my_key\":\"my_value\"}"
# Compatible protocol version: Defaults to 1, can also be determined a plugin image manifest annotation of "org.ccf.plugin.protocol.version=2"
protocol_version: 2
# Source to plugin executable location. Can be an OCI image or local executable
source: /path/to/dist/plugin
# List to all policies to pass to plugin, all may be processed or filtered later via policy_behavior
policies:
- /path/to/policy/bundle.tar.gz
Comment on lines +35 to +48
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a policy_data / policy_behavior example here would also be useful.

# Policy behaviour can be defined to later filter policies to specific bundles per execution
# This is useful if your plugin proccesses more than 1 type of component
Comment on lines +49 to +50
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix spelling/wording in YAML comments.

Line 49-50 has user-facing typos/inconsistent spelling (behaviour, proccesses). Please normalize to behavior and processes for clarity and consistency with the rest of the docs/code terminology.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 49 - 50, Update the two YAML comment strings to fix
spelling/wording: change "Policy behaviour can be defined to later filter
policies to specific bundles per execution" to use "behavior" instead of
"behaviour", and change "This is useful if your plugin proccesses more than 1
type of component" to use "processes" instead of "proccesses" (i.e., replace the
exact substrings "behaviour" -> "behavior" and "proccesses" -> "processes" in
the README comment lines).

policy_behavior:
string-to-match-to-policy:
- "associated-behavior-1"
# Policy data is passed to the plugin for evaluation, can be used to customize evaluation parameters
policy_data:
policy_data_key: "policy_data_value"


This plugin is released using goreleaser to build binaries, and Docker to build OCI artifacts (WIP), which will ensure a binary is built for most OS and Architecture combinations.

You can find the binaries on each release of this plugin in the GitHub releases page.

You can find the OCI implementations in the GitHub Packages page.

[Not Yet Implemented] To run this plugin with the Compliance Agent, you can specify the release. The agent will take care of pulling the correct binary.

```shell
concom agent --plugin=https://github.com/compliance-framework/plugin-template/releases/tag/0.0.1
```

You can also use `make run` to build this plugin and execute against the agent, if the agent is located in the parent directory. See Makefile:run

78 changes: 41 additions & 37 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,57 +1,61 @@
module github.com/compliance-framework/plugin-template

go 1.23.6

toolchain go1.24.1
go 1.26.1

require (
github.com/compliance-framework/agent v0.1.2
github.com/compliance-framework/configuration-service v0.1.1
github.com/google/uuid v1.6.0
github.com/compliance-framework/agent v0.7.0
github.com/hashicorp/go-hclog v1.6.3
github.com/hashicorp/go-plugin v1.6.3
google.golang.org/protobuf v1.36.6
github.com/hashicorp/go-plugin v1.7.0
)

require (
github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/agnivade/levenshtein v1.2.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/compliance-framework/api v0.16.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 // indirect
github.com/defenseunicorns/go-oscal v0.7.0 // indirect
github.com/docker/docker v28.5.2+incompatible // indirect
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check if docker package is actually imported/used in the codebase

echo "=== Checking for direct docker imports ==="
rg -n --type=go 'github\.com/docker/docker' -g '!go.mod' -g '!go.sum'

echo ""
echo "=== Checking which dependency brings in docker ==="
go mod why github.com/docker/docker

echo ""
echo "=== Checking for latest docker version and patches ==="
curl -s https://proxy.golang.org/github.com/docker/docker/@latest | jq -r '.Version'

Repository: compliance-framework/plugin-template

Length of output: 9640


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== rg for docker/docker imports (code only) ==="
rg -n --type=go 'github\.com/docker/docker' -g '!go.mod' -g '!go.sum' || true

echo
echo "=== go mod why (module-level) ==="
go mod why -m github.com/docker/docker || true

echo
echo "=== go list deps (including tests) that reference docker/docker ==="
go list -deps -test ./... 2>/dev/null | rg -n 'github\.com/docker/docker' || true

echo
echo "=== go mod graph edges that mention docker/docker (filtered) ==="
go mod graph | rg 'github\.com/docker/docker' || true

Repository: compliance-framework/plugin-template

Length of output: 863


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Find any packages in this module that import docker/docker subpackages ==="
rg -n --type=go 'github\.com/docker/docker/(.+)?' -g '!go.mod' -g '!go.sum' || true

echo
echo "=== Identify packages whose resolved module is github.com/docker/docker (deps including tests) ==="
# Uses -json to map packages -> module path, then filters for github.com/docker/docker
go list -deps -test -json ./... 2>/dev/null \
  | jq -r 'select(.Module != null and .Module.Path=="github.com/docker/docker") | .ImportPath' \
  | sort -u | sed '/^$/d' || true

echo
echo "=== Does testcontainers-go appear in non-test packages? ==="
rg -n --type=go 'github\.com/testcontainers/testcontainers-go' -g '!go.mod' -g '!go.sum' . || true

Repository: compliance-framework/plugin-template

Length of output: 320


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Inspect go list -deps -test -json for packages belonging to github.com/docker/docker ==="
go list -deps -test -json ./... 2>/dev/null \
  | rg -n '"Module":\s*{' -n || true

# More direct: print ImportPath values where the JSON shows Module.Path == github.com/docker/docker
go list -deps -test -json ./... 2>/dev/null \
  | python3 - <<'PY'
import sys, json, re
buf=[]
for line in sys.stdin:
    buf.append(line)
    if line.strip() == '}':
        pass
PY

Repository: compliance-framework/plugin-template

Length of output: 283


🏁 Script executed:

#!/bin/bash
set -euo pipefail

pkgs=(
  "github.com/compliance-framework/agent/runner"
  "github.com/compliance-framework/api/sdk"
  "github.com/compliance-framework/api/sdk.test"
)

for p in "${pkgs[@]}"; do
  echo "===== $p ====="
  dir="$(go list -f '{{.Dir}}' "$p" 2>/dev/null || true)"
  echo "Dir: ${dir:-<unknown>}"

  if [ -n "$dir" ] && [ "$dir" != "<unknown>" ]; then
    rg -n --hidden --no-ignore -S 'github\.com/docker/docker' "$dir" || true
    rg -n --hidden --no-ignore -S 'docker\.go' "$dir" || true
  fi

  echo
done

echo "===== Any docker/docker imports across this module (all .go files) ====="
rg -n --type=go 'github\.com/docker/docker' . -g '!go.mod' -g '!go.sum' || true

Repository: compliance-framework/plugin-template

Length of output: 499


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== docker/docker packages in NON-TEST deps (import graph) ==="
go list -deps -json ./... 2>/dev/null \
  | jq -r 'select(.Module != null and .Module.Path=="github.com/docker/docker") | .ImportPath' \
  | sort -u || true

echo
echo "=== docker/docker packages in TEST deps (import graph) ==="
go list -deps -test -json ./... 2>/dev/null \
  | jq -r 'select(.Module != null and .Module.Path=="github.com/docker/docker") | .ImportPath' \
  | sort -u || true

echo
echo "=== modules requiring docker/docker in NON-TEST build ==="
go mod why -m github.com/docker/docker 2>/dev/null || true

Repository: compliance-framework/plugin-template

Length of output: 546


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== rg for testcontainers-go usage (excluding vendor) ==="
rg -n --hidden --no-ignore -S 'testcontainers[-.]go' . -g '!go.mod' -g '!go.sum' || true

echo
echo "=== rg for docker client imports in repo (excluding go.mod/sum) ==="
rg -n --hidden --no-ignore -S 'github\.com/docker/docker' . -g '!go.mod' -g '!go.sum' || true

echo
echo "=== List any _test.go files that reference testcontainers ==="
rg -n --hidden --no-ignore -S 'testcontainers[-.]go' . -g '*_test.go' || true

Repository: compliance-framework/plugin-template

Length of output: 270


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Importers of github.com/docker/docker (test vs non-test) ==="
for mode in "" "-test"; do
  echo "--- mode: ${mode:-non-test} ---"
  go list $mode -deps -json ./... 2>/dev/null \
    | jq -r '
        select(.Module and (.Module.Path=="github.com/docker/docker")) 
        | .ImportPath
      ' | sort -u | head -n 200
done

echo
echo "=== Importers that pull in github.com/testcontainers/testcontainers-go (test vs non-test) ==="
for mode in "" "-test"; do
  echo "--- mode: ${mode:-non-test} ---"
  go list $mode -deps -json ./... 2>/dev/null \
    | jq -r '
        select(.Module and (.Module.Path=="github.com/testcontainers/testcontainers-go")) 
        | .ImportPath
      ' | sort -u | head -n 200
done

echo
echo "=== Raw module paths present for deps mentioning docker/docker (sanity) ==="
go list -deps -test -json ./... 2>/dev/null | jq -r '
  select(.Module and (.Module.Path|contains("docker/docker"))) 
  | (.Module.Path + " " + (.Version // ""))
' | sort -u | head -n 50

Repository: compliance-framework/plugin-template

Length of output: 403


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect dependency module sources (not this repo) for docker/testcontainers usage
mods=(
  "/home/jailuser/go/pkg/mod/github.com/compliance-framework/agent@v0.7.0"
  "/home/jailuser/go/pkg/mod/github.com/compliance-framework/api@v0.16.0"
)

for d in "${mods[@]}"; do
  echo "===== Searching in $d for docker/docker ====="
  test -d "$d" && rg -n --hidden --no-ignore -S 'github\.com/docker/docker' "$d" || echo "missing"
  echo
  echo "===== Searching in $d for testcontainers-go ====="
  test -d "$d" && rg -n --hidden --no-ignore -S 'github\.com/testcontainers/testcontainers-go' "$d" || echo "missing"
  echo
  echo "===== Searching in $d for docker client usage indicators ====="
  test -d "$d" && rg -n --hidden --no-ignore -S 'docker\.NewClient|client\.NewClient|dockertest|testcontainers' "$d" || echo "missing"
  echo "----------------------------------------"
done

Repository: compliance-framework/plugin-template

Length of output: 7955


🌐 Web query:

GO-2026-4883 Off-by-one error in plugin privilege validation github.com/docker/docker

💡 Result:

GO-2026-4883 refers to an off-by-one error in plugin privilege validation within the Moby project (the core component of Docker), tracked as CVE-2026-33997 and GHSA-pxq6-2prw-chj9 [1][2]. The vulnerability arises from an error in the daemon's privilege comparison logic, specifically within the isEqual() function, where the loop responsible for comparing requested privileges against approved ones incorrectly started at index 1 instead of index 0 [3]. This flaw leads to two security consequences: 1. Privilege Validation Bypass: The first privilege (alphabetically) is never validated, allowing a malicious plugin to request different values for privileges such as "allow-all-devices," which can grant unrestricted read-write access to host devices [3]. 2. Complete Bypass for Single Privileges: Plugins that request exactly one privilege trigger zero iterations of the comparison loop, effectively bypassing validation entirely [3][4]. This issue is patched in Moby version 29.3.1 [4][2]. Users and projects using the github.com/docker/docker module are advised to update their dependencies, although the Docker/Moby project has also moved toward deprecating the github.com/docker/docker module in favor of maintained modules like github.com/moby/moby/client and github.com/moby/moby/api [5].

Citations:


🌐 Web query:

GHSA-x86f-5xw2-fm2r Container binary execution on host via PUT /containers/{id}/archive github.com/docker/docker

💡 Result:

GHSA-x86f-5xw2-fm2r (also tracked as CVE-2026-41567) is a security vulnerability in Docker Engine that allows for arbitrary code execution on the host with daemon (root) privileges [1][2][3]. The vulnerability occurs when handling PUT /containers/{id}/archive requests that contain compressed archives (specifically xz or gzip) [1][2]. The Docker daemon incorrectly resolves external system binaries required for decompression from the container's filesystem instead of the host's filesystem [1][3]. A malicious container image containing a trojanized decompression binary can exploit this behavior, allowing the binary to execute with the full privileges of the host daemon when an archive is uploaded to the container [1][2][4]. Key points regarding this vulnerability: - Affected Component: github.com/docker/docker (and related moby/moby components) [1][5][2]. - Attack Vector: Requires a user to run a container from a malicious image and subsequently upload a compressed archive (xz or gzip) into that container [1][2]. - Exploitation Examples: This can be triggered by calling the PUT /containers/{id}/archive API directly or by piping a compressed archive through commands like docker cp - [1][2][4]. - Limitations: Standard docker cp usage is not affected because the CLI sends uncompressed tar by default [4]. Decompression formats using pure Go implementations (such as bzip2, zstd, and gzip when an unpigz binary is absent) are also not affected [1][2]. Recommended mitigations include: - Only running containers from trusted images [1][2]. - Using authorization plugins to limit access to the PUT /containers/{id}/archive endpoint [1][2]. - Avoiding the piping of compressed archives into containers created from untrusted sources [1][2]. As of May 28, 2026, advisories indicate that a fix may still be pending for the primary github.com/docker/docker module path [5].

Citations:


🌐 Web query:

GHSA-vp62-88p7-qqf5 Race condition in docker cp (arbitrary file creation) github.com/docker/docker

💡 Result:

GHSA-vp62-88p7-qqf5 (also tracked as CVE-2026-41568) is a security vulnerability in the Docker Engine related to a race condition in the docker cp command [1][2][3][4]. Vulnerability Details The vulnerability exists because of a race condition that occurs when the Docker daemon sets up a temporary filesystem view by bind-mounting volumes while executing a docker cp command (or equivalent API calls like PUT/HEAD /containers/{id}/archive) [1][3]. During this setup process: 1. The daemon resolves the target mount path within the container's root filesystem [1][4]. 2. It then creates the mountpoint (file or directory) if it does not already exist [1][4]. An attacker with a running malicious container can exploit the timing window between these two steps [1][3]. By rapidly creating and swapping path components for symlinks pointing to arbitrary locations on the host, the attacker can cause the daemon to follow these symlinks when it creates the mountpoint [1][4]. Consequently, the daemon creates empty files or directories at arbitrary absolute paths on the host filesystem with root privileges [1][4]. Distinction from Related Vulnerabilities This advisory (GHSA-vp62-88p7-qqf5) specifically addresses the race condition during mountpoint creation [3]. A separate, related vulnerability, tracked as GHSA-rg2x-37c3-w2rh (CVE-2026-42306), involves a different race condition that occurs during the subsequent mount syscall, which allows for bind mount redirection [3][5][6]. Mitigation and Recommendations - Avoid using docker cp with untrusted running containers [1][6]. - Only run containers from trusted images [1][6]. - Utilize authorization plugins to restrict access to the affected archive API endpoints (PUT /containers/{id}/archive and HEAD /containers/{id}/archive) [1][6]. - Ensure your Docker environment is updated to a patched version, as fixes have been implemented to scope mountpoint creation to the container root, preventing escapes even if symlinks are swapped [1].

Citations:


🌐 Web query:

GHSA-rg2x-37c3-w2rh Race condition in docker cp (bind mount redirection) github.com/docker/docker

💡 Result:

GHSA-rg2x-37c3-w2rh is a security advisory describing a race condition in the docker cp command that allows a malicious container to perform bind mount redirection to an arbitrary path on the host filesystem [1][2]. When a user initiates a docker cp operation, the Docker daemon sets up a temporary filesystem view by bind-mounting volumes into a private mount namespace [1]. During this setup process, a mount destination is created inside the container root, and a bind mount is subsequently attached to the container-relative path [1]. The vulnerability arises because there is a race condition between the creation of this mountpoint and the execution of the mount syscall [1]. A process running inside a malicious container can exploit this window by replacing the mount destination (or one of its parent path components) with a symbolic link pointing to an arbitrary location on the host [1]. When the mount syscall is executed, it follows the symlink, resulting in the volume being bind-mounted onto the host path rather than the intended location inside the container [1]. The impact of this exploit depends on the nature of the mount: - If the volume is writable, an attacker could potentially overwrite arbitrary host files at the redirected path with the volume's contents [1]. - If the volume is read-only, the host path is masked by the mount for the duration of the copy operation, which can cause a denial of service on the host [1]. Requirements for exploitation include [1]: - The container must have at least one volume mount. - A process inside the container must be capable of rapidly creating and swapping symlinks at the target mount destination. - An operator must trigger a docker cp command into the affected container (or call the corresponding PUT/HEAD /containers/{id}/archive API endpoints) [1]. Mitigation strategies recommended by the advisory include [1]: - Running only containers from trusted images. - Avoiding the use of docker cp with untrusted or running containers. - Utilizing authorization plugins to restrict access to the archive API endpoints [1]. This vulnerability is distinct from a related issue, tracked as GHSA-vp62-88p7-qqf5, which involves a race condition during mountpoint creation that allows for the creation of arbitrary empty files or directories on the host [3][4].

Citations:


🌐 Web query:

GHSA-x744-4wpc-v9h2 AuthZ plugin bypass github.com/docker/docker

💡 Result:

GHSA-x744-4wpc-v9h2 (also tracked as CVE-2026-34040) is a security vulnerability in Moby (the engine powering Docker) that allows an attacker to bypass authorization (AuthZ) plugins [1][2][3]. Under specific circumstances, a specially-crafted API request can cause the Docker daemon to forward the request to an AuthZ plugin without including the request body [1][3]. If an AuthZ plugin relies on introspecting this body to make access control decisions, it may incorrectly allow a request that it otherwise would have denied [1][3]. Key details include: - Impact: Users are only affected if they utilize AuthZ plugins that rely on request body inspection for security decisions [1][3]. - Status: This issue is identified as an incomplete fix for a previous, related vulnerability, CVE-2024-41110 [1][3]. - Affected Versions: Versions of Moby prior to 29.3.1 [4][2][3]. - Resolution: The issue was patched in version 29.3.1 [4][2][3]. - Mitigations: If updating immediately is not possible, users are advised to restrict access to the Docker API to trusted parties following the principle of least privilege and avoid using AuthZ plugins that rely on request body inspection [1][3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Direct imports of github.com/docker/docker (excluding go.mod/go.sum) ==="
rg -n --type=go 'github\.com/docker/docker' -g '!go.mod' -g '!go.sum' . || true

echo
echo "=== docker/docker required for non-test builds? ==="
go list -deps ./... 2>/dev/null | rg -n 'github\.com/docker/docker' || true

echo
echo "=== docker/docker required only for test builds? ==="
go list -deps -test ./... 2>/dev/null | rg -n 'github\.com/docker/docker' || true

echo
echo "=== go mod why ==="
go mod why -m github.com/docker/docker || true

Repository: compliance-framework/plugin-template

Length of output: 568


Transitive github.com/docker/docker vulns are mainly relevant to Docker-backed integration tests/CI; update transitive deps.

go.mod pins github.com/docker/docker v28.5.2+incompatible // indirect (line 18). go mod why shows it’s pulled in via github.com/testcontainers/testcontainers-go used by github.com/compliance-framework/api integration tests (api/sdk.test) and dependency graph from api/sdk/agent/runner, not via direct imports in this repo.

Mapped HIGH advisories for this dependency:

Action: bump github.com/testcontainers/testcontainers-go (and run go mod tidy) so the resulting Docker/Moby (github.com/docker/docker) version is updated to a patched release; ensure CI runs only trusted images/containers when exercising these Docker API flows.

🧰 Tools
🪛 OSV Scanner (2.3.8)

[HIGH] 18-18: github.com/docker/docker 28.5.2+incompatible: Moby has an Off-by-one error in its plugin privilege validation in github.com/docker/docker

(GO-2026-4883)


[HIGH] 18-18: github.com/docker/docker 28.5.2+incompatible: Moby has AuthZ plugin bypass when provided oversized request bodies in github.com/docker/docker

(GO-2026-4887)


[HIGH] 18-18: github.com/docker/docker 28.5.2+incompatible: Moby has an Off-by-one error in its plugin privilege validation

(GHSA-pxq6-2prw-chj9)


[HIGH] 18-18: github.com/docker/docker 28.5.2+incompatible: Docker: Race condition in docker cp allows bind mount redirection to host path

(GHSA-rg2x-37c3-w2rh)


[HIGH] 18-18: github.com/docker/docker 28.5.2+incompatible: Docker: Race condition in docker cp allows creation of arbitrary empty files on the host via symlink swap

(GHSA-vp62-88p7-qqf5)


[HIGH] 18-18: github.com/docker/docker 28.5.2+incompatible: Moby has AuthZ plugin bypass when provided oversized request bodies

(GHSA-x744-4wpc-v9h2)


[HIGH] 18-18: github.com/docker/docker 28.5.2+incompatible: Docker: PUT /containers/{id}/archive executes container binary on the host

(GHSA-x86f-5xw2-fm2r)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@go.mod` at line 18, Update the transitive Docker dependency by bumping the
testcontainers library: in go.mod replace or update the
github.com/testcontainers/testcontainers-go version to a newer release that
pulls Moby/docker >= 29.3.1 (so github.com/docker/docker transitive
vulnerabilities are patched), then run go mod tidy to refresh the module graph
and vendor (if used); verify via `go list -m all` or `go mod graph` that
github.com/docker/docker now resolves to a patched version and CI uses trusted
images for Docker-backed tests.

github.com/fatih/color v1.18.0 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect
github.com/lestrrat-go/blackmagic v1.0.4 // indirect
github.com/lestrrat-go/dsig v1.0.0 // indirect
github.com/lestrrat-go/dsig-secp256k1 v1.0.0 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc/v3 v3.0.4 // indirect
github.com/lestrrat-go/jwx/v3 v3.0.13 // indirect
github.com/lestrrat-go/option/v2 v2.0.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/open-policy-agent/opa v1.2.0 // indirect
github.com/prometheus/client_golang v1.21.1 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.63.0 // indirect
github.com/prometheus/procfs v0.16.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/tchap/go-patricia/v2 v2.3.2 // indirect
github.com/oklog/run v1.2.0 // indirect
github.com/open-policy-agent/opa v1.14.1 // indirect
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect
github.com/segmentio/asm v1.2.1 // indirect
github.com/sirupsen/logrus v1.9.4 // indirect
github.com/tchap/go-patricia/v2 v2.3.3 // indirect
github.com/valyala/fastjson v1.6.10 // indirect
github.com/vektah/gqlparser/v2 v2.5.32 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/yashtewari/glob-intersection v0.2.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
golang.org/x/net v0.37.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect
google.golang.org/grpc v1.71.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
go.opentelemetry.io/otel/metric v1.42.0 // indirect
go.opentelemetry.io/otel/trace v1.42.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.1 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.49.0 // indirect
golang.org/x/net v0.52.0 // indirect
golang.org/x/sync v0.20.0 // indirect
golang.org/x/sys v0.42.0 // indirect
golang.org/x/text v0.35.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
google.golang.org/grpc v1.79.3 // indirect
google.golang.org/protobuf v1.36.11 // indirect
sigs.k8s.io/yaml v1.6.0 // indirect
)
Loading
Loading