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
14 changes: 12 additions & 2 deletions docs/areas/hosting.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,16 @@ registry never delays or prevents startup.
- The process runs as UID `64000` in the root group (GID `0`), never as UID `0`. `/app` is owned by `64000:0` with
group permissions equal to owner permissions, so the application also works when started with another UID in
group `0`. Membership in group `0` keeps a `root:root` Docker socket readable where the socket grants group access.
- The Trivy CLI is bundled at `/usr/local/bin/trivy` (taken from `aquasec/trivy:0.58.1` by default) with its cache in
`/tmp/trivy`, so Trivy client mode works without extra installation (see [Vulnerabilities](vulnerabilities.md)).
- The Trivy CLI is bundled at `/usr/local/bin/trivy` (taken from the digest-pinned `aquasec/trivy` image of v0.76.1,
by default) with its cache in `/tmp/trivy`, so Trivy client mode works without extra installation (see
[Vulnerabilities](vulnerabilities.md)). The deployment tiers of the documented compose files run the Trivy server
of the same version.
- The image sets `TRIVY_SKIP_VERSION_CHECK=true` and `TRIVY_DISABLE_TELEMETRY=true`, so Trivy sends no update check
or usage data to `check.trivy.dev` and contacts only the Trivy server, the Docker Engine at `/var/run/docker.sock`
when it is mounted there, and the registries, including Trivy's Java DB repository when an image contains Java
archives. Setting either to `false` brings the request back, and a Trivy run
outside the image needs both set by the operator
([0016](../decisions/0016-the-bundled-trivy-skips-its-update-check-and-telemetry.md)).
- The image sets `DockerUpdateGuard__DisplayVersion` to the version it was built with.
- CA certificates are installed so outbound TLS connections can be verified.
- Before the application starts, the entrypoint:
Expand Down Expand Up @@ -218,6 +226,8 @@ These properties hold today and must be provided for by the deployment:
through a private directory appended to `SSL_CERT_DIR`, so no write access to the system trust store is needed.
- [0012](../decisions/0012-configured-urls-are-rejected-when-an-at-sign-is-not-their-user-info-separator.md):
configured URLs are rejected when an `@` is not their user-info separator.
- [0016](../decisions/0016-the-bundled-trivy-skips-its-update-check-and-telemetry.md): the bundled Trivy skips its
update check and telemetry through the image's environment.

## Not here

Expand Down
6 changes: 6 additions & 0 deletions docs/areas/vulnerabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ scan run:
process environment, added to the environment inherited from the application (an inherited `TRIVY_SERVER` is
replaced), so it does not stand on the command line, where every user who can see the process could read the user
info.
- Besides the Trivy server, the Trivy process contacts only the Docker Engine at `/var/run/docker.sock` (Trivy reads
the image from it first when the socket is mounted there) and the registries, including Trivy's Java DB repository
when an image contains Java archives; the container image switches off Trivy's update check and telemetry
([Hosting](hosting.md#container-image)).
- The target is `<repository>:<tag>` for `docker.io` images and `<registry>/<repository>:<tag>` otherwise, followed by
`@<digest>` when the digest is known.
- The process gets `RequestTimeoutSeconds` plus 10 seconds. When that passes, the process and its children are killed
Expand Down Expand Up @@ -196,6 +200,8 @@ The dashboard shows at most one hint about the vulnerability configuration:
environment.
- [0015](../decisions/0015-the-trivy-scan-target-follows-an-end-of-options-marker.md): the Trivy scan target follows
an end-of-options marker (`--`).
- [0016](../decisions/0016-the-bundled-trivy-skips-its-update-check-and-telemetry.md): the bundled Trivy skips its
update check and telemetry through the image's environment.

## Not here

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ added to the environment it inherits from the application, and no `--server` arg
environment by the application's own user and by root, as the configuration it comes from already is. Trivy still
repeats it in its error output, so the withholding above stays.
- A Trivy executable that does not read `TRIVY_SERVER` (a custom `TrivyExecutablePath`) would scan without a server,
downloading the vulnerability database itself; the bundled Trivy v0.58.1 reads it. A token setting of our own is
downloading the vulnerability database itself; the bundled Trivy v0.76.1 reads it. A token setting of our own is
not added: `TRIVY_TOKEN` in the application's environment reaches Trivy already.
- The Trivy process inherits the application's whole environment, other secrets supplied as environment variables
included. It is not reduced to an allow-list: the process runs as the application's user, which can read the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ ever read as a Trivy option. The argument list is described in [Vulnerabilities]

- A registered reference that begins with `-` is scanned as an image name; when Trivy cannot pull it, its scan ends
with a non-zero exit code and is reported like any other image Trivy cannot find.
- The protection rests on Trivy honoring `--`. It was measured on Trivy v0.76.1: without `--`, `--config=x.y/z:latest`
is read as the configuration file option; after `--`, `--config=…`, `--input=…` and `-a/b` targets are taken as image
names and fail, and a normal target scans as before. The bundled v0.58.1 could not be measured (its release archive
is no longer published); moving the bundled version to a measured one is tracked as a follow-up, and any later Trivy
update is measured again with the same cases.
- The protection rests on Trivy honoring `--`. It was measured on Trivy v0.76.1, the version the image bundles
(pinned by digest, the digest of the v0.76.1 image index, so the build copies the measured binary): without
`--`, `--config=x.y/z:latest` is read as the configuration file option; after `--`, `--config=…`, `--input=…` and `-a/b` targets are taken as image names
and fail without opening the file they name, and a normal target takes the normal scan path. Any later Trivy update
is measured again with the same cases.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# 0016: The bundled Trivy skips its update check and telemetry

- **Status:** Accepted
- **Date:** 2026-10-29
- **Area:** Hosting and configuration
- **Source:** Issue #372
- **Supersedes:** β€”

## Context

The image bundles the Trivy CLI, which the Trivy provider starts for every scan in client mode against the operator's
Trivy server ([Vulnerabilities](../areas/vulnerabilities.md#trivy)). Trivy v0.76.1, the version issue #372 bundles,
sends on every `trivy image` run a background request to `https://check.trivy.dev/updates` with a stable host
identifier (a SHA-256 of the host name and the first MAC address), the command, the flag names, the OS and the
architecture. `--quiet`, which the provider passes, only hides the printed notice; the request stops only when both
the version check and telemetry are switched off. v0.58.1, the version bundled before, makes no such call. A
deployment with restricted egress would gain an outbound destination it never allowed, and every scan would report
a host fingerprint to a third party, without anything in DockerUpdateGuard asking for it.

## Options considered

1. **Set `TRIVY_SKIP_VERSION_CHECK=true` and `TRIVY_DISABLE_TELEMETRY=true` in the image's environment** β€” no code
change; every Trivy the application starts inside the image inherits them, a custom `TrivyExecutablePath`
included, and an older Trivy ignores environment variables it does not know. Outside the image the operator
sets them. Chosen.
2. **Add `--skip-version-check --disable-telemetry` to the provider's argument list** β€” also covers a Trivy run
outside the image, but changes production code, its tests and the argument list of
[0015](0015-the-trivy-scan-target-follows-an-end-of-options-marker.md), and an older custom Trivy without these
flags fails every scan with `unknown flag`.
3. **Leave it to the operator** (document the call, block it by network policy) β€” every default deployment would
send the fingerprint until someone notices.

## Decision

The container image sets `TRIVY_SKIP_VERSION_CHECK=true` and `TRIVY_DISABLE_TELEMETRY=true`, so the bundled Trivy
sends nothing to `check.trivy.dev`; the provider's arguments stay unchanged. The behavior is
described in [Hosting](../areas/hosting.md#container-image).

## Consequences

- An operator who sets either variable to `false` in the container gets Trivy's update notice request back; that is
the operator's choice.
- A Trivy started outside the image (the application run without the container) gets the suppression only from the
operator's environment.
- Measured on the bundled v0.76.1 with a control run (issue #372); a later Trivy update is measured again, since a
new release may add another outbound call or rename the variables.
1 change: 1 addition & 0 deletions docs/decisions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,5 @@ once in the [area document](../areas/README.md) of the record's area, and the re
| [0013](0013-docker-instance-keys-are-named-relative-to-the-instance.md) | Validation messages name Docker instance keys relative to the instance | Accepted | 2026-10-27 |
| [0014](0014-registry-tag-names-and-digests-are-validated-where-they-are-read.md) | Remote tag names, digests, image references and names are validated or bounded where they are read | Accepted | 2026-10-28 |
| [0015](0015-the-trivy-scan-target-follows-an-end-of-options-marker.md) | The Trivy scan target follows an end-of-options marker | Accepted | 2026-10-29 |
| [0016](0016-the-bundled-trivy-skips-its-update-check-and-telemetry.md) | The bundled Trivy skips its update check and telemetry | Accepted | 2026-10-29 |
<!-- project:end index -->
2 changes: 1 addition & 1 deletion docs/docker-compose.full.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ services:
retries: 5

trivy:
image: aquasec/trivy:0.58.1
image: aquasec/trivy:0.76.1
container_name: dockerupdateguard-trivy
restart: unless-stopped
command: ["server", "--listen", "0.0.0.0:4954"]
Expand Down
2 changes: 1 addition & 1 deletion docs/docker-compose.trivy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ services:
retries: 5

trivy:
image: aquasec/trivy:0.58.1
image: aquasec/trivy:0.76.1
container_name: dockerupdateguard-trivy
restart: unless-stopped
command: ["server", "--listen", "0.0.0.0:4954"]
Expand Down
7 changes: 6 additions & 1 deletion src/DockerUpdateGuard/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
ARG BASE_SDK="mcr.microsoft.com/dotnet/sdk:10.0-alpine"
ARG BASE_RUNTIME="mcr.microsoft.com/dotnet/aspnet:10.0-alpine"
ARG BASE_RUNTIME_DIGEST
ARG TRIVY_IMAGE="aquasec/trivy:0.58.1"
# Trivy v0.76.1 (digest of the multi-arch image index)
ARG TRIVY_IMAGE="aquasec/trivy@sha256:790fd66d1697395d8693d1acaa1ea702406a20f109b6fc7bac8db623eca6c06c"
ARG APP_VERSION=1.0.0

# ---------------------------
Expand Down Expand Up @@ -56,6 +57,10 @@ RUN apk add --no-cache ca-certificates
# The cache directory lives under /tmp so any runtime UID can write it.
COPY --from=trivy /usr/local/bin/trivy /usr/local/bin/trivy
ENV TRIVY_CACHE_DIR=/tmp/trivy
# Trivy's update check and telemetry would send a host identifier to check.trivy.dev on every scan;
# both are off so Trivy sends nothing to check.trivy.dev.
ENV TRIVY_SKIP_VERSION_CHECK=true
ENV TRIVY_DISABLE_TELEMETRY=true

COPY --from=build /app/publish .

Expand Down
Loading