fix(full-image): make tsunami-linter usable under a non-root container user

Author: coygeekCreated Aug 9, 2026Updated Aug 9, 2026

Summary

The full image exposes /usr/bin/tsunami-linter, but that path is a symbolic link into /root/go/bin. Because /root is mode 0700, the globally named command cannot be resolved or executed when the container is run with a non-root user.

Target repository: google/tsunami-security-scanner.

Steps to reproduce

Use the currently published amd64 image by digest:

bash
image='ghcr.io/google/tsunami-scanner-full@sha256:26973ab2614c7e7280d3b757aa24faf63b20b1a871832b54d75df8f5064b32e2'

# The installed entry point starts as root.
docker run --rm --platform linux/amd64 "$image" \
  bash -lc 'command -v tsunami-linter; tsunami-linter --help; printf "status=%s\n" "$?"'

# The same global entry point is inaccessible to a non-root user.
docker run --rm --platform linux/amd64 --user 65534:65534 "$image" \
  bash -lc '
    id
    command -v tsunami-linter
    printf "lookup_status=%s\n" "$?"
    /usr/bin/tsunami-linter
    printf "run_status=%s\n" "$?"
  '

Expected behavior

An executable deliberately exposed at /usr/bin/tsunami-linter should be invokable when the container runs with a non-root user, just like the image's other global wrapper commands.

A direct closure check is to run the second command under --user 65534:65534 and confirm that:

  1. command -v tsunami-linter succeeds.
  2. The linter process starts without Permission denied.

Actual behavior

The command is present and starts with the image's default root user:

/usr/bin/tsunami-linter
status=0

With UID/GID 65534, shell lookup fails and direct execution returns status 126:

uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
lookup_status=1
bash: line 1: /usr/bin/tsunami-linter: Permission denied
run_status=126

Affected area

  • The linter installation step in full.Dockerfile.
  • Non-root use of the published ghcr.io/google/tsunami-scanner-full image.

Runtime or environment

  • Image: ghcr.io/google/tsunami-scanner-full@sha256:26973ab2614c7e7280d3b757aa24faf63b20b1a871832b54d75df8f5064b32e2
  • OCI source revision: 363ba87b3543f8ae8e4304d3416818f03da7f262
  • OCI version: nightly
  • Image platform: linux/amd64
  • Host: Docker Desktop on macOS arm64, using Docker's linux/amd64 platform support
  • Reproducing user: UID/GID 65534:65534 (nobody:nogroup in the image)

Evidence

The current full.Dockerfile installs the linter with Go's root-default install path and then creates this global link:

/usr/bin/tsunami-linter -> /root/go/bin/linter

The relevant runtime permissions are:

drwx------ 1 root root    4096 /root
drwxr-xr-x 4 root root    4096 /root/go
drwxr-xr-x 2 root root    4096 /root/go/bin
-rwxr-xr-x 1 root root 8233436 /root/go/bin/linter
lrwxrwxrwx 1 root root      19 /usr/bin/tsunami-linter -> /root/go/bin/linter

Although the binary and link are executable, a non-root process cannot traverse /root to reach the link target. The tested image's org.opencontainers.image.revision label exactly matches the cited source revision.

The live open-issue searches for tsunami-linter and /root/go/bin/linter returned no matching report in google/tsunami-security-scanner on 2026-08-08.

Impact

Container platforms and local workflows that enforce a non-root UID cannot use the linter shipped by the full image. The failure is misleading because the public /usr/bin entry point exists, yet normal command lookup treats it as unavailable and direct execution only reports a permissions error.

Source: google/tsunami-security-scanner