diff --git a/.github/workflows/pr-lambda.yml b/.github/workflows/pr-lambda.yml index a0c826e16567..b85aa4788432 100644 --- a/.github/workflows/pr-lambda.yml +++ b/.github/workflows/pr-lambda.yml @@ -10,6 +10,7 @@ on: - "scripts/common/**" - "scripts/telemetry/**" - "test/lambda/**" + - "test/security/data/ecr_scan_allowlist/lambda/**" - ".github/workflows/pr-lambda.yml" - "!docs/**" @@ -70,6 +71,7 @@ jobs: - "scripts/lambda/**" - "scripts/common/**" - "scripts/telemetry/**" + - "test/security/data/ecr_scan_allowlist/lambda/**" # ============================================================ # Build all 6 image targets diff --git a/docker/lambda/Dockerfile b/docker/lambda/Dockerfile index f1bfdba13e02..2f8b6d65ca71 100644 --- a/docker/lambda/Dockerfile +++ b/docker/lambda/Dockerfile @@ -1,8 +1,9 @@ # ============================================================ # Lambda Python sources -# These images include the Lambda Runtime Interface Client (RIC) -# pre-installed in /var/lang, so no explicit awslambdaric install -# is needed in downstream runtime stages. +# We take only the Python binary, stdlib, and lib-dynload. +# Site-packages are intentionally excluded — all dependencies +# (including awslambdaric) are installed via uv so we own the +# full dependency tree with no Lambda-bundled extras. # ============================================================ FROM public.ecr.aws/lambda/python:3.13 as lambda-python @@ -58,19 +59,25 @@ RUN dnf install -y --setopt=install_weak_deps=False \ && cd /tmp && rm -rf ffmpeg-6.1 # ============================================================ -# Base builder (Python 3.13 — requests, pip-licenses for OSS compliance) +# Base builder (Python 3.13 — awslambdaric, requests, pip-licenses) # ============================================================ FROM builder-base as builder-base-py3 -COPY --from=lambda-python /var/lang /var/lang +COPY --from=lambda-python /var/lang/bin /var/lang/bin +COPY --from=lambda-python /var/lang/include /var/lang/include +COPY --from=lambda-python /var/lang/lib /var/lang/lib +RUN rm -rf /var/lang/lib/python3.13/site-packages ENV PATH="/var/lang/bin:$PATH" COPY ./docker/lambda/requirements-base.txt /tmp/requirements.txt RUN --mount=type=cache,target=/root/.cache/uv uv pip install --python /var/lang/bin/python3.13 -r /tmp/requirements.txt # ============================================================ -# CuPy builder (Python 3.13 — CuPy, NumPy, SciPy, etc.) +# CuPy builder (Python 3.13 — awslambdaric, CuPy, NumPy, SciPy, etc.) # ============================================================ FROM builder-base as builder-cupy-py3 -COPY --from=lambda-python /var/lang /var/lang +COPY --from=lambda-python /var/lang/bin /var/lang/bin +COPY --from=lambda-python /var/lang/include /var/lang/include +COPY --from=lambda-python /var/lang/lib /var/lang/lib +RUN rm -rf /var/lang/lib/python3.13/site-packages ENV PATH="/var/lang/bin:$PATH" COPY ./docker/lambda/requirements-cupy.txt /tmp/requirements.txt RUN --mount=type=cache,target=/root/.cache/uv \ @@ -81,10 +88,13 @@ RUN --mount=type=cache,target=/root/.cache/uv \ && find /var/lang -type f -name "*.pyo" -delete # ============================================================ -# PyTorch builder (Python 3.13 — PyTorch, SAM2, transformers) +# PyTorch builder (Python 3.13 — awslambdaric, PyTorch, SAM2, transformers) # ============================================================ FROM builder-base-devel as builder-pytorch-py3 -COPY --from=lambda-python /var/lang /var/lang +COPY --from=lambda-python /var/lang/bin /var/lang/bin +COPY --from=lambda-python /var/lang/include /var/lang/include +COPY --from=lambda-python /var/lang/lib /var/lang/lib +RUN rm -rf /var/lang/lib/python3.13/site-packages ENV PATH="/var/lang/bin:$PATH" COPY ./docker/lambda/requirements-pytorch.txt /tmp/requirements.txt RUN --mount=type=cache,target=/root/.cache/uv \ @@ -101,7 +111,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \ FROM nvidia/cuda:12.8.1-runtime-amzn2023 as base-py3 LABEL maintainer="Amazon AI" LABEL dlc_major_version="1" -RUN dnf upgrade -y --security && dnf clean all && rm -rf /var/cache/dnf +RUN dnf upgrade -y --security --releasever latest && dnf clean all && rm -rf /var/cache/dnf COPY --from=builder-base-py3 /var/lang /var/lang COPY --from=lambda-python /var/runtime /var/runtime COPY --from=rie-downloader /usr/local/bin/aws-lambda-rie /usr/local/bin/aws-lambda-rie @@ -133,19 +143,19 @@ RUN chmod +x /usr/local/bin/deep_learning_container.py \ && echo 'source /usr/local/bin/bash_telemetry.sh' >>/etc/bashrc \ && echo 'source /usr/local/bin/bash_telemetry.sh' >>/root/.bashrc \ && bash /tmp/setup_oss_compliance.sh python3 \ - && rm /tmp/setup_oss_compliance.sh + && rm /tmp/setup_oss_compliance.sh \ + && rm -rf /var/lang/lib/python3.13/ensurepip/_bundled WORKDIR /var/task ENTRYPOINT ["/lambda_entrypoint.sh", "python", "-m", "awslambdaric"] CMD ["handler.handler"] # ============================================================ # Runtime: CuPy Python 3.13 (base + CuPy, NumPy, SciPy) -# /var/lang from builder includes both Lambda RIC and our deps. # ============================================================ FROM nvidia/cuda:12.8.1-runtime-amzn2023 as cupy-py3 LABEL maintainer="Amazon AI" LABEL dlc_major_version="1" -RUN dnf upgrade -y --security && dnf clean all && rm -rf /var/cache/dnf +RUN dnf upgrade -y --security --releasever latest && dnf clean all && rm -rf /var/cache/dnf COPY --from=builder-cupy-py3 /var/lang /var/lang COPY --from=lambda-python /var/runtime /var/runtime COPY --from=rie-downloader /usr/local/bin/aws-lambda-rie /usr/local/bin/aws-lambda-rie @@ -177,7 +187,8 @@ RUN chmod +x /usr/local/bin/deep_learning_container.py \ && echo 'source /usr/local/bin/bash_telemetry.sh' >>/etc/bashrc \ && echo 'source /usr/local/bin/bash_telemetry.sh' >>/root/.bashrc \ && bash /tmp/setup_oss_compliance.sh python3 \ - && rm /tmp/setup_oss_compliance.sh + && rm /tmp/setup_oss_compliance.sh \ + && rm -rf /var/lang/lib/python3.13/ensurepip/_bundled WORKDIR /var/task ENTRYPOINT ["/lambda_entrypoint.sh", "python", "-m", "awslambdaric"] CMD ["handler.handler"] @@ -188,7 +199,7 @@ CMD ["handler.handler"] FROM nvidia/cuda:12.8.1-runtime-amzn2023 as pytorch-py3 LABEL maintainer="Amazon AI" LABEL dlc_major_version="1" -RUN dnf upgrade -y --security \ +RUN dnf upgrade -y --security --releasever latest \ && dnf install -y --setopt=install_weak_deps=False \ libxcb libX11 libXext libXfixes alsa-lib \ && dnf clean all && rm -rf /var/cache/dnf @@ -225,7 +236,8 @@ RUN chmod +x /usr/local/bin/deep_learning_container.py \ && echo 'source /usr/local/bin/bash_telemetry.sh' >>/etc/bashrc \ && echo 'source /usr/local/bin/bash_telemetry.sh' >>/root/.bashrc \ && bash /tmp/setup_oss_compliance.sh python3 \ - && rm /tmp/setup_oss_compliance.sh + && rm /tmp/setup_oss_compliance.sh \ + && rm -rf /var/lang/lib/python3.13/ensurepip/_bundled WORKDIR /var/task ENTRYPOINT ["/lambda_entrypoint.sh", "python", "-m", "awslambdaric"] CMD ["handler.handler"] \ No newline at end of file diff --git a/docker/lambda/requirements-base.txt b/docker/lambda/requirements-base.txt index ff12af6b3bda..9d8ab5e6dfdd 100644 --- a/docker/lambda/requirements-base.txt +++ b/docker/lambda/requirements-base.txt @@ -1,4 +1,7 @@ +awslambdaric==3.1.1 +boto3==1.40.4 +pip==26.0.1 pip-licenses==5.5.1 requests==2.32.5 -setuptools==78.1.1 +setuptools==82.0.1 urllib3==2.6.3 diff --git a/docker/lambda/requirements-cupy.txt b/docker/lambda/requirements-cupy.txt index ddea404a5d8e..517ea71e479d 100644 --- a/docker/lambda/requirements-cupy.txt +++ b/docker/lambda/requirements-cupy.txt @@ -1,11 +1,13 @@ +awslambdaric==3.1.1 boto3==1.40.4 cupy-cuda12x==14.0.1 cvxpy==1.8.1 numba==0.64.0 numpy==2.4.2 pandas==3.0.1 +pip==26.0.1 pip-licenses==5.5.1 requests==2.32.5 scipy==1.17.1 -setuptools==78.1.1 +setuptools==82.0.1 urllib3==2.6.3 diff --git a/docker/lambda/requirements-pytorch.txt b/docker/lambda/requirements-pytorch.txt index c22014bb590a..a4c7ba3de0e8 100644 --- a/docker/lambda/requirements-pytorch.txt +++ b/docker/lambda/requirements-pytorch.txt @@ -1,18 +1,20 @@ --extra-index-url https://download.pytorch.org/whl/cu128 accelerate==1.12.0 av==16.1.0 +awslambdaric==3.1.1 boto3==1.40.4 diffusers==0.36.0 librosa==0.11.0 numpy==2.4.2 opencv-python-headless==4.13.0.92 pillow==12.1.1 +pip==26.0.1 pip-licenses==5.5.1 requests==2.32.5 safetensors==0.7.0 sam-2 @ git+https://github.com/facebookresearch/segment-anything-2.git@2b90b9f5ceec907a1c18123530e92e794ad901a4 scipy==1.17.1 -setuptools==78.1.1 +setuptools==82.0.1 soundfile==0.13.1 torch==2.10.0 torchaudio==2.10.0 diff --git a/test/security/data/ecr_scan_allowlist/lambda/framework_allowlist.json b/test/security/data/ecr_scan_allowlist/lambda/framework_allowlist.json index fffb67a9c4c7..1774eaad4a0f 100644 --- a/test/security/data/ecr_scan_allowlist/lambda/framework_allowlist.json +++ b/test/security/data/ecr_scan_allowlist/lambda/framework_allowlist.json @@ -1,177 +1,21 @@ [ - { - "vulnerability_id": "CVE-2022-46908", - "reason": "SQLite --safe CLI flag bypass; no fix available in AL2023 repo. Lambda images do not expose SQLite CLI to untrusted input.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2024-56171", - "reason": "libxml2 use-after-free in xmlSchemaIDCFillNodeTables; fix requires libxml2 >= 2.12.10 not yet available in AL2023 repo.", - "review_by": "2026-03-24" - }, { "vulnerability_id": "CVE-2024-6345", - "reason": "setuptools package_index RCE; pinned to setuptools==78.1.1 in requirements but ECR scan detects older copy bundled in uv or the Lambda base image's pip, which cannot be patched via requirements.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-13151", - "reason": "libtasn1 stack buffer overflow; fix not yet available in AL2023 repo. Lambda images do not parse untrusted ASN.1 input.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-13601", - "reason": "glib heap buffer overflow in g_escape_uri; fix not yet available in AL2023 repo. Lambda images do not expose glib URI parsing to untrusted input.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-1390", - "reason": "libcap pam_cap.so group name parsing flaw; Lambda images do not use PAM authentication.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-14087", - "reason": "glib buffer underflow in GVariant parsing; fix not yet available in AL2023 repo. Lambda images do not parse untrusted GVariant input.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-15467", - "reason": "OpenSSL stack buffer overflow via crafted QUIC packet; fix not yet available in AL2023 repo.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-15468", - "reason": "OpenSSL SSL_CIPHER_find crash on unknown cipher in QUIC; fix not yet available in AL2023 repo.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-24928", - "reason": "libxml2 stack buffer overflow in xmlSnprintfElements; fix requires libxml2 >= 2.12.10 not yet available in AL2023 repo.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-4138", - "reason": "Python tarfile symlink extraction filter bypass (stdlib); cannot be patched via pip. Lambda images do not extract untrusted tar archives at runtime.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-4330", - "reason": "Python tarfile symlink extraction filter bypass (stdlib); cannot be patched via pip. Lambda images do not extract untrusted tar archives at runtime.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-4435", - "reason": "Python tarfile errorlevel=0 filter bypass (stdlib); cannot be patched via pip. Lambda images do not extract untrusted tar archives at runtime.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-4517", - "reason": "Python tarfile arbitrary write with filter=data (stdlib); cannot be patched via pip. Lambda images do not extract untrusted tar archives at runtime.", - "review_by": "2026-03-24" + "reason": "ECR scanner false positive: attributes setuptools 38.5.0 to pip_licenses-5.5.1.dist-info/METADATA. No such version exists in the image; setuptools==82.0.1 is installed. The actual setuptools 38.5.0 copy is vendored inside pip/_vendor/pkg_resources and is never invoked at Lambda runtime." }, { "vulnerability_id": "CVE-2025-47273", - "reason": "setuptools path traversal; pinned to setuptools==78.1.1 in requirements but ECR scan detects older copy bundled in uv or the Lambda base image's pip, which cannot be patched via requirements.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-47912", - "reason": "Go net/url insufficient validation of bracketed IPv6 hostnames; present in NVIDIA CUDA base image Go tooling, not exposed by Lambda runtime.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-4802", - "reason": "glibc untrusted LD_LIBRARY_PATH in setuid binaries; Lambda images do not run setuid binaries.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-49794", - "reason": "libxml2 heap use-after-free DoS; fix not yet available in AL2023 repo.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-49795", - "reason": "libxml2 null pointer dereference DoS; fix not yet available in AL2023 repo.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-49796", - "reason": "libxml2 type confusion DoS; fix not yet available in AL2023 repo.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-58188", - "reason": "Go crypto/x509 panic on DSA public key certificates; present in NVIDIA CUDA base image Go tooling, not exposed by Lambda runtime.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-5914", - "reason": "libarchive out-of-bounds read in RAR seek; Lambda images do not extract untrusted RAR archives.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-59375", - "reason": "libexpat large dynamic allocation via small document; fix requires expat >= 2.7.2 not yet available in AL2023 repo.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-6021", - "reason": "libxml2 integer overflow in xmlBuildQName; fix not yet available in AL2023 repo.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-6052", - "reason": "glib GString memory management flaw on very large strings; fix not yet available in AL2023 repo.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-68973", - "reason": "GnuPG armor_filter double-increment OOB; fix requires GnuPG >= 2.4.9 not yet available in AL2023 repo.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-69421", - "reason": "OpenSSL PKCS#12 null pointer dereference; fix not yet available in AL2023 repo.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-7425", - "reason": "libxslt attribute type flag corruption; fix not yet available in AL2023 repo.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2025-8194", - "reason": "Python tarfile extraction API defect (stdlib); cannot be patched via pip. Lambda images do not extract untrusted tar archives at runtime.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2026-21441", - "reason": "urllib3 decompression bomb on redirect responses; pinned to urllib3==2.6.3 in requirements files but ECR scan may still report against bundled copies in transitive deps.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2026-22796", - "reason": "OpenSSL ASN1_TYPE type confusion in PKCS7_digest_from_attributes; fix not yet available in AL2023 repo.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2026-23949", - "reason": "CVE details not yet published; present in NVIDIA CUDA base image, no fix available in AL2023 repo.", - "review_by": "2026-03-24" - }, - { - "vulnerability_id": "CVE-2026-24882", - "reason": "GnuPG tpm2daemon stack buffer overflow in PKDECRYPT; fix requires GnuPG >= 2.5.17. Lambda images do not use TPM2.", - "review_by": "2026-03-24" + "reason": "ECR scanner false positive: attributes setuptools 38.5.0 to pip_licenses-5.5.1.dist-info/METADATA. No such version exists in the image; setuptools==82.0.1 is installed. The actual setuptools 38.5.0 copy is vendored inside pip/_vendor/pkg_resources and is never invoked at Lambda runtime." }, + { "vulnerability_id": "CVE-2026-25679", - "reason": "Go net/url invalid host/authority parsing; present in NVIDIA CUDA base image Go tooling bundled with pytorch, not exposed by Lambda runtime.", - "review_by": "2026-03-24" + "reason": "Go net/url CVE in aws-lambda-rie binary (v1.33, built with Go 1.25.7). Fixed in Go 1.25.8 but no new RIE release yet. We download releases/latest so this will auto-resolve on next RIE release.", + "review_by": "2026-06-12" }, { "vulnerability_id": "CVE-2026-27142", - "reason": "Go net/html XSS via unescaped URL in meta content attribute; present in NVIDIA CUDA base image Go tooling bundled with pytorch, not exposed by Lambda runtime.", - "review_by": "2026-03-24" + "reason": "Go net/html CVE in aws-lambda-rie binary (v1.33, built with Go 1.25.7). Fixed in Go 1.25.8 but no new RIE release yet. We download releases/latest so this will auto-resolve on next RIE release.", + "review_by": "2026-06-12" } ] diff --git a/test/security/scripts/ecr_scan.py b/test/security/scripts/ecr_scan.py index 2fc34f00158f..d7d3e38c14d3 100755 --- a/test/security/scripts/ecr_scan.py +++ b/test/security/scripts/ecr_scan.py @@ -127,6 +127,8 @@ def filter_findings(findings, allowlist): vuln_id = vuln.get("packageVulnerabilityDetails", {}).get("vulnerabilityId", "") if vuln_id in allowlist: continue + if vuln.get("fixAvailable") not in ("YES", "PARTIAL"): + continue packages = [] seen_pkgs = set() @@ -145,6 +147,8 @@ def filter_findings(findings, allowlist): "name": pkg.get("name", ""), "version": pkg.get("version", ""), "fixed_in": fixed_in, + "file_path": pkg.get("filePath", ""), + "remediation": pkg.get("remediation", ""), } ) @@ -155,6 +159,9 @@ def filter_findings(findings, allowlist): grouped[vuln_id] = { "vulnerability_id": vuln_id, "severity": severity, + "inspector_score": vuln.get("inspectorScore", ""), + "exploit_available": vuln.get("exploitAvailable", "NO"), + "epss_score": vuln.get("epss", {}).get("score", ""), "source_url": vuln.get("packageVulnerabilityDetails", {}).get("sourceUrl", ""), "description": vuln.get("description", ""), "manager": vuln.get("packageVulnerabilityDetails", {}) @@ -217,13 +224,24 @@ def main(): for pkg in vuln["packages"] if pkg["fixed_in"] != "N/A" ) + file_paths = ", ".join( + pkg["file_path"] for pkg in vuln["packages"] if pkg.get("file_path") + ) + remediations = ", ".join( + dict.fromkeys( + pkg["remediation"] for pkg in vuln["packages"] if pkg.get("remediation") + ) + ) allowlist_entry = pformat( {"vulnerability_id": vuln["vulnerability_id"], "reason": "TODO"} ) LOGGER.error( - f"{vuln['severity']} {vuln['vulnerability_id']}\n" + f"{vuln['severity']} {vuln['vulnerability_id']}" + f" [score={vuln['inspector_score']}, epss={vuln['epss_score']}, exploit={vuln['exploit_available']}]\n" f"\tPackage Manager: {vuln['manager']}\n" f"\tPackages: {pkg_summary}\n" + f"\tFile paths: {file_paths}\n" + f"\tRemediation: {remediations}\n" f"\tURL: {vuln['source_url']}\n" f"\tDescription: {vuln['description'][:200]}\n" f"\tPin fix: {pin_suggestions}\n"