Scanning Container Images via Checkmarx One CLI - Flag Validation and Best Practices
Overview
The --container-images flag accepts a comma-separated list of container image references. Each reference can be:
An image name with tag:
<image-name>:<image-tag>A tar file path:
<filename>.tarA prefixed reference using supported providers
Related Documentation: See Syft Supported Sources for more information about the underlying scanning engine capabilities.
Supported Image Formats
1. Standard Image References (with tags)
Format:
<image-name>:<tag>or<registry>/<namespace>/<image>:<tag>Examples:
alpine:latest nginx:1.21 docker.io/library/ubuntu:22.04
2. Tar Files (Docker/Podman saved images)
Format:
<filename>.tarorfile:<path/to/file>.tarExamples:
my-image.tar file:./images/nginx.tar docker-archive:path/to/image.tarNote: Images with 0 packages are automatically skipped and excluded from scan results.
3. OCI Directory Format (Skopeo/Buildah-created images)
Format:
oci-dir:<path/to/oci/directory>(tag is read fromindex.json)Examples:
oci-dir:docker.io/library/alpine oci-dir:/absolute/path/to/oci-image oci-dir:./my-alpine-imageImportant: Tags are automatically extracted from the
index.jsonfile, not from the command lineRequirements:
Directory must contain valid OCI layout (
oci-layout,index.json,blobs/)index.jsonmust includeorg.opencontainers.image.ref.nameannotation for tag extractionImage name is extracted from the last directory segment
4. Daemon References
Format:
<daemon>:<image-name>:<tag>Supported:
docker:,podman:,containerd:,registry:Examples:
docker:nginx:latest podman:alpine:3.18 registry:myregistry.io/myimage:v1.0
5. Archive Formats
Formats:
docker-archive:,oci-archive:,file:Examples:
docker-archive:./images/myimage.tar oci-archive:/path/to/image.tar
Supported Prefixes
Prefix | Purpose | Expected Format | Example |
|---|---|---|---|
| Pull from Docker daemon |
|
|
| Pull from Podman daemon |
|
|
| Pull from containerd daemon |
|
|
| Pull from registry |
|
|
| Load from Docker tar archive |
|
|
| Load from OCI tar archive |
|
|
| Load from OCI directory layout |
|
|
| Load from file |
|
|
Image Name and Tag Extraction Rules
Input Format | Image Name | Image Tag | Example |
|---|---|---|---|
Standard registry | Last part before | After |
|
OCI directory | Last directory segment | From |
|
OCI archive | From filename (before first | From |
|
Tar file | From internal | From | Extracted from tar contents |
Using Skopeo with Checkmarx CLI - Best Practices
What is Skopeo?
Skopeo is a command-line utility for working with container images without requiring a container runtime. Perfect for CI/CD environments where Docker/Podman daemons are not available.
Installation
# macOS brew install skopeo # Ubuntu/Debian sudo apt-get install skopeo # Red Hat/CentOS/Fedora sudo dnf install skopeo
Best Practice: OCI Directory Format
Recommended approach: Save images in OCI directory format with proper annotations.
Step 1: Create OCI Directory
# Create structured directory mkdir -p docker.io/library # Copy image with tag annotation - IMPORTANT: include :tag in destination skopeo copy --override-os linux --override-arch amd64 \ docker://alpine:latest oci:docker.io/library/alpine:3.19
Critical: Always include the tag (:latest, :3.19) in the Skopeo destination path to ensure proper annotation in index.json. Without it, the CLI won't be able to determine the image tag.
Step 2: Verify Tag Annotation
cat docker.io/library/alpine/index.json | python3 -m json.tool
Expected output should include:
"annotations": {
"org.opencontainers.image.ref.name": "3.19"
}If this annotation is missing, the image will be skipped during scanning.
Step 3: Scan with CxOne CLI
cx scan create \ --project-name my-project \ -s ./source \ --branch main \ --scan-types container-security \ --container-images "oci-dir:docker.io/library/alpine" \ --containers-local-resolution
Note: Do NOT add the tag :3.19 to the --container-images value. The tag is automatically read from index.json.
Common Scenarios
Scenario 1: Private Registry with Authentication
# Save image with authentication skopeo copy --src-creds username:password \ --override-os linux --override-arch amd64 \ docker://private-registry.com/myapp:v1.0 \ oci:private-registry.com/myapp:v1.0 # Scan (no tag needed in CLI command) cx scan create --project-name myapp \ -s . --scan-types container-security \ --container-images "oci-dir:private-registry.com/myapp" \ --containers-local-resolution
Scenario 2: Multiple Images
# Save multiple images with tags skopeo copy docker://nginx:1.21 oci:docker.io/library/nginx:1.21 skopeo copy docker://postgres:14 oci:docker.io/library/postgres:14 # Scan all (no tags in CLI command) cx scan create --project-name my-app \ -s ./source --scan-types container-security \ --container-images "oci-dir:docker.io/library/nginx,oci-dir:docker.io/library/postgres" \ --containers-local-resolution
Scenario 3: Multi-Architecture Images
# Save different architectures with tags skopeo copy --override-arch amd64 \ docker://alpine:latest oci:images/alpine-amd64:latest skopeo copy --override-arch arm64 \ docker://alpine:latest oci:images/alpine-arm64:latest # Scan both architectures (no tags in CLI command) cx scan create --project-name multi-arch \ -s . --scan-types container-security \ --container-images "oci-dir:images/alpine-amd64,oci-dir:images/alpine-arm64" \ --containers-local-resolution
Troubleshooting
Error: "no image tag found in OCI index.json annotations"
Cause: OCI directory created without tag annotation in the destination path.
Solution:
# Wrong - no tag in destination skopeo copy docker://alpine:latest oci:my-alpine-image # Correct - tag included in destination skopeo copy docker://alpine:latest oci:my-alpine-image:latest
The tag must be specified in the Skopeo copy command's destination (after oci:), not in the CLI scan command.
Warning: "Image has 0 packages, skipping"
Cause: Image contains no analyzable packages or is corrupted/empty.
Solution: 1. Verify image integrity: skopeo inspect oci:path/to/image 2. Re-pull and save the image 3. Check if base image actually contains packages (e.g., scratch images have none)
Error: "path does not exist"
Cause: OCI directory path is incorrect or not accessible.
Solution: - Use absolute paths: oci-dir:/absolute/path/to/image - Or ensure relative paths are correct from the CLI execution directory
Using Buildah with Checkmarx CLI - Best Practices
What is Buildah?
Buildah is a tool that facilitates building OCI and Docker container images without requiring a container daemon. Like Skopeo, it's ideal for CI/CD environments and follows the same daemonless architecture. Buildah can both build images from scratch/Dockerfiles AND export them in various formats that are fully compatible with Checkmarx CLI.
Installation (MacOS)
Buildah is Linux-only and does not have native macOS support.
Use Podman (which includes a Linux VM) [option1]
or run Buildah in a container [option2]
or run a containers and install Buildah [option3]
# brew install podman # After installation, you must start the Podman machine podman machine init podman machine startx (Ubuntu/Debian) sudo apt-get update sudo apt-get install -y buildah # Linux (Red Hat/CentOS/Fedora) sudo dnf install -y buildah # macOS - Buildah is not natively supported # Option 1: Use Podman (includes Buildah-compatible functionality) brew install podman podman machine init --rootful podman machine start # Option 2: Run Buildah in a container with volume mount podman run --rm -it --privileged -v $(pwd):/output quay.io/buildah/stable # Option 3: Use Fedora (Docker or Podman installed and running on your macOS) # Since Buildah requires a Linux kernel, run a privileged Fedora container # on the macOS host to act as your test environment. # Using Docker (or swap 'docker' for 'podman' if preferred) docker run --rm -it --privileged -v $(pwd):/mnt/output fedora:latest bash # 1. Install Buildah and standard tools (now that we are inside the Fedora container) dnf -y install buildah curl # 2. Install Syft (using standard installation script for quick setup) curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin # Verify installation buildah version # Linux podman --version # macOS syft --version
Best Practice: OCI Directory Format
Recommended approach: Build and save images in OCI directory format with proper tag annotations.
Step 1: Build Image with Buildah
# Option 1: Build from Dockerfile buildah bud -t myapp:v1.0 . # Option 2: Build from scratch (no Dockerfile) buildah from scratch buildah copy working-container /etc/os-release / buildah commit working-container myapp:v1.0 # Option 3: Build from an existing image # Create a working container from a specific, full image name - in this case, traefik:v2 new_container=$(buildah from docker.io/library/traefik:v2) # You can now run commands, add files, or set config buildah run $new_container -- touch /newfile.txt buildah config --author "Your Name" $new_container # Commit your changes to a new image buildah commit $new_container myapp:v1.0
Step 2: Save to OCI Directory or Archive
# Option A: Push to OCI directory # IMPORTANT: include :tag in destination buildah push localhost/myapp:v1.0 oci:/output/docker.io/library/myapp:v1.0 # Option B: Save to docker-archive tar (includes tag in tar metadata) # IMPORTANT: include both imagename and tag in destination # in this case: myapp.tar:testapp:v1.0 -> file-name=myapp.tar, image-name=testapp, image-tag=v1.0) buildah push localhost/myapp:v1.0 docker-archive:/output/myapp.tar:testapp:v1.0 # Option C: Save to oci-archive tar # IMPORTANT: include :tag in destination # in this case: myapp.tar:v1.0 -> image-name=myapp, image-tag=v1.0 buildah push localhost/myapp:v1.0 oci-archive:/output/myapp.tar:v1.0
Critical: Always include the tag (:v1.0, :latest) in the Buildah destination path to ensure proper annotation in index.json (for OCI formats) or tar metadata (for docker-archive). This is identical to Skopeo's requirement.
Step 3: Verify Tag Annotation (OCI Directory)
# Check that tag annotation exists cat /output/docker.io/library/myapp/index.json | grep -A2 "annotations" # Or use jq for formatted output cat /output/docker.io/library/myapp/index.json | jq '.manifests[].annotations'
Expected output:
{
"org.opencontainers.image.ref.name": "v1.0"
}Step 4: Scan with CxOne CLI
# For OCI directory (Step 2 -> Option A) cx scan create \ --project-name myapp \ -s ./source \ --branch main \ --scan-types container-security \ --container-images "oci-dir:/output/docker.io/library/myapp" \ --containers-local-resolution # For docker-archive (Step 2 -> Option B) cx scan create \ --project-name myapp \ -s ./source \ --branch main \ --scan-types container-security \ --container-images "docker-archive:/output/myapp.tar" # For oci-archive (Step 2 -> Option C) cx scan create \ --project-name myapp \ -s ./source \ --branch main \ --scan-types container-security \ --container-images "oci-archive:/output/myapp.tar"
Note: For OCI directory, the tag is NOT specified in the CLI command - it's automatically read from index.json.
Common Scenarios
Scenario 1: Multi-Stage Dockerfile Build
# Build multi-stage Dockerfile buildah bud -t frontend:v2.0 -f Dockerfile.frontend . # Save to OCI directory with tag buildah push frontend:v2.0 oci:builds/frontend:v2.0 # Scan cx scan create --project-name frontend \ -s . --scan-types container-security \ --container-images "oci-dir:builds/frontend" \ --containers-local-resolution
Scenario 2: Multiple Images from Same Build Context
# Build multiple images with different tags buildah bud -t myapp:latest . buildah bud -t myapp:v1.0 . buildah bud -t myapp:stable . # Save all with tags buildah push myapp:latest oci:images/myapp:latest buildah push myapp:v1.0 oci:images/myapp-v1:v1.0 buildah push myapp:stable oci:images/myapp-stable:stable # Scan all versions cx scan create --project-name myapp \ -s . --scan-types container-security \ --container-images "oci-dir:images/myapp,oci-dir:images/myapp-v1,oci-dir:images/myapp-stable" \ --containers-local-resolution
Scenario 3: Private Registry Integration
# Pull from private registry, modify, and save for scanning buildah pull --creds username:password private-registry.com/baseimage:v1.0 buildah bud -t myapp:v2.0 --from private-registry.com/baseimage:v1.0 . # Save to OCI directory buildah push myapp:v2.0 oci:registry-mirror/myapp:v2.0 # Scan cx scan create --project-name myapp \ -s . --scan-types container-security \ --container-images "oci-dir:registry-mirror/myapp" \ --containers-local-resolution
Scenario 4: Multi-Architecture Builds
# Build for different architectures buildah bud --arch amd64 -t myapp:v1.0-amd64 . buildah bud --arch arm64 -t myapp:v1.0-arm64 . # Save each architecture buildah push myapp:v1.0-amd64 oci:images/myapp-amd64:v1.0 buildah push myapp:v1.0-arm64 oci:images/myapp-arm64:v1.0 # Scan both architectures cx scan create --project-name myapp \ -s . --scan-types container-security \ --container-images "oci-dir:images/myapp-amd64,oci-dir:images/myapp-arm64" \ --containers-local-resolution
Troubleshooting
Error: "no image tag found in OCI index.json annotations"
Cause: OCI directory created without tag annotation in the destination path.
Solution:
# Wrong - no tag in destination buildah push myapp:v1.0 oci:myapp-dir # Correct - tag included in destination buildah push myapp:v1.0 oci:myapp-dir:v1.0
The tag must be specified in the Buildah push command's destination (after oci:), matching the Skopeo requirement.
Error: "Image has 0 packages, skipping"
Cause: Built image contains no analyzable packages (e.g., scratch-based images with only binaries).
Solution: 1. Verify image was built correctly: buildah images 2. Inspect image contents: buildah inspect myapp:v1.0 3. If using FROM scratch, ensure you're installing packages or using a base image with an OS 4. For minimal images, this is expected behavior - Checkmarx skips images with no packages
Issue: Buildah Image Not Found After Build
Cause: Image exists in Buildah's local storage but not properly tagged.
Solution:
# List all Buildah images buildah images # If image is missing tag, re-tag it buildah tag <image-id> myapp:v1.0 # Then push with proper tag buildah push myapp:v1.0 oci:path/to/dir:v1.0
Permission Issues on Linux
Cause: Buildah requires proper permissions for rootless operation.
Solution:
# Ensure subuid/subgid are configured cat /etc/subuid cat /etc/subgid # Run buildah in rootless mode buildah unshare buildah bud -t myapp:v1.0 .
OCI Directory Tag Extraction Logic
When scanning OCI directories created with Skopeo or Buildah:
Image Name: Extracted from the last directory segment in the path -
oci-dir:docker.io/library/alpine→ Image Name:alpineImage Tag: Extracted from
index.jsonannotation (org.opencontainers.image.ref.name) - Tags are read from the OCI metadata, NOT from the command line - If multiple manifests exist, prefers tags that differ from the image name - Example: If manifests have tags "alpine" and "latest", prefers "latest"Fallback: If no tag annotation found, the image is skipped with a warning
Note: Unlike daemon sources (docker:, podman:), OCI directories do NOT support explicit tag syntax like
oci-dir:path:tag. Tags must be embedded in the OCI directory'sindex.jsonfile.
Examples
Valid Inputs
# Standard image with tag --container-images "nginx:latest" # Multiple images --container-images "nginx:latest,alpine:3.18,ubuntu:22.04" # With spaces (normalized) --container-images "nginx:latest, alpine:3.18, ubuntu:22.04" # With quotes (normalized) --container-images "'nginx:latest', 'alpine:3.18'" # Local tar file --container-images "alpine.tar" # Absolute path tar file --container-images "/path/to/image.tar" # File prefix --container-images "file:alpine.tar" # File prefix with quotes --container-images "file:'/path/to/image.tar'" # Docker daemon --container-images "docker:nginx:latest" # Docker archive --container-images "docker-archive:./saved-image.tar" # OCI archive --container-images "oci-archive:/tmp/oci-image.tar" # OCI directory (tag from index.json) --container-images "oci-dir:docker.io/library/alpine" # OCI directory with relative path --container-images "oci-dir:./my-alpine-image" # OCI directory with absolute path --container-images "oci-dir:/home/user/images/alpine" # Registry --container-images "registry:myregistry.io/myapp:v1.0" # Mixed formats --container-images "nginx:latest,file:alpine.tar,oci-dir:docker.io/library/postgres"
Invalid Inputs
# Missing tag (non-prefixed) --container-images "nginx" # Error: image does not have a tag # Non-existent tar file --container-images "nonexistent.tar" # Error: file 'nonexistent.tar' does not exist # Compressed tar --container-images "image.tar.gz" # Error: file 'image.tar.gz' is compressed, use non-compressed format (tar) # Wrong extension (looks like tar) --container-images "image.tar.bz" # Error: image does not have a tag. Did you try to scan a tar file? # File prefix with image name --container-images "file:nginx:latest" # Error: file 'nginx:latest' does not exist. Did you try to scan an image using image name and tag? # Archive prefix with image name --container-images "docker-archive:nginx:latest" # Error: file 'nginx:latest' does not exist. Did you try to scan an image using image name and tag? # OCI directory without tag annotation in index.json --container-images "oci-dir:path/to/oci-dir" # Warning: no image tag found in OCI index.json annotations (image skipped) # OCI directory with explicit tag (NOT SUPPORTED) --container-images "oci-dir:./my-image:latest" # Will fail: tries to read ./my-image:latest/index.json which doesn't exist # Use "oci-dir:./my-image" instead (tag read from index.json) # Tar file with tag suffix (invalid) --container-images "oci-dir:image.tar:latest" # Error: tar files cannot have tags
Error Messages
Consolidated Error Format
When validation fails, all errors are collected and presented in a single, user-friendly message:
User input error for --container-images flag. Expected format: <image-name>:<image-tag> or <filename>.tar, or use a supported prefix (docker:, podman:, containerd:, registry:, docker-archive:, oci-archive:, oci-dir:, file:) - User input: 'check.tar' error: file 'check.tar' does not exist - User input: 'alpine' error: image does not have a tag - User input: 'test.tar.gz' error: file 'test.tar.gz' is compressed, use non-compressed format (tar)
Error Types with Helpful Hints
Error Type | Error Message | Helpful Hint |
|---|
Error Type | Error Message | Helpful Hint |
|---|---|---|
Missing tag |
| - |
Looks like tar |
|
|
File not found (with colon) |
|
|
Compressed tar |
| - |
File not found |
| - |
OCI missing tag |
| Image skipped with warning |
OCI archive missing tag |
| Image skipped with warning |
OCI explicit tag | Path with | Use path without tag, embed in index.json |