Skip to content

Scan reports are unreadable by downstream GitHub Actions steps #85

Open

Description

@ANAMASGARD

Description

Scan reports generated by the action can be unreadable by subsequent GitHub Actions steps, causing SARIF uploads and JSON artifact uploads to fail with EACCES.

We encountered this while investigating failed configuration-scan, image-scan, and autofix workflows. The scanner produced reports, but downstream uploaders could not open them.

This was reproduced with Kubescape CLI v4.0.16 and action revision 6a527186fc87c668469fe8b9333b251ffc4eaed8, which already includes the separate SARIF path fix from #84.

Environment

  • Linux runner with rootful Docker.
  • Non-root host runner executing subsequent workflow steps.
  • Kubescape CLI v4.0.16.
  • SARIF and JSON output formats.

Steps to reproduce locally

Prerequisites: Git, Docker, jq, and internet access. Run these commands as a non-root user with access to a rootful Docker daemon.

  1. Check out the affected action and build its container:
git clone https://github.com/kubescape/github-action.git github-action-report-repro
cd github-action-report-repro
git checkout 6a527186fc87c668469fe8b9333b251ffc4eaed8

docker build \
  --build-arg KUBESCAPE_VERSION=v4.0.16 \
  -t kubescape-action-report-repro .
  1. Create a manifest fixture. This is scanned only; do not deploy it:
repro_dir=$(mktemp -d)
mkdir -p "$repro_dir/k"

cat > "$repro_dir/k/pod.yaml" <<'YAML'
apiVersion: v1
kind: Pod
metadata:
  name: privileged-report-repro
spec:
  containers:
    - name: app
      image: nginx:alpine
      securityContext:
        privileged: true
YAML
  1. Run a scan that produces reports and fails the High severity threshold:
scan_status=0

docker run --rm \
  -v "$repro_dir:/github/workspace" \
  -w /github/workspace \
  -e GITHUB_ACTIONS=true \
  -e GITHUB_WORKSPACE=/github/workspace \
  -e INPUT_CONTROLS=C-0057 \
  -e INPUT_FILES=. \
  -e INPUT_FORMAT=sarif,json \
  -e INPUT_OUTPUTFILE=results \
  -e INPUT_SEVERITYTHRESHOLD=high \
  -e INPUT_FIXFILES=false \
  kubescape-action-report-repro || scan_status=$?

printf 'Scanner exit status: %s\n' "$scan_status"
  1. Inspect the reports and try reading them as the same non-root host user:
stat -c '%a %u:%g %n' \
  "$repro_dir/results.sarif" \
  "$repro_dir/results.json"

jq -e . "$repro_dir/results.sarif"
jq -e . "$repro_dir/results.json"

Observed: the reports are owned by container root with mode 0600, and the non-root reader receives permission errors.

Rootless Docker/Podman uses different UID mappings, so it requires an appropriately mapped producer/consumer test rather than assuming identical host ownership.

Expected behavior

  • The runner can read the requested reports without making them world-readable.
  • Newly created nested output directories remain accessible to that runner.
  • A threshold failure still returns the scanner's original nonzero exit status.
  • Valid SARIF produced before a threshold failure is still normalized.
  • Finalization errors fail an otherwise successful action.

Actual behavior and root cause

The composite action starts Docker without --user, so the container runs as root. CLI v4.0.16 intentionally writes reports with owner-only permissions because reports may contain sensitive data.

Two entrypoint behaviors compound the problem:

  1. set -e exits immediately after a scanner threshold failure, skipping SARIF finalization.
  2. After successful scans, the predictable SARIF temporary-file replacement can change 0600 to 0644 under umask 0022. JSON remains 0600. Nested root-owned 0750 directories can also prevent traversal.

Typical downstream failures include:

EACCES: permission denied, open 'results.sarif'
EACCES: permission denied, open 'results.json'

These errors indicate unreadable files, not necessarily malformed SARIF.

Real-world impact

Scans can detect findings successfully while their reports cannot be uploaded to GitHub Code Scanning, archived as artifacts, or consumed by later review tooling.

Making reports world-readable would undermine the CLI's intentional confidentiality protection.

Proposed resolution

  • Run the container using the invoking runner's UID/GID.
  • Provide a writable, ephemeral container HOME/cache location.
  • Preserve owner-only report permissions and accessible nested directories.
  • Finalize available SARIF after scanner failure, then return the original scanner status.
  • Use unique, private temporary files with cleanup on failure.
  • Detect missing, malformed, or empty SARIF and propagate finalization errors.
  • Preserve autofix behavior and avoid recursive workspace ownership/permission changes.

Verification

The candidate correction has passing local regression and real-CLI coverage, including threshold failures, restrictive umasks, nested paths, arbitrary numeric UIDs, and actual manifest autofix.

Hosted configuration and image scans using the candidate action both completed successful SARIF uploads:

Hosted JSON artifact-upload validation remains outstanding.

This issue is independent of #83/#84 and the separate CodeQL uploader-version update.

Activity

  1. moved this to Accepted in Kubescapingon Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions