Expected Behavior
.github/workflows/vulnerability-scan.yml scans public.ecr.aws/datadog/lambda-extension:latest daily with both Trivy and Grype (ignore-unfixed / only-fixed, exit-code: 1). I'd expect those to cover bottlecap's own Rust dependencies, so that a vulnerable crate in a released extension fails the scan.
Actual Behavior
Neither scanner can see any of bottlecap's dependencies, so for the Rust surface the daily scan isn't finding nothing — it's looking at nothing. It passes on the base image alone.
The cause is visible in the build rather than the artifact. images/Dockerfile.bottlecap.compile:49 builds with plain cargo build:
cargo +stable build --verbose --locked --no-default-features --features="${FEATURES}" ${BUILD_FLAG}
Without cargo auditable, no dependency metadata is embedded, and the shipped /opt/extensions/datadog-agent has no .dep-v0 section — confirmed with both objdump -h and pyelftools.
Stripping isn't the obstacle. bottlecap is stripped only by [profile.release] strip = true (bottlecap/Cargo.toml:121); the Rust compile path runs no external strip, unlike the legacy Go scripts/Dockerfile.build. For comparison, uv uses the same strip = true and retains its .dep-v0 (9,106 bytes, non-ALLOC), which is why scanners read its dependency tree fine.
This has practical consequences today. Scanning bottlecap/Cargo.lock at v99 — authoritative, since the build passes --locked — surfaces two advisories the image scan cannot:
opentelemetry_sdk 0.31.0 → 0.32.1 (GHSA-w9wp-h8wv-79jx / CVE-2026-48504). This one reaches the shipped build: bottlecap → opentelemetry-proto 0.31.0 → opentelemetry_sdk ^0.31, a non-optional kind=normal dependency. opentelemetry-proto-0.31.0 is evidenced in the released binary.
tar 0.4.45 → 0.4.46 (GHSA-3pv8-6f4r-ffg2), reached only via libddwaf-sys. I could not verify whether this is a build-script dependency, so it may well never be linked.
That ambiguity is itself the argument: Cargo.lock over-reports because it includes build and dev dependencies, while the binary exposes nothing at all. cargo auditable records exactly the crates linked into the release build and resolves it in the right direction.
You already use this in the org — DataDog/saluki pins cargo-auditable 0.7.4 and wraps CI builds with it, commented "so released binaries embed an SBOM (dependency tree)". Applying the same in Dockerfile.bottlecap.compile requires no new published artifact and negligible size cost. An SBOM attestation on the published image would work equally well if that's a better fit — there are currently no referrers or attestations on the image, and it contains only /opt/extensions/datadog-agent and /opt/datadog_wrapper, so consumers embedding it via COPY --from= have nothing to scan.
Steps to Reproduce the Problem
docker create --name ddext public.ecr.aws/datadog/lambda-extension:99 && docker cp ddext:/opt/extensions/datadog-agent .
readelf -S datadog-agent | grep dep-v0 — no output (a cargo auditable build shows .dep-v0)
trivy rootfs datadog-agent and grype datadog-agent — neither detects any package
trivy fs bottlecap/ at v99 — reports the two advisories above from Cargo.lock
Specifications
- Datadog Extension version: 99 (
public.ecr.aws/datadog/lambda-extension:latest; arm64 manifest sha256:92aeb004f9b30eb1f30436ee4eba17c7a492ef77d5d10033df3155cdb37d2ada; binary sha256 d7a9f772a1b8…, 10,137,968 bytes)
- Datadog Lambda Library name and version: n/a — deployed as a container image via
COPY --from=public.ecr.aws/datadog/lambda-extension, not as a Lambda layer
Stacktrace
$ readelf -S datadog-agent | grep dep-v0
(no output)
$ trivy rootfs --scanners vuln datadog-agent
┌────────┬──────┬─────────────────┐
│ Target │ Type │ Vulnerabilities │
├────────┼──────┼─────────────────┤
│ - │ - │ - │
└────────┴──────┴─────────────────┘
$ grype datadog-agent
No vulnerabilities found
$ trivy fs bottlecap/ # same tree, from Cargo.lock
opentelemetry_sdk 0.31.0 → 0.32.1 CVE-2026-48504 MEDIUM
tar 0.4.45 → 0.4.46 GHSA-3pv8-6f4r-ffg2 MEDIUM
Expected Behavior
.github/workflows/vulnerability-scan.ymlscanspublic.ecr.aws/datadog/lambda-extension:latestdaily with both Trivy and Grype (ignore-unfixed/only-fixed,exit-code: 1). I'd expect those to cover bottlecap's own Rust dependencies, so that a vulnerable crate in a released extension fails the scan.Actual Behavior
Neither scanner can see any of bottlecap's dependencies, so for the Rust surface the daily scan isn't finding nothing — it's looking at nothing. It passes on the base image alone.
The cause is visible in the build rather than the artifact.
images/Dockerfile.bottlecap.compile:49builds with plaincargo build:Without
cargo auditable, no dependency metadata is embedded, and the shipped/opt/extensions/datadog-agenthas no.dep-v0section — confirmed with bothobjdump -hand pyelftools.Stripping isn't the obstacle. bottlecap is stripped only by
[profile.release] strip = true(bottlecap/Cargo.toml:121); the Rust compile path runs no externalstrip, unlike the legacy Goscripts/Dockerfile.build. For comparison,uvuses the samestrip = trueand retains its.dep-v0(9,106 bytes, non-ALLOC), which is why scanners read its dependency tree fine.This has practical consequences today. Scanning
bottlecap/Cargo.lockatv99— authoritative, since the build passes--locked— surfaces two advisories the image scan cannot:opentelemetry_sdk0.31.0 → 0.32.1 (GHSA-w9wp-h8wv-79jx / CVE-2026-48504). This one reaches the shipped build:bottlecap→opentelemetry-proto0.31.0 →opentelemetry_sdk ^0.31, a non-optionalkind=normaldependency.opentelemetry-proto-0.31.0is evidenced in the released binary.tar0.4.45 → 0.4.46 (GHSA-3pv8-6f4r-ffg2), reached only vialibddwaf-sys. I could not verify whether this is a build-script dependency, so it may well never be linked.That ambiguity is itself the argument:
Cargo.lockover-reports because it includes build and dev dependencies, while the binary exposes nothing at all.cargo auditablerecords exactly the crates linked into the release build and resolves it in the right direction.You already use this in the org —
DataDog/salukipinscargo-auditable 0.7.4and wraps CI builds with it, commented "so released binaries embed an SBOM (dependency tree)". Applying the same inDockerfile.bottlecap.compilerequires no new published artifact and negligible size cost. An SBOM attestation on the published image would work equally well if that's a better fit — there are currently no referrers or attestations on the image, and it contains only/opt/extensions/datadog-agentand/opt/datadog_wrapper, so consumers embedding it viaCOPY --from=have nothing to scan.Steps to Reproduce the Problem
docker create --name ddext public.ecr.aws/datadog/lambda-extension:99 && docker cp ddext:/opt/extensions/datadog-agent .readelf -S datadog-agent | grep dep-v0— no output (acargo auditablebuild shows.dep-v0)trivy rootfs datadog-agentandgrype datadog-agent— neither detects any packagetrivy fs bottlecap/atv99— reports the two advisories above fromCargo.lockSpecifications
public.ecr.aws/datadog/lambda-extension:latest; arm64 manifestsha256:92aeb004f9b30eb1f30436ee4eba17c7a492ef77d5d10033df3155cdb37d2ada; binary sha256d7a9f772a1b8…, 10,137,968 bytes)COPY --from=public.ecr.aws/datadog/lambda-extension, not as a Lambda layerStacktrace