From a0c14d5e6e5f762df8f0aa37fda8fe48162bfad4 Mon Sep 17 00:00:00 2001 From: "Cheng-Chen, Chen" Date: Thu, 15 Oct 2026 08:27:40 +0800 Subject: [PATCH] fix(security): package the official Ubuntu curl security update --- docs/releases/server-1.6.533.md | 9 ++++ scripts/check-server-api-explorer-patch.sh | 17 ++++-- .../test-current-server-packaging-contract.py | 52 +++++++++++++++++++ scripts/test-server-component-candidate.py | 2 +- server/Dockerfile.web-compose-release | 18 ++++--- server/build-api-explorer-patch-image.sh | 6 +-- server/security/openvex.json | 8 +-- 7 files changed, 95 insertions(+), 17 deletions(-) diff --git a/docs/releases/server-1.6.533.md b/docs/releases/server-1.6.533.md index 97b201254f5..975351dc337 100644 --- a/docs/releases/server-1.6.533.md +++ b/docs/releases/server-1.6.533.md @@ -23,6 +23,15 @@ Server正式發行、成品讀回、8080部署、13語系×桌面/窄版×亮 以及普通HTTP複製仍各自待完成,不將來源測試當成瀏覽器通過。 歷史矩陣與KVM待驗維持原狀。 +正式成品安全 gate 發現 curl `8.18.0-1ubuntu2.7` 的 `CVE-2026-92392` HIGH。 +本候選版改用 Ubuntu 2026-10-14 [USN-8927-1](https://ubuntu.com/security/notices/USN-8927-1) +正式修補的 `curl`、`libcurl3t64-gnutls`、`libcurl4t64` `8.18.0-1ubuntu2.8`。 +三包直接取自官方安全套件庫,以簽章索引與實際 deb bytes 核對 SHA-256 後鎖定; +保留其他套件的既有 snapshot、原套件 metadata、授權與安裝路徑。 +既有 `PASTURESTACK_CURL_SECURITY_SNAPSHOT=20261002T000000Z` 僅保留為 apt 來源標記; +本次 curl 三包由上述獨立官方 ADD 與 checksum 提供,不來自該舊 snapshot。 +不新增 HIGH 豁免或 vendor-pending;仍須由正式成品安全 gate 確認修補結果。 + ## 邊界與升級 不改註冊API、帳號權限、OIDC、MFA、HAProxy、DB、網路後端或效能設定。 diff --git a/scripts/check-server-api-explorer-patch.sh b/scripts/check-server-api-explorer-patch.sh index 307e806d47a..0366ca7ffae 100755 --- a/scripts/check-server-api-explorer-patch.sh +++ b/scripts/check-server-api-explorer-patch.sh @@ -1731,7 +1731,7 @@ fi for release_curl_security_marker in \ 'FROM ${UBUNTU_SECURITY_IMAGE} AS runtime_security_packages' \ 'ARG UBUNTU_RUNTIME_SECURITY_SNAPSHOT=20261002T000000Z' \ - 'ARG CURL_PACKAGE_VERSION=8.18.0-1ubuntu2.7' \ + 'ARG CURL_PACKAGE_VERSION=8.18.0-1ubuntu2.8' \ 'ARG OPENSSL_PACKAGE_VERSION=3.5.5-1ubuntu3.7' \ 'Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg' \ 'Acquire::AllowInsecureRepositories "false"' \ @@ -1753,6 +1753,17 @@ for release_curl_security_marker in \ require_marker "$release_dockerfile" "$release_curl_security_marker" \ SERVER_INCREMENTAL_CURL_SECURITY_REFRESH_MISSING done +for release_curl_official_deb_marker in \ + 'ADD --checksum=sha256:2c418a61d7165d0cde01d9cb05ae025cc41fc75ef6d3f095996bd045ba0945dc' \ + 'https://security.ubuntu.com/ubuntu/pool/main/c/curl/curl_8.18.0-1ubuntu2.8_amd64.deb' \ + 'ADD --checksum=sha256:8db913e1fa5a694ca6ba7b828bd18c5204e6853ac07fe7ed9c6e1f94e3444d8e' \ + 'https://security.ubuntu.com/ubuntu/pool/main/c/curl/libcurl3t64-gnutls_8.18.0-1ubuntu2.8_amd64.deb' \ + 'ADD --checksum=sha256:7c0b37592f83a629cc22f0c98effa176da9edbd6d77b3f38184a9d0ddc5e0266' \ + 'https://security.ubuntu.com/ubuntu/pool/main/c/curl/libcurl4t64_8.18.0-1ubuntu2.8_amd64.deb' \ + 'cp "/tmp/${package}.deb" "/out/packages/${package}_${CURL_PACKAGE_VERSION}_amd64.deb"'; do + require_marker "$release_dockerfile" "$release_curl_official_deb_marker" \ + SERVER_CURL_OFFICIAL_FIXED_DEB_PIN_MISSING +done for release_libdbi_security_marker in \ 'ARG LIBDBI_PERL_PACKAGE_VERSION=1.647-1ubuntu0.26.04.4' \ 'ADD --checksum=sha256:3040f61cc06ebf363e5895db4cc2c7a2db8951296d39d4ef5fa0fc3fd364654e' \ @@ -1831,7 +1842,7 @@ require_marker "$build_script" \ 'PASTURESTACK_CURL_SECURITY_SNAPSHOT=20261002T000000Z' \ SERVER_CURL_IMAGE_SNAPSHOT_GATE_MISSING require_marker "$build_script" \ - 'PASTURESTACK_CURL_PACKAGE_VERSION=8.18.0-1ubuntu2.7' \ + 'PASTURESTACK_CURL_PACKAGE_VERSION=8.18.0-1ubuntu2.8' \ SERVER_CURL_IMAGE_VERSION_GATE_MISSING require_marker "$build_script" \ 'PASTURESTACK_GLIBC_PACKAGE_VERSION=2.43-2ubuntu2.4' \ @@ -2261,4 +2272,4 @@ for release_readback_contract in \ fi done -printf 'SERVER_API_EXPLORER_PATCH_OK release=v1.6.533 base=v1.6.460 engine=0.183.348 web_console=1.6.188 catalog_service=0.20.13 webhook_automation_service=0.10.4 authentication_service=0.4.43 curl=8.18.0-1ubuntu2.7 freemarker=2.3.35 artifact_scan=required vendor_pending=exact-set role_matrix=qa-required locale_layout=qa-required\n' +printf 'SERVER_API_EXPLORER_PATCH_OK release=v1.6.533 base=v1.6.460 engine=0.183.348 web_console=1.6.188 catalog_service=0.20.13 webhook_automation_service=0.10.4 authentication_service=0.4.43 curl=8.18.0-1ubuntu2.8 freemarker=2.3.35 artifact_scan=required vendor_pending=exact-set role_matrix=qa-required locale_layout=qa-required\n' diff --git a/scripts/test-current-server-packaging-contract.py b/scripts/test-current-server-packaging-contract.py index 285fef5caf3..9bc1d84858d 100644 --- a/scripts/test-current-server-packaging-contract.py +++ b/scripts/test-current-server-packaging-contract.py @@ -508,6 +508,58 @@ def previous_gate(gate=GATE): class Tests(unittest.TestCase): + def test_official_curl_fixed_debs_are_pinned_outside_the_unchanged_snapshot(self): + recipe, builder = FILES[DOCKER], FILES[BUILD] + version = '8.18.0-1ubuntu2.8' + expected = { + 'curl': '2c418a61d7165d0cde01d9cb05ae025cc41fc75ef6d3f095996bd045ba0945dc', + 'libcurl3t64-gnutls': '8db913e1fa5a694ca6ba7b828bd18c5204e6853ac07fe7ed9c6e1f94e3444d8e', + 'libcurl4t64': '7c0b37592f83a629cc22f0c98effa176da9edbd6d77b3f38184a9d0ddc5e0266', + } + declared = engine_gate_markers(GATE, 'release_curl_official_deb_marker') + normalized = recipe.replace('\\\n', ' ') + for package, digest in expected.items(): + url = 'https://security.ubuntu.com/ubuntu/pool/main/c/curl/' + package + '_' + version + '_amd64.deb' + pattern = (r'^ADD --checksum=sha256:' + digest + r'\s+' + re.escape(url) + + r'\s+/tmp/' + re.escape(package) + r'[.]deb\s*$') + self.assertRegex(normalized, re.compile(pattern, re.M)) + self.assertIn('ADD --checksum=sha256:' + digest, declared) + self.assertIn(url, declared) + self.assertEqual(recipe.count('ARG CURL_PACKAGE_VERSION=' + version), 2) + self.assertEqual(recipe.count('ARG UBUNTU_RUNTIME_SECURITY_SNAPSHOT=20261002T000000Z'), 2) + self.assertNotRegex(recipe, r'apt-get download\s+\\\s*\n\s*"curl=') + copy = 'cp "/tmp/${package}.deb" "/out/packages/${package}_${CURL_PACKAGE_VERSION}_amd64.deb"' + self.assertIn(copy, declared) + self.assertIn(copy + ';', recipe) + self.assertIn('PASTURESTACK_CURL_PACKAGE_VERSION=' + version, builder) + self.assertIn('"' + version + '"', builder) + self.assertNotIn('8.18.0-1ubuntu2.7', recipe + builder + FILES[VEX] + GATE) + for field in ('Package', 'Version', 'Architecture'): + self.assertIn('dpkg-deb -f "${package_file}" ' + field, recipe) + fixed = next(item for item in json.loads(FILES[VEX])['statements'] + if item['vulnerability']['name'] == 'CVE-2026-8932') + self.assertEqual(fixed['status'], 'fixed') + self.assertEqual({item['@id'] for item in fixed['products']}, + {'pkg:deb/ubuntu/' + package + '@' + version + '?arch=amd64&distro=ubuntu-26.04' + for package in expected}) + + def test_official_curl_gate_rejects_replaced_deb_inputs(self): + declared = engine_gate_markers(GATE, 'release_curl_official_deb_marker') + recipe = FILES[DOCKER] + self.assertEqual(len(declared), 7) + self.assertTrue(all(marker in recipe for marker in declared)) + for marker in declared: + replacements = ['REMOVED_CURL_PIN'] + if '8.18.0-1ubuntu2.8' in marker: + replacements.append(marker.replace('8.18.0-1ubuntu2.8', '8.18.0-1ubuntu2.7')) + if 'ADD --checksum=sha256:' in marker: + replacements.append('ADD --checksum=sha256:' + '0' * 64) + for replacement in replacements: + with self.subTest(marker=marker, replacement=replacement): + mutated = recipe.replace(marker, replacement) + self.assertFalse(all(required in mutated for required in declared), + 'the actual require_marker set rejects a removed, stale or wrong-hash input') + def test_official_dbi_security_update_is_isolated_and_hash_pinned(self): recipe, builder = FILES[DOCKER], FILES[BUILD] digest = '3040f61cc06ebf363e5895db4cc2c7a2db8951296d39d4ef5fa0fc3fd364654e' diff --git a/scripts/test-server-component-candidate.py b/scripts/test-server-component-candidate.py index 85fe0527fdc..844e2986f5f 100644 --- a/scripts/test-server-component-candidate.py +++ b/scripts/test-server-component-candidate.py @@ -264,7 +264,7 @@ def test_agent_archive_verbose_failure_cannot_bypass_link_rejection(self): def test_security_pins_and_overlay_path_are_retained(self): text = (ROOT / "server/Dockerfile.web-compose-release").read_text() for marker in ("ghcr.io/pasturestack/server:v1.6.460@sha256:c855af8aea232dacc5bb6df68e2271d482c68b53c43ab0c108ec19118f5ab403", - "OPENSSL_PACKAGE_VERSION=3.5.5-1ubuntu3.7", "CURL_PACKAGE_VERSION=8.18.0-1ubuntu2.7", + "OPENSSL_PACKAGE_VERSION=3.5.5-1ubuntu3.7", "CURL_PACKAGE_VERSION=8.18.0-1ubuntu2.8", "FREETYPE_PACKAGE_VERSION=2.14.2+dfsg-1ubuntu0.2", "UBUNTU_RUNTIME_SECURITY_SNAPSHOT=20261002T000000Z", "PatchV1GlobalSubscribe verify-hardware", "schema/service/service-auth.json", "db/core-124.xml"): self.assertIn(marker, text) diff --git a/server/Dockerfile.web-compose-release b/server/Dockerfile.web-compose-release index d6c62a2df2e..bc05b7e003f 100644 --- a/server/Dockerfile.web-compose-release +++ b/server/Dockerfile.web-compose-release @@ -460,7 +460,7 @@ RUN set -eux; \ FROM ${UBUNTU_SECURITY_IMAGE} AS runtime_security_packages ARG UBUNTU_RUNTIME_SECURITY_SNAPSHOT=20261002T000000Z -ARG CURL_PACKAGE_VERSION=8.18.0-1ubuntu2.7 +ARG CURL_PACKAGE_VERSION=8.18.0-1ubuntu2.8 ARG OPENSSL_PACKAGE_VERSION=3.5.5-1ubuntu3.7 ARG LIBDBI_PERL_PACKAGE_VERSION=1.647-1ubuntu0.26.04.4 ARG FREETYPE_PACKAGE_VERSION=2.14.2+dfsg-1ubuntu0.2 @@ -479,6 +479,15 @@ ADD --checksum=sha256:f24a7f7c0428d74e33ea934696987b7336ec0962f212535185f0493792 ADD --checksum=sha256:3040f61cc06ebf363e5895db4cc2c7a2db8951296d39d4ef5fa0fc3fd364654e \ https://security.ubuntu.com/ubuntu/pool/main/libd/libdbi-perl/libdbi-perl_1.647-1ubuntu0.26.04.4_amd64.deb \ /tmp/libdbi-perl.deb +ADD --checksum=sha256:2c418a61d7165d0cde01d9cb05ae025cc41fc75ef6d3f095996bd045ba0945dc \ + https://security.ubuntu.com/ubuntu/pool/main/c/curl/curl_8.18.0-1ubuntu2.8_amd64.deb \ + /tmp/curl.deb +ADD --checksum=sha256:8db913e1fa5a694ca6ba7b828bd18c5204e6853ac07fe7ed9c6e1f94e3444d8e \ + https://security.ubuntu.com/ubuntu/pool/main/c/curl/libcurl3t64-gnutls_8.18.0-1ubuntu2.8_amd64.deb \ + /tmp/libcurl3t64-gnutls.deb +ADD --checksum=sha256:7c0b37592f83a629cc22f0c98effa176da9edbd6d77b3f38184a9d0ddc5e0266 \ + https://security.ubuntu.com/ubuntu/pool/main/c/curl/libcurl4t64_8.18.0-1ubuntu2.8_amd64.deb \ + /tmp/libcurl4t64.deb RUN set -eux; \ mkdir -p /tmp/ca-bootstrap /etc/ssl/certs; \ dpkg-deb --extract /tmp/ca-certificates.deb /tmp/ca-bootstrap; \ @@ -511,11 +520,8 @@ RUN set -eux; \ sha256sum usr/lib/x86_64-linux-gnu/libpng16.so.16 > /out/libpng-runtime.sha256; \ test "$(wc -l < /out/libpng-runtime.sha256)" -eq 1; \ cd /out/packages; \ - apt-get download \ - "curl=${CURL_PACKAGE_VERSION}" \ - "libcurl3t64-gnutls=${CURL_PACKAGE_VERSION}" \ - "libcurl4t64=${CURL_PACKAGE_VERSION}"; \ for package in curl libcurl3t64-gnutls libcurl4t64; do \ + cp "/tmp/${package}.deb" "/out/packages/${package}_${CURL_PACKAGE_VERSION}_amd64.deb"; \ package_file="$(find . -maxdepth 1 -type f -name "${package}_*.deb" -print)"; \ test -n "${package_file}"; \ test "$(printf '%s\n' "${package_file}" | wc -l)" -eq 1; \ @@ -581,7 +587,7 @@ ARG NODE_AGENT_VERSION=0.13.28 ARG NODE_AGENT_COMMIT=bb4e057c089e5384bc9836b42db206326c690387 ARG NODE_AGENT_ARCHIVE_SHA256=a16ae6be5fb72fa2ba38bd1076fd3b9e0536c48e70995ffa49d17b8063e2f8d0 ARG UBUNTU_RUNTIME_SECURITY_SNAPSHOT=20261002T000000Z -ARG CURL_PACKAGE_VERSION=8.18.0-1ubuntu2.7 +ARG CURL_PACKAGE_VERSION=8.18.0-1ubuntu2.8 ARG OPENSSL_PACKAGE_VERSION=3.5.5-1ubuntu3.7 ARG LIBDBI_PERL_PACKAGE_VERSION=1.647-1ubuntu0.26.04.4 ARG FREETYPE_PACKAGE_VERSION=2.14.2+dfsg-1ubuntu0.2 diff --git a/server/build-api-explorer-patch-image.sh b/server/build-api-explorer-patch-image.sh index be66dbae1f4..218f5f3dfd1 100755 --- a/server/build-api-explorer-patch-image.sh +++ b/server/build-api-explorer-patch-image.sh @@ -356,7 +356,7 @@ for marker in \ PASTURESTACK_RUNTIME_GO_VERSION=1.27.2 \ PASTURESTACK_UBUNTU_SECURITY_REFRESH=2026-09-10 \ PASTURESTACK_CURL_SECURITY_SNAPSHOT=20261002T000000Z \ - PASTURESTACK_CURL_PACKAGE_VERSION=8.18.0-1ubuntu2.7 \ + PASTURESTACK_CURL_PACKAGE_VERSION=8.18.0-1ubuntu2.8 \ PASTURESTACK_GLIBC_CVE_2026_18374_FIX=not-in-execute-path \ PASTURESTACK_GLIBC_PACKAGE_VERSION=2.43-2ubuntu2.4 \ PASTURESTACK_PERL_PACKAGE_VERSION=5.40.1-7ubuntu0.3 \ @@ -847,7 +847,7 @@ EOF } for curl_package in curl libcurl3t64-gnutls libcurl4t64; do test "$(dpkg-query -W -f='"'"'${Version}'"'"' "${curl_package}")" = \ - "8.18.0-1ubuntu2.7" + "8.18.0-1ubuntu2.8" done for glibc_package in libc6 libc-bin libc-gconv-modules-extra; do test "$(dpkg-query -W -f='"'"'${Version}'"'"' "${glibc_package}")" = \ @@ -966,7 +966,7 @@ EOF docker run --rm -i --network none --entrypoint bash "$image" -s \ < scripts/test-server-openssl-tls.sh -printf 'SERVER_API_EXPLORER_PATCH_IMAGE_OK image=%s revision=%s base=%s orchestration=%s orchestration_commit=%s orchestration_sha256=%s api_explorer=%s api_explorer_commit=%s artifact_sha256=%s web_console=%s web_console_commit=%s web_console_sha256=%s catalog_service=%s catalog_service_commit=%s catalog_service_archive_sha256=%s catalog_service_binary_sha256=%s catalog_service_sqlite_binary_sha256=%s authentication_service=%s authentication_service_commit=%s authentication_service_archive_sha256=%s authentication_service_binary_sha256=%s websocket_proxy=%s websocket_proxy_commit=%s websocket_proxy_archive_sha256=%s websocket_proxy_binary_sha256=%s compose_executor=%s compose_executor_commit=%s compose_executor_archive_sha256=%s compose_executor_binary_sha256=%s vsphere_cli=%s vsphere_cli_commit=%s vsphere_cli_archive_sha256=%s govc_binary_sha256=%s runtime_go=1.27.2 orchestration_updated=1 wrappers_pinned=1 audit_log_filters=1 curl=8.18.0-1ubuntu2.7 freemarker=2.3.35 vendor_pending=exact-set artifact_scan=required\n' \ +printf 'SERVER_API_EXPLORER_PATCH_IMAGE_OK image=%s revision=%s base=%s orchestration=%s orchestration_commit=%s orchestration_sha256=%s api_explorer=%s api_explorer_commit=%s artifact_sha256=%s web_console=%s web_console_commit=%s web_console_sha256=%s catalog_service=%s catalog_service_commit=%s catalog_service_archive_sha256=%s catalog_service_binary_sha256=%s catalog_service_sqlite_binary_sha256=%s authentication_service=%s authentication_service_commit=%s authentication_service_archive_sha256=%s authentication_service_binary_sha256=%s websocket_proxy=%s websocket_proxy_commit=%s websocket_proxy_archive_sha256=%s websocket_proxy_binary_sha256=%s compose_executor=%s compose_executor_commit=%s compose_executor_archive_sha256=%s compose_executor_binary_sha256=%s vsphere_cli=%s vsphere_cli_commit=%s vsphere_cli_archive_sha256=%s govc_binary_sha256=%s runtime_go=1.27.2 orchestration_updated=1 wrappers_pinned=1 audit_log_filters=1 curl=8.18.0-1ubuntu2.8 freemarker=2.3.35 vendor_pending=exact-set artifact_scan=required\n' \ "$image" "$revision" "$base_image" "${orchestration_engine_release_tag#v}" \ "$orchestration_engine_commit" "$orchestration_engine_artifact_sha256" \ "${api_explorer_release_tag#v}" "$api_explorer_commit" "$api_explorer_artifact_sha256" \ diff --git a/server/security/openvex.json b/server/security/openvex.json index 0fc2baf51d4..93a2104fa6c 100644 --- a/server/security/openvex.json +++ b/server/security/openvex.json @@ -55,17 +55,17 @@ }, "products": [ { - "@id": "pkg:deb/ubuntu/curl@8.18.0-1ubuntu2.7?arch=amd64&distro=ubuntu-26.04" + "@id": "pkg:deb/ubuntu/curl@8.18.0-1ubuntu2.8?arch=amd64&distro=ubuntu-26.04" }, { - "@id": "pkg:deb/ubuntu/libcurl3t64-gnutls@8.18.0-1ubuntu2.7?arch=amd64&distro=ubuntu-26.04" + "@id": "pkg:deb/ubuntu/libcurl3t64-gnutls@8.18.0-1ubuntu2.8?arch=amd64&distro=ubuntu-26.04" }, { - "@id": "pkg:deb/ubuntu/libcurl4t64@8.18.0-1ubuntu2.7?arch=amd64&distro=ubuntu-26.04" + "@id": "pkg:deb/ubuntu/libcurl4t64@8.18.0-1ubuntu2.8?arch=amd64&distro=ubuntu-26.04" } ], "status": "fixed", - "impact_statement": "The final runtime installs Ubuntu 26.04 curl and both shipped libcurl variants at 8.18.0-1ubuntu2.7, including the 2026-09-24 security update, and enforces the exact installed versions during image assembly and post-build validation." + "impact_statement": "The final runtime installs Ubuntu 26.04 curl and both shipped libcurl variants at 8.18.0-1ubuntu2.8 from the official USN-8927-1 security update, retaining the CVE-2026-8932 fix, and enforces the exact installed versions during image assembly and post-build validation." }, { "vulnerability": {