From 07ba641b3f6e992ce458eca05654422ddcff3efc Mon Sep 17 00:00:00 2001 From: chen21019 <19357113+chen21019@users.noreply.github.com> Date: Tue, 15 Sep 2026 17:12:10 +0800 Subject: [PATCH] fix: separate OIDC source and access-policy updates --- .github/workflows/release.yml | 2 +- .github/workflows/security-release-gate.yml | 6 +- COMPATIBILITY.md | 16 + README.md | 19 +- SECURITY.md | 8 + model/auth_config.go | 17 +- model/error.go | 6 +- providers/oidc/oidc_client.go | 6 + providers/oidc/oidc_provider.go | 7 +- security/dapper.openvex.json | 1593 ++++++++++++++++++- server/auth_server.go | 167 +- server/config_update_policy.go | 321 ++++ server/config_update_policy_test.go | 444 ++++++ service/route_handlers.go | 12 +- service/routes.go | 13 +- service/routes_test.go | 23 + 16 files changed, 2565 insertions(+), 95 deletions(-) create mode 100644 server/config_update_policy.go create mode 100644 server/config_update_policy_test.go diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 30deccc..0a04e6a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -208,7 +208,7 @@ jobs: { printf '# PastureStack Authentication Service %s\n\n' "$RELEASE_TAG" - printf 'This release provides provider-neutral OpenID Connect authorization-code authentication, a short-lived signed identity proof for explicit account linking or reassignment, transactional provider switching, and local-administrator recovery without username or email guessing.\n\n' + printf 'This release separates OIDC identity-source initialization from site-access policy updates. Access-only changes skip discovery, unrestricted mode clears the allowlist, restricted and required policies accept only deduplicated OIDC users and groups, and access expansion requires a single-use MFA confirmation bound to the operator and canonical request digest. Initial enablement and identity-source changes retain the fresh local-recovery gate.\n\n' printf '## Immutable coordinates\n\n' printf -- '- Source commit: `%s`\n' "$SOURCE_SHA" printf -- '- Artifact SHA-256: `%s`\n\n' "$artifact_sha" diff --git a/.github/workflows/security-release-gate.yml b/.github/workflows/security-release-gate.yml index 4093863..d81b4ef 100644 --- a/.github/workflows/security-release-gate.yml +++ b/.github/workflows/security-release-gate.yml @@ -20,7 +20,7 @@ jobs: env: DAPPER_IMAGE: pasturestack/authentication-service-dapper:${{ github.sha }} TRIVY_IMAGE: aquasec/trivy:0.73.0@sha256:7cced7cae583819fc7806d4cbc0dbbc7cad18b99f7d3e235192e6da8c091045c - VERSION_OVERRIDE: v0.4.36 + VERSION_OVERRIDE: v0.4.37 steps: - name: Check out candidate uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -70,7 +70,7 @@ jobs: } run_ci - artifact="dist/artifacts/authentication-service-0.4.36-linux-amd64.tar.xz" + artifact="dist/artifacts/authentication-service-0.4.37-linux-amd64.tar.xz" test -s "$artifact" cp "$artifact" /tmp/authentication-service-first.tar.xz rm -rf bin dist @@ -81,7 +81,7 @@ jobs: tar -xJf "$artifact" -C evidence/product test -x evidence/product/authentication-service test "$(find evidence/product -maxdepth 1 -type f | wc -l)" -eq 1 - evidence/product/authentication-service --version | grep -F '0.4.36' >/dev/null + evidence/product/authentication-service --version | grep -F '0.4.37' >/dev/null sha256sum "$artifact" > evidence/authentication-service.tar.xz.sha256 docker run --rm --entrypoint go \ --volume "$PWD:/work:ro" \ diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md index 7d67a8e..6a69b9c 100644 --- a/COMPATIBILITY.md +++ b/COMPATIBILITY.md @@ -12,6 +12,22 @@ the active authentication method changes. Existing local authentication remains the recovery path until a second, fresh authorization-code exchange creates a normal platform session. +## OIDC site-access policy updates + +OIDC provider initialization and site-access authorization are independent +transactions. Updating only `accessMode` or `allowedIdentities` on an already +enabled, unchanged OIDC provider must not repeat discovery, key retrieval, or +provider initialization. Initial enablement, changing provider type, or +changing the OIDC identity source still requires a fresh local-recovery check +and successful provider initialization. + +Expanding access requires a one-time Engine MFA security confirmation bound to +the authenticated operator, purpose `oidcAccessPolicyUpdate`, and the canonical +SHA-256 request digest. Reducing access does not require step-up confirmation. +Unrestricted mode persists a non-null empty allowlist. Restricted and required +mode entries are canonicalized and deduplicated by `externalIdType` plus +`externalId`; only `oidc_user` and `oidc_group` are accepted. + Operator lifecycle messages support `en-US` and `zh-TW`. Tokens, usernames, groups, identity-provider data, OpenID Connect claims, SAML documents, database settings, HTTP payloads, and protocol errors are not translated. diff --git a/README.md b/README.md index 51d8c21..02586a4 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ PastureStack is an independent community effort to preserve, audit, and moderniz ## Project status -The current compatibility release retains the existing Ubuntu 26.04, +The current compatibility release is `v0.4.37`. It retains the existing Ubuntu 26.04, Go 1.27.0, JWT, cookie, TLS, LDAP, GitHub, Shibboleth, dependency, and build maintenance. It adds a provider-neutral OpenID Connect authorization-code client with discovery, PKCE S256, nonce validation, @@ -20,6 +20,19 @@ Successful staged sign-in also produces a short-lived, audience-bound, single-use signed identity proof. The control platform uses that proof for an explicit account-link or reassignment decision; profile fields are never trusted as implicit account-matching keys. + +Release `v0.4.37` separates OIDC identity-source changes from site-access +policy changes. An already-enabled provider can change access mode and its +OIDC user/group allowlist without repeating discovery or the five-minute local +recovery ceremony. Initial enablement, provider switches, and changes to the +discovery URL, client credentials, custom CA, scopes, PKCE, or identity claims +still require fresh local recovery and provider validation. Access expansion +requires a single-use MFA confirmation bound to the authenticated operator and +the canonical request digest. Unrestricted mode always persists an explicit +empty allowlist; restricted and required modes accept and deduplicate only +`oidc_user` and `oidc_group` identities. Stable error codes distinguish local +recovery, MFA confirmation, and invalid access-policy failures. + Product-owned imports, executable names, CLI settings, client variables, and operator messages use PastureStack naming. @@ -37,9 +50,9 @@ make build make package ``` -Set `VERSION_OVERRIDE=v0.4.36` for the reviewed identity-security compatibility +Set `VERSION_OVERRIDE=v0.4.37` for the reviewed identity-security compatibility release. Packaging produces the deterministic, versioned -`authentication-service-0.4.36-linux-amd64.tar.xz` asset. The manually +`authentication-service-0.4.37-linux-amd64.tar.xz` asset. The manually dispatched release workflow runs the full test and validation suite twice, requires byte-identical packages, verifies a fixed and attested security scanner, publishes CycloneDX SBOMs and scan evidence, and publishes the diff --git a/SECURITY.md b/SECURITY.md index cfa9005..6b70177 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -34,6 +34,14 @@ administrator testing before activation. replay-protected by the control platform. It carries the exact provider and immutable external identifier used for an explicit account-link decision; usernames and email addresses are display data, not matching keys. +- Expanding OIDC site access requires a single-use MFA confirmation bound to + the authenticated operator, the fixed policy-update purpose, and a canonical + SHA-256 request digest. The confirmation value is detached before provider + normalization or persistence and is never written to settings or logs. +- Unrestricted OIDC access always clears the stored identity allowlist. Other + access modes accept only canonical `oidc_user` and `oidc_group` principals; + duplicate or delimiter-injecting entries are rejected or deduplicated before + storage. - Do not commit keys, credentials, tokens, encrypted production settings, identity data, or live assertions. ## Dependency and build evidence diff --git a/model/auth_config.go b/model/auth_config.go index f3cd9a8..2d3a5a0 100644 --- a/model/auth_config.go +++ b/model/auth_config.go @@ -5,14 +5,15 @@ import "github.com/rancher/go-rancher/v2" // AuthConfig structure contains the AuthConfig definition type AuthConfig struct { client.Resource - Provider string `json:"provider"` - Enabled bool `json:"enabled"` - AccessMode string `json:"accessMode"` - AllowedIdentities []client.Identity `json:"allowedIdentities"` - GithubConfig GithubConfig `json:"githubConfig"` - ShibbolethConfig ShibbolethConfig `json:"shibbolethConfig"` - LdapConfig LdapConfig `json:"ldapConfig"` - OIDCConfig OIDCConfig `json:"oidcConfig"` + Provider string `json:"provider"` + Enabled bool `json:"enabled"` + AccessMode string `json:"accessMode"` + AllowedIdentities []client.Identity `json:"allowedIdentities"` + GithubConfig GithubConfig `json:"githubConfig"` + ShibbolethConfig ShibbolethConfig `json:"shibbolethConfig"` + LdapConfig LdapConfig `json:"ldapConfig"` + OIDCConfig OIDCConfig `json:"oidcConfig"` + SecurityConfirmation string `json:"securityConfirmation,omitempty"` } type TestAuthConfig struct { diff --git a/model/error.go b/model/error.go index 44f76d7..802504e 100644 --- a/model/error.go +++ b/model/error.go @@ -5,6 +5,8 @@ import "github.com/rancher/go-rancher/client" // AuthServiceError structure contains the error resource definition type AuthServiceError struct { client.Resource - Status string `json:"status"` - Message string `json:"message"` + Status string `json:"status"` + Code string `json:"code,omitempty"` + Message string `json:"message"` + RequestDigest string `json:"requestDigest,omitempty"` } diff --git a/providers/oidc/oidc_client.go b/providers/oidc/oidc_client.go index 9a5f66a..012dc12 100644 --- a/providers/oidc/oidc_client.go +++ b/providers/oidc/oidc_client.go @@ -131,6 +131,12 @@ func normalizeConfig(config *model.OIDCConfig) { } } +// NormalizeConfig applies the same canonical defaults used by the live OIDC +// client without performing discovery or making a network request. +func NormalizeConfig(config *model.OIDCConfig) { + normalizeConfig(config) +} + func validateConfig(config *model.OIDCConfig) error { if config.WellKnownURL == "" { return fmt.Errorf("OIDC discovery URL is required") diff --git a/providers/oidc/oidc_provider.go b/providers/oidc/oidc_provider.go index 45ad769..78007ed 100644 --- a/providers/oidc/oidc_provider.go +++ b/providers/oidc/oidc_provider.go @@ -120,7 +120,12 @@ func (p *Provider) GetConfig() model.AuthConfig { } func (p *Provider) GetSettings() map[string]string { - config := p.client.config + return SettingsForConfig(*p.client.config) +} + +// SettingsForConfig serializes OIDC settings without initializing the +// provider. It is used for display-only updates that must not repeat discovery. +func SettingsForConfig(config model.OIDCConfig) map[string]string { settings := map[string]string{ displayNameSetting: config.DisplayName, wellKnownURLSetting: config.WellKnownURL, diff --git a/security/dapper.openvex.json b/security/dapper.openvex.json index 58c02ad..b0a086b 100644 --- a/security/dapper.openvex.json +++ b/security/dapper.openvex.json @@ -1,13 +1,13 @@ { "@context": "https://openvex.dev/ns/v0.2.0", - "@id": "https://github.com/PastureStack/authentication-service/security/openvex/dapper/2026-08-09", + "@id": "https://github.com/PastureStack/authentication-service/security/openvex/dapper/2026-09-15", "author": "PastureStack contributors", - "timestamp": "2026-08-09T05:14:44+08:00", - "version": 1, + "timestamp": "2026-09-15T17:24:46+08:00", + "version": 2, "statements": [ { "vulnerability": { - "name": "CVE-2026-53215" + "name": "CVE-2025-10263" }, "products": [ { @@ -20,7 +20,1268 @@ }, { "vulnerability": { - "name": "CVE-2026-53260" + "name": "CVE-2025-40190" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-52908" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-52909" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-52910" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53145" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53148" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53153" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53159" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53170" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53171" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53172" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53173" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53178" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53182" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53183" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53185" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53192" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53193" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53196" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53198" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53235" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53239" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53240" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53250" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53254" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53256" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53259" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53262" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53264" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53266" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53269" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53270" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53275" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53276" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53356" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53362" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53388" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53398" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-53399" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-63801" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-63809" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-63815" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-63823" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64188" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64191" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64260" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64266" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64269" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64276" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64300" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64361" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64367" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64380" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64383" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64385" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64386" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64387" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64390" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64393" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64396" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64423" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64432" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64440" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64441" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64442" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64467" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64490" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64531" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64535" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64543" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64548" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64554" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64557" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64558" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64562" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64564" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64567" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64597" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-64601" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-68085" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-68098" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-68117" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-68121" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-68147" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-68162" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-68189" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-68196" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-68198" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-68199" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-68201" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-68204" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-68236" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-68257" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-68284" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-68323" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-68329" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-68380" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-68393" }, "products": [ { @@ -33,7 +1294,7 @@ }, { "vulnerability": { - "name": "CVE-2025-40190" + "name": "CVE-2026-68399" }, "products": [ { @@ -46,7 +1307,7 @@ }, { "vulnerability": { - "name": "CVE-2026-46331" + "name": "CVE-2026-68442" }, "products": [ { @@ -59,7 +1320,7 @@ }, { "vulnerability": { - "name": "CVE-2026-52908" + "name": "CVE-2026-68446" }, "products": [ { @@ -72,7 +1333,7 @@ }, { "vulnerability": { - "name": "CVE-2026-52909" + "name": "CVE-2026-68451" }, "products": [ { @@ -85,7 +1346,7 @@ }, { "vulnerability": { - "name": "CVE-2026-52910" + "name": "CVE-2026-68470" }, "products": [ { @@ -98,7 +1359,7 @@ }, { "vulnerability": { - "name": "CVE-2026-52924" + "name": "CVE-2026-72003" }, "products": [ { @@ -111,7 +1372,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53145" + "name": "CVE-2026-72024" }, "products": [ { @@ -124,7 +1385,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53148" + "name": "CVE-2026-72110" }, "products": [ { @@ -137,7 +1398,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53151" + "name": "CVE-2026-72111" }, "products": [ { @@ -150,7 +1411,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53153" + "name": "CVE-2026-72123" }, "products": [ { @@ -163,7 +1424,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53159" + "name": "CVE-2026-72124" }, "products": [ { @@ -176,7 +1437,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53170" + "name": "CVE-2026-72135" }, "products": [ { @@ -189,7 +1450,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53171" + "name": "CVE-2026-72151" }, "products": [ { @@ -202,7 +1463,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53172" + "name": "CVE-2026-72195" }, "products": [ { @@ -215,7 +1476,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53173" + "name": "CVE-2026-72287" }, "products": [ { @@ -228,7 +1489,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53175" + "name": "CVE-2026-72288" }, "products": [ { @@ -241,7 +1502,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53176" + "name": "CVE-2026-72331" }, "products": [ { @@ -254,7 +1515,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53178" + "name": "CVE-2026-72338" }, "products": [ { @@ -267,7 +1528,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53182" + "name": "CVE-2026-72372" }, "products": [ { @@ -280,7 +1541,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53183" + "name": "CVE-2026-72390" }, "products": [ { @@ -293,7 +1554,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53185" + "name": "CVE-2026-72461" }, "products": [ { @@ -306,7 +1567,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53186" + "name": "CVE-2026-72462" }, "products": [ { @@ -319,7 +1580,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53192" + "name": "CVE-2026-72472" }, "products": [ { @@ -332,7 +1593,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53193" + "name": "CVE-2026-72478" }, "products": [ { @@ -345,7 +1606,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53196" + "name": "CVE-2026-74268" }, "products": [ { @@ -358,7 +1619,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53198" + "name": "CVE-2026-74317" }, "products": [ { @@ -371,7 +1632,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53212" + "name": "CVE-2026-74334" }, "products": [ { @@ -384,7 +1645,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53224" + "name": "CVE-2026-74341" }, "products": [ { @@ -397,7 +1658,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53235" + "name": "CVE-2026-74363" }, "products": [ { @@ -410,7 +1671,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53239" + "name": "CVE-2026-74378" }, "products": [ { @@ -423,7 +1684,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53240" + "name": "CVE-2026-74390" }, "products": [ { @@ -436,7 +1697,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53250" + "name": "CVE-2026-74394" }, "products": [ { @@ -449,7 +1710,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53254" + "name": "CVE-2026-74411" }, "products": [ { @@ -462,7 +1723,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53256" + "name": "CVE-2026-74427" }, "products": [ { @@ -475,7 +1736,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53259" + "name": "CVE-2026-74438" }, "products": [ { @@ -488,7 +1749,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53262" + "name": "CVE-2026-74446" }, "products": [ { @@ -501,7 +1762,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53264" + "name": "CVE-2026-74465" }, "products": [ { @@ -514,7 +1775,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53266" + "name": "CVE-2026-74470" }, "products": [ { @@ -527,7 +1788,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53269" + "name": "CVE-2026-74506" }, "products": [ { @@ -540,7 +1801,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53270" + "name": "CVE-2026-74510" }, "products": [ { @@ -553,7 +1814,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53275" + "name": "CVE-2026-74529" }, "products": [ { @@ -566,7 +1827,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53276" + "name": "CVE-2026-74534" }, "products": [ { @@ -579,7 +1840,7 @@ }, { "vulnerability": { - "name": "CVE-2026-53359" + "name": "CVE-2026-74535" }, "products": [ { @@ -592,7 +1853,241 @@ }, { "vulnerability": { - "name": "CVE-2026-64531" + "name": "CVE-2026-80631" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-80634" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-80637" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-80644" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-80665" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-80668" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-80671" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-80681" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-80683" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-80691" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-80692" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-80693" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-80700" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-80702" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-80710" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-80714" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-80716" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-80718" + }, + "products": [ + { + "@id": "pkg:deb/ubuntu/linux-libc-dev@7.0.0-29.29?arch=amd64&distro=ubuntu-26.04" + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_present", + "impact_statement": "linux-libc-dev is present only in the ephemeral Dapper builder as user-space API headers pulled by libc6-dev for GCC and Go race tests. The builder contains no Linux kernel image or module package and is never shipped or run as the product. The shipped archive contains one statically linked, CGO-disabled Go binary whose raw Trivy scan reports zero Critical or High findings." + }, + { + "vulnerability": { + "name": "CVE-2026-80721" }, "products": [ { diff --git a/server/auth_server.go b/server/auth_server.go index 324d76c..f92b090 100644 --- a/server/auth_server.go +++ b/server/auth_server.go @@ -17,6 +17,7 @@ import ( "github.com/PastureStack/authentication-service/model" "github.com/PastureStack/authentication-service/providers" + "github.com/PastureStack/authentication-service/providers/oidc" "github.com/PastureStack/authentication-service/providers/shibboleth" "github.com/PastureStack/authentication-service/util" "github.com/golang-jwt/jwt/v5" @@ -472,26 +473,34 @@ func updateSettings(saveConfig map[string]map[string]string, secretSettings []st func updateCommonSettings(settings map[string]string) error { for key, value := range settings { - if value != "" { - log.Debugf("Updating platform setting %v", key) - setting, err := PlatformClient.Setting.ById(key) - if err != nil { - log.Errorf("Error getting the setting %v , error: %v", key, err) - return err - } + if !shouldUpdateCommonSetting(key, value) { + continue + } + log.Debugf("Updating platform setting %v", key) + setting, err := PlatformClient.Setting.ById(key) + if err != nil { + log.Errorf("Error getting the setting %v , error: %v", key, err) + return err + } - setting, err = PlatformClient.Setting.Update(setting, &client.Setting{ - Value: value, - }) - if err != nil { - log.Errorf("Error updating the setting %v: %v", key, err) - return err - } + setting, err = PlatformClient.Setting.Update(setting, &client.Setting{ + Value: value, + }) + if err != nil { + log.Errorf("Error updating the setting %v: %v", key, err) + return err } } return nil } +func shouldUpdateCommonSetting(key string, value string) bool { + // Preserve the historical "empty means unchanged" behavior for all common + // settings except the OIDC allowlist. An unrestricted policy must be able + // to persist an explicit empty allowlist instead of retaining stale entries. + return value != "" || key == allowedIdentitiesSetting +} + func getAllowedIDString(allowedIdentities []client.Identity, separator string) string { if len(allowedIdentities) > 0 { var idArray []string @@ -542,21 +551,67 @@ func getAllowedIdentities(idString string, accessToken string, separator string) // UpdateConfig updates the config in DB func UpdateConfig(authConfig model.AuthConfig) error { - if authConfig.Enabled && strings.EqualFold(authConfig.Provider, "oidcconfig") { - settings, err := readCommonSettings([]string{ - localRecoveryEnabledSetting, - localRecoveryVerifiedAtSetting, - localRecoveryMFAReadySetting, - }) + return UpdateConfigWithRequest(authConfig, ConfigUpdateRequest{}) +} + +// UpdateConfigWithRequest updates the configuration and carries the current +// administrator's proof only when a policy expansion needs bound MFA. +func UpdateConfigWithRequest(authConfig model.AuthConfig, updateRequest ConfigUpdateRequest) error { + // A security confirmation is request-scoped proof. Remove it from the + // configuration object before any provider, persistence, reload, or + // in-memory path can observe it, and keep only the local value needed for + // the bound consume call below. + securityConfirmation := detachSecurityConfirmation(&authConfig) + preparedProviderConfig := false + if strings.EqualFold(authConfig.Provider, oidcProviderName) { + currentConfig, err := GetConfig("", false) + if err != nil { + return errors.Wrap(err, "UpdateConfig: Could not read the current authentication configuration") + } + if err := prepareProviderConfig(&authConfig); err != nil { + return err + } + preparedProviderConfig = true + if err := normalizeOIDCAccessPolicy(&authConfig, true); err != nil { + return err + } + oidc.NormalizeConfig(&authConfig.OIDCConfig) + plan, err := planOIDCConfigUpdate(currentConfig, authConfig) if err != nil { - return errors.Wrap(err, "UpdateConfig: Could not verify local administrator recovery") + return err + } + if plan.RequiresLocalRecovery { + settings, err := readCommonSettings([]string{ + localRecoveryEnabledSetting, + localRecoveryVerifiedAtSetting, + localRecoveryMFAReadySetting, + }) + if err != nil { + return errors.Wrap(err, "UpdateConfig: Could not verify local administrator recovery") + } + if !localRecoveryReady(settings, time.Now()) { + return &ConfigUpdateError{ + HTTPStatus: http.StatusForbidden, + Code: configErrorLocalRecovery, + Message: "Verify an active local system-administrator account within five minutes before changing the OpenID Connect identity source", + } + } + } + if plan.PermissionExpansion { + if err := requireBoundSecurityConfirmation(updateRequest, + securityConfirmation, plan.RequestDigest); err != nil { + return err + } } - if !localRecoveryReady(settings, time.Now()) { - return fmt.Errorf("verify an active local system-administrator account within five minutes before activating OpenID Connect") + if plan.SameProvider && !plan.RequiresProviderInitialization { + return updateOIDCConfigWithoutInitialization(currentConfig, authConfig) } } - if err := prepareProviderConfig(&authConfig); err != nil { - return err + + if !preparedProviderConfig { + if err := prepareProviderConfig(&authConfig); err != nil { + return err + } } newProvider, err := initProviderWithConfig(&authConfig) @@ -629,6 +684,68 @@ func UpdateConfig(authConfig model.AuthConfig) error { return nil } +func detachSecurityConfirmation(authConfig *model.AuthConfig) string { + securityConfirmation := authConfig.SecurityConfirmation + authConfig.SecurityConfirmation = "" + return securityConfirmation +} + +func updateOIDCConfigWithoutInitialization(currentConfig model.AuthConfig, authConfig model.AuthConfig) error { + newProvider, err := providers.GetProvider(authConfig.Provider) + if err != nil || newProvider == nil { + if err != nil { + return err + } + return fmt.Errorf("Could not get the %s auth provider", authConfig.Provider) + } + + currentOIDCConfig := currentConfig.OIDCConfig + oidc.NormalizeConfig(¤tOIDCConfig) + if currentOIDCConfig.DisplayName != authConfig.OIDCConfig.DisplayName { + genObjConfig := map[string]map[string]string{ + newProvider.GetName(): oidc.SettingsForConfig(authConfig.OIDCConfig), + } + if err := updateSettings(genObjConfig, newProvider.GetProviderSecretSettings(), + newProvider.GetName(), authConfig.Enabled); err != nil { + return errors.Wrap(err, "UpdateConfig: Error storing OpenID Connect display settings") + } + } + + orderedSettings := []struct { + key string + value string + }{ + {allowedIdentitiesSetting, getAllowedIDString(authConfig.AllowedIdentities, newProvider.GetIdentitySeparator())}, + {accessModeSetting, authConfig.AccessMode}, + {securitySetting, strconv.FormatBool(authConfig.Enabled)}, + {authServiceConfigUpdateTimestamp, time.Now().String()}, + } + for _, setting := range orderedSettings { + if err := updateCommonSettings(map[string]string{setting.key: setting.value}); err != nil { + return errors.Wrap(err, "UpdateConfig: Error storing OpenID Connect access policy") + } + } + updateOIDCConfigInMemory(authConfig) + return nil +} + +func updateOIDCConfigInMemory(authConfig model.AuthConfig) { + if refreshReqChannel == nil { + authConfigInMemory = authConfig + return + } + for { + select { + case *refreshReqChannel <- 1: + authConfigInMemory = authConfig + <-*refreshReqChannel + return + default: + time.Sleep(30 * time.Millisecond) + } + } +} + func localRecoveryReady(settings map[string]string, now time.Time) bool { if !strings.EqualFold(settings[localRecoveryEnabledSetting], "true") { return false diff --git a/server/config_update_policy.go b/server/config_update_policy.go new file mode 100644 index 0000000..e2db702 --- /dev/null +++ b/server/config_update_policy.go @@ -0,0 +1,321 @@ +package server + +import ( + "bytes" + "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "sort" + "strings" + "time" + + "github.com/PastureStack/authentication-service/model" + "github.com/PastureStack/authentication-service/providers/oidc" + "github.com/rancher/go-rancher/v2" +) + +const ( + oidcProviderName = "oidcconfig" + oidcAccessPolicyUpdatePurpose = "oidcAccessPolicyUpdate" + configErrorLocalRecovery = "LocalRecoveryRequired" + configErrorMFAConfirmation = "MfaConfirmationRequired" + configErrorMFAUnavailable = "MfaConfirmationUnavailable" + configErrorInvalidAccessMode = "InvalidAccessMode" + configErrorInvalidIdentity = "InvalidAllowedIdentity" + securityConfirmationBodyLimit = 1 << 20 + securityConfirmationRequestTime = 10 * time.Second +) + +var validOIDCAccessModes = map[string]bool{ + "unrestricted": true, + "restricted": true, + "required": true, +} + +var validOIDCIdentityTypes = map[string]bool{ + "oidc_user": true, + "oidc_group": true, +} + +// ConfigUpdateRequest contains only the caller proof needed to consume a +// one-time security confirmation. Authentication material is never persisted. +type ConfigUpdateRequest struct { + Context context.Context + Authorization string + Cookie string + HTTPClient *http.Client +} + +// ConfigUpdateError is returned to clients with a stable machine-readable +// code. RequestDigest is present only when the client must complete MFA for +// this exact normalized access-policy request. +type ConfigUpdateError struct { + HTTPStatus int + Code string + Message string + RequestDigest string +} + +func (e *ConfigUpdateError) Error() string { + return e.Message +} + +type oidcConfigUpdatePlan struct { + SameProvider bool + SourceChanged bool + InitialEnable bool + RequiresLocalRecovery bool + RequiresProviderInitialization bool + PermissionExpansion bool + RequestDigest string +} + +type canonicalOIDCIdentity struct { + ExternalIDType string `json:"externalIdType"` + ExternalID string `json:"externalId"` +} + +type canonicalOIDCAccessPolicy struct { + Provider string `json:"provider"` + Enabled bool `json:"enabled"` + AccessMode string `json:"accessMode"` + AllowedIdentities []canonicalOIDCIdentity `json:"allowedIdentities"` +} + +func normalizeOIDCAccessPolicy(config *model.AuthConfig, strict bool) error { + config.AccessMode = strings.ToLower(strings.TrimSpace(config.AccessMode)) + if !validOIDCAccessModes[config.AccessMode] { + if !strict && config.AccessMode == "" { + config.AccessMode = "restricted" + } else { + return &ConfigUpdateError{ + HTTPStatus: http.StatusUnprocessableEntity, + Code: configErrorInvalidAccessMode, + Message: "OpenID Connect accessMode must be unrestricted, restricted, or required", + } + } + } + + if config.AccessMode == "unrestricted" { + config.AllowedIdentities = []client.Identity{} + return nil + } + + separator := "#oidc#" + seen := make(map[string]bool) + normalized := make([]client.Identity, 0, len(config.AllowedIdentities)) + for _, identity := range config.AllowedIdentities { + identityType := strings.TrimSpace(identity.ExternalIdType) + externalID := strings.TrimSpace(identity.ExternalId) + if !validOIDCIdentityTypes[identityType] || externalID == "" || strings.Contains(externalID, separator) { + if !strict { + continue + } + return &ConfigUpdateError{ + HTTPStatus: http.StatusUnprocessableEntity, + Code: configErrorInvalidIdentity, + Message: "OpenID Connect allowed identities must be non-empty oidc_user or oidc_group values", + } + } + + key := identityType + "\x00" + externalID + if seen[key] { + continue + } + seen[key] = true + identity.ExternalIdType = identityType + identity.ExternalId = externalID + identity.Resource.Id = identityType + ":" + externalID + normalized = append(normalized, identity) + } + config.AllowedIdentities = normalized + return nil +} + +func planOIDCConfigUpdate(current model.AuthConfig, requested model.AuthConfig) (oidcConfigUpdatePlan, error) { + if err := normalizeOIDCAccessPolicy(¤t, false); err != nil { + return oidcConfigUpdatePlan{}, err + } + if err := normalizeOIDCAccessPolicy(&requested, true); err != nil { + return oidcConfigUpdatePlan{}, err + } + oidc.NormalizeConfig(¤t.OIDCConfig) + oidc.NormalizeConfig(&requested.OIDCConfig) + + sameProvider := strings.EqualFold(current.Provider, oidcProviderName) && + strings.EqualFold(requested.Provider, oidcProviderName) + sourceChanged := !sameProvider || oidcIdentitySourceChanged(current.OIDCConfig, requested.OIDCConfig) + initialEnable := requested.Enabled && (!current.Enabled || !sameProvider) + permissionExpansion := current.Enabled && requested.Enabled && sameProvider && + oidcAccessPolicyExpands(current, requested) + digest, err := oidcAccessPolicyDigest(requested) + if err != nil { + return oidcConfigUpdatePlan{}, err + } + + return oidcConfigUpdatePlan{ + SameProvider: sameProvider, + SourceChanged: sourceChanged, + InitialEnable: initialEnable, + RequiresLocalRecovery: initialEnable || sourceChanged, + RequiresProviderInitialization: initialEnable || sourceChanged, + PermissionExpansion: permissionExpansion, + RequestDigest: digest, + }, nil +} + +func oidcIdentitySourceChanged(current model.OIDCConfig, requested model.OIDCConfig) bool { + return current.WellKnownURL != requested.WellKnownURL || + current.ClientID != requested.ClientID || + current.ClientSecret != requested.ClientSecret || + current.Scopes != requested.Scopes || + current.UsePKCE != requested.UsePKCE || + current.UsernameClaim != requested.UsernameClaim || + current.DisplayNameClaim != requested.DisplayNameClaim || + current.EmailClaim != requested.EmailClaim || + current.GroupsClaim != requested.GroupsClaim || + current.CertificateAuthority != requested.CertificateAuthority +} + +func oidcAccessPolicyExpands(current model.AuthConfig, requested model.AuthConfig) bool { + if current.AccessMode == "unrestricted" { + return false + } + if requested.AccessMode == "unrestricted" || + (current.AccessMode == "required" && requested.AccessMode == "restricted") { + return true + } + + currentIdentities := make(map[string]bool, len(current.AllowedIdentities)) + for _, identity := range current.AllowedIdentities { + currentIdentities[identity.ExternalIdType+"\x00"+identity.ExternalId] = true + } + for _, identity := range requested.AllowedIdentities { + if !currentIdentities[identity.ExternalIdType+"\x00"+identity.ExternalId] { + return true + } + } + return false +} + +func oidcAccessPolicyDigest(config model.AuthConfig) (string, error) { + identities := make([]canonicalOIDCIdentity, 0, len(config.AllowedIdentities)) + for _, identity := range config.AllowedIdentities { + identities = append(identities, canonicalOIDCIdentity{ + ExternalIDType: identity.ExternalIdType, + ExternalID: identity.ExternalId, + }) + } + sort.Slice(identities, func(i, j int) bool { + if identities[i].ExternalIDType == identities[j].ExternalIDType { + return identities[i].ExternalID < identities[j].ExternalID + } + return identities[i].ExternalIDType < identities[j].ExternalIDType + }) + payload, err := json.Marshal(canonicalOIDCAccessPolicy{ + Provider: strings.ToLower(config.Provider), + Enabled: config.Enabled, + AccessMode: config.AccessMode, + AllowedIdentities: identities, + }) + if err != nil { + return "", fmt.Errorf("failed to encode the OpenID Connect access policy: %w", err) + } + digest := sha256.Sum256(payload) + return hex.EncodeToString(digest[:]), nil +} + +func requireBoundSecurityConfirmation(request ConfigUpdateRequest, confirmation string, digest string) error { + if strings.TrimSpace(confirmation) == "" { + return mfaConfirmationRequired(digest) + } + + endpoint, err := platformEndpoint("/v2-beta/mfaOperation") + if err != nil { + return &ConfigUpdateError{ + HTTPStatus: http.StatusBadGateway, + Code: configErrorMFAUnavailable, + Message: "The MFA confirmation service is unavailable", + } + } + body, err := json.Marshal(map[string]string{ + "operation": "consumeSecurityConfirmation", + "securityConfirmation": confirmation, + "purpose": oidcAccessPolicyUpdatePurpose, + "requestDigest": digest, + }) + if err != nil { + return err + } + + ctx := request.Context + if ctx == nil { + ctx = context.Background() + } + ctx, cancel := context.WithTimeout(ctx, securityConfirmationRequestTime) + defer cancel() + httpRequest, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, bytes.NewReader(body)) + if err != nil { + return err + } + httpRequest.Header.Set("Content-Type", "application/json") + if request.Authorization != "" { + httpRequest.Header.Set("Authorization", request.Authorization) + } + if request.Cookie != "" { + httpRequest.Header.Set("Cookie", request.Cookie) + } + + httpClient := request.HTTPClient + if httpClient == nil { + httpClient = &http.Client{Timeout: securityConfirmationRequestTime} + } + response, err := httpClient.Do(httpRequest) + if err != nil { + return &ConfigUpdateError{ + HTTPStatus: http.StatusBadGateway, + Code: configErrorMFAUnavailable, + Message: "The MFA confirmation service is unavailable", + } + } + defer response.Body.Close() + _, _ = io.Copy(io.Discard, io.LimitReader(response.Body, securityConfirmationBodyLimit)) + if response.StatusCode >= 200 && response.StatusCode < 300 { + return nil + } + if response.StatusCode == http.StatusUnauthorized || response.StatusCode == http.StatusForbidden || + response.StatusCode == http.StatusUnprocessableEntity { + return mfaConfirmationRequired(digest) + } + return &ConfigUpdateError{ + HTTPStatus: http.StatusBadGateway, + Code: configErrorMFAUnavailable, + Message: "The MFA confirmation service is unavailable", + } +} + +func mfaConfirmationRequired(digest string) error { + return &ConfigUpdateError{ + HTTPStatus: http.StatusForbidden, + Code: configErrorMFAConfirmation, + Message: "A one-time MFA confirmation is required to expand OpenID Connect access", + RequestDigest: digest, + } +} + +func platformEndpoint(path string) (string, error) { + parsed, err := url.Parse(PlatformURL) + if err != nil || parsed.Scheme == "" || parsed.Host == "" { + return "", fmt.Errorf("invalid platform URL") + } + parsed.Path = path + parsed.RawPath = "" + parsed.RawQuery = "" + parsed.Fragment = "" + return parsed.String(), nil +} diff --git a/server/config_update_policy_test.go b/server/config_update_policy_test.go new file mode 100644 index 0000000..bca88d0 --- /dev/null +++ b/server/config_update_policy_test.go @@ -0,0 +1,444 @@ +package server + +import ( + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "strconv" + "strings" + "testing" + "time" + + "github.com/PastureStack/authentication-service/model" + "github.com/rancher/go-rancher/v2" +) + +func TestOIDCPolicyOnlyUpdateSkipsRecoveryAndProviderInitialization(t *testing.T) { + current := oidcConfigForPolicyTest(true, "required", oidcIdentity("oidc_user", "alice")) + requested := current + requested.AccessMode = "restricted" + + plan, err := planOIDCConfigUpdate(current, requested) + if err != nil { + t.Fatal(err) + } + if plan.RequiresLocalRecovery || plan.RequiresProviderInitialization { + t.Fatalf("policy-only update unexpectedly required recovery or provider initialization: %#v", plan) + } + if !plan.PermissionExpansion { + t.Fatal("required to restricted is an access expansion and must require bound MFA") + } +} + +func TestExpiredLocalRecoveryOnlyBlocksIdentitySourceChanges(t *testing.T) { + now := time.UnixMilli(1_800_000_000_000) + expiredRecovery := map[string]string{ + localRecoveryEnabledSetting: "true", + localRecoveryMFAReadySetting: "true", + localRecoveryVerifiedAtSetting: strconv.FormatInt(now.Add(-6*time.Minute).UnixMilli(), 10), + } + if localRecoveryReady(expiredRecovery, now) { + t.Fatal("a six-minute-old local recovery verification was accepted") + } + + current := oidcConfigForPolicyTest(true, "restricted", oidcIdentity("oidc_user", "alice")) + policyOnly := current + policyOnly.AllowedIdentities = append(policyOnly.AllowedIdentities, + oidcIdentity("oidc_group", "operators")) + policyPlan, err := planOIDCConfigUpdate(current, policyOnly) + if err != nil { + t.Fatal(err) + } + if policyPlan.RequiresLocalRecovery || policyPlan.RequiresProviderInitialization { + t.Fatalf("an expired recovery incorrectly blocked a policy-only update: %#v", policyPlan) + } + + sourceChange := current + sourceChange.OIDCConfig.ClientID = "replacement-client" + sourcePlan, err := planOIDCConfigUpdate(current, sourceChange) + if err != nil { + t.Fatal(err) + } + if !sourcePlan.RequiresLocalRecovery || !sourcePlan.RequiresProviderInitialization { + t.Fatalf("an identity-source change bypassed expired-recovery enforcement: %#v", sourcePlan) + } +} + +func TestOIDCIdentitySourceChangesRequireRecoveryAndInitialization(t *testing.T) { + base := oidcConfigForPolicyTest(true, "restricted", oidcIdentity("oidc_user", "alice")) + tests := []struct { + name string + change func(*model.AuthConfig) + }{ + {"well-known URL", func(config *model.AuthConfig) { + config.OIDCConfig.WellKnownURL = "https://new.example/.well-known/openid-configuration" + }}, + {"client ID", func(config *model.AuthConfig) { config.OIDCConfig.ClientID = "new-client" }}, + {"client secret", func(config *model.AuthConfig) { config.OIDCConfig.ClientSecret = "new-secret" }}, + {"certificate authority", func(config *model.AuthConfig) { config.OIDCConfig.CertificateAuthority = "new-ca" }}, + {"scope", func(config *model.AuthConfig) { config.OIDCConfig.Scopes = "openid email groups" }}, + {"PKCE", func(config *model.AuthConfig) { config.OIDCConfig.UsePKCE = false }}, + {"username claim", func(config *model.AuthConfig) { config.OIDCConfig.UsernameClaim = "preferred_username" }}, + {"display-name claim", func(config *model.AuthConfig) { config.OIDCConfig.DisplayNameClaim = "display_name" }}, + {"email claim", func(config *model.AuthConfig) { config.OIDCConfig.EmailClaim = "mail" }}, + {"groups claim", func(config *model.AuthConfig) { config.OIDCConfig.GroupsClaim = "roles" }}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + requested := base + test.change(&requested) + plan, err := planOIDCConfigUpdate(base, requested) + if err != nil { + t.Fatal(err) + } + if !plan.SourceChanged || !plan.RequiresLocalRecovery || !plan.RequiresProviderInitialization { + t.Fatalf("identity-source change was not gated: %#v", plan) + } + }) + } +} + +func TestDisabledOIDCIdentitySourceChangeStillRequiresRecovery(t *testing.T) { + current := oidcConfigForPolicyTest(false, "restricted", oidcIdentity("oidc_user", "alice")) + requested := current + requested.OIDCConfig.ClientID = "replacement-client" + + plan, err := planOIDCConfigUpdate(current, requested) + if err != nil { + t.Fatal(err) + } + if !plan.SourceChanged || !plan.RequiresLocalRecovery || !plan.RequiresProviderInitialization { + t.Fatalf("disabled identity-source change bypassed the recovery gate: %#v", plan) + } +} + +func TestOIDCInitialEnableAndProviderSwitchRequireRecovery(t *testing.T) { + requested := oidcConfigForPolicyTest(true, "restricted", oidcIdentity("oidc_user", "alice")) + for name, current := range map[string]model.AuthConfig{ + "initial enable": oidcConfigForPolicyTest(false, "restricted", oidcIdentity("oidc_user", "alice")), + "provider switch": {Provider: "githubconfig", Enabled: true, AccessMode: "restricted"}, + } { + t.Run(name, func(t *testing.T) { + plan, err := planOIDCConfigUpdate(current, requested) + if err != nil { + t.Fatal(err) + } + if !plan.InitialEnable || !plan.RequiresLocalRecovery || !plan.RequiresProviderInitialization { + t.Fatalf("activation was not gated: %#v", plan) + } + }) + } +} + +func TestOIDCDisplayNameUpdateDoesNotInitializeProvider(t *testing.T) { + current := oidcConfigForPolicyTest(true, "restricted", oidcIdentity("oidc_user", "alice")) + requested := current + requested.OIDCConfig.DisplayName = "Company login" + plan, err := planOIDCConfigUpdate(current, requested) + if err != nil { + t.Fatal(err) + } + if plan.SourceChanged || plan.RequiresProviderInitialization || plan.RequiresLocalRecovery { + t.Fatalf("display-only update was treated as an identity-source change: %#v", plan) + } +} + +func TestOIDCAccessExpansionRequiresMFAWhileContractionDoesNot(t *testing.T) { + alice := oidcIdentity("oidc_user", "alice") + operators := oidcIdentity("oidc_group", "operators") + tests := []struct { + name string + current model.AuthConfig + requested model.AuthConfig + expands bool + }{ + { + name: "add an allowed group", + current: oidcConfigForPolicyTest(true, "restricted", alice), + requested: oidcConfigForPolicyTest(true, "restricted", alice, operators), + expands: true, + }, + { + name: "switch to unrestricted", + current: oidcConfigForPolicyTest(true, "restricted", alice), + requested: oidcConfigForPolicyTest(true, "unrestricted"), + expands: true, + }, + { + name: "remove an allowed group", + current: oidcConfigForPolicyTest(true, "restricted", alice, operators), + requested: oidcConfigForPolicyTest(true, "restricted", alice), + expands: false, + }, + { + name: "tighten restricted to required", + current: oidcConfigForPolicyTest(true, "restricted", alice), + requested: oidcConfigForPolicyTest(true, "required", alice), + expands: false, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + plan, err := planOIDCConfigUpdate(test.current, test.requested) + if err != nil { + t.Fatal(err) + } + if plan.PermissionExpansion != test.expands { + t.Fatalf("PermissionExpansion = %v, expected %v: %#v", + plan.PermissionExpansion, test.expands, plan) + } + }) + } +} + +func TestNormalizeOIDCAccessPolicyClearsUnrestrictedAndDeduplicatesRestricted(t *testing.T) { + unrestricted := oidcConfigForPolicyTest(true, " unrestricted ", + oidcIdentity("oidc_user", "alice"), oidcIdentity("oidc_group", "operators")) + if err := normalizeOIDCAccessPolicy(&unrestricted, true); err != nil { + t.Fatal(err) + } + if unrestricted.AllowedIdentities == nil || len(unrestricted.AllowedIdentities) != 0 { + t.Fatalf("unrestricted policy retained identities: %#v", unrestricted.AllowedIdentities) + } + + restricted := oidcConfigForPolicyTest(true, "restricted", + oidcIdentity("oidc_user", "alice"), oidcIdentity(" oidc_user ", " alice "), + oidcIdentity("oidc_group", "operators")) + if err := normalizeOIDCAccessPolicy(&restricted, true); err != nil { + t.Fatal(err) + } + if len(restricted.AllowedIdentities) != 2 { + t.Fatalf("duplicate identities were not removed: %#v", restricted.AllowedIdentities) + } +} + +func TestNormalizeOIDCAccessPolicyRejectsIllegalIdentityTypes(t *testing.T) { + for _, identity := range []client.Identity{ + oidcIdentity("github_user", "alice"), + oidcIdentity("oidc_user", ""), + oidcIdentity("oidc_group", "bad#oidc#value"), + } { + config := oidcConfigForPolicyTest(true, "restricted", identity) + err := normalizeOIDCAccessPolicy(&config, true) + assertConfigUpdateError(t, err, configErrorInvalidIdentity) + } +} + +func TestOnlyTheAllowedIdentitySettingAcceptsAnExplicitEmptyValue(t *testing.T) { + if !shouldUpdateCommonSetting(allowedIdentitiesSetting, "") { + t.Fatal("the OIDC allowlist cannot be explicitly cleared") + } + if shouldUpdateCommonSetting(accessModeSetting, "") || + shouldUpdateCommonSetting(providerSetting, "") { + t.Fatal("unrelated common settings lost their historical empty-means-unchanged behavior") + } +} + +func TestOIDCAccessPolicyDigestIsStableForIdentityOrder(t *testing.T) { + first := oidcConfigForPolicyTest(true, "restricted", + oidcIdentity("oidc_user", "alice"), oidcIdentity("oidc_group", "operators")) + second := oidcConfigForPolicyTest(true, "restricted", + oidcIdentity("oidc_group", "operators"), oidcIdentity("oidc_user", "alice")) + firstDigest, err := oidcAccessPolicyDigest(first) + if err != nil { + t.Fatal(err) + } + secondDigest, err := oidcAccessPolicyDigest(second) + if err != nil { + t.Fatal(err) + } + if firstDigest != secondDigest || len(firstDigest) != 64 { + t.Fatalf("policy digest was not canonical: %q != %q", firstDigest, secondDigest) + } +} + +func TestBoundSecurityConfirmationForwardsActorAndExactDigest(t *testing.T) { + digest := strings.Repeat("a", 64) + server := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) { + if request.URL.Path != "/v2-beta/mfaOperation" { + t.Errorf("unexpected MFA path %q", request.URL.Path) + } + if request.Header.Get("Authorization") != "Bearer actor-token" || + request.Header.Get("Cookie") != "token=actor-cookie" { + t.Errorf("actor credentials were not forwarded") + } + var payload map[string]string + if err := json.NewDecoder(request.Body).Decode(&payload); err != nil { + t.Fatal(err) + } + if payload["operation"] != "consumeSecurityConfirmation" || + payload["purpose"] != oidcAccessPolicyUpdatePurpose || + payload["requestDigest"] != digest || payload["securityConfirmation"] != "ticket" { + t.Errorf("unexpected MFA consume payload: %#v", payload) + } + response.WriteHeader(http.StatusCreated) + })) + defer server.Close() + + previousPlatformURL := PlatformURL + PlatformURL = server.URL + "/v1" + defer func() { PlatformURL = previousPlatformURL }() + err := requireBoundSecurityConfirmation(ConfigUpdateRequest{ + Authorization: "Bearer actor-token", + Cookie: "token=actor-cookie", + HTTPClient: server.Client(), + }, "ticket", digest) + if err != nil { + t.Fatal(err) + } +} + +func TestBoundSecurityConfirmationReturnsStableChallenge(t *testing.T) { + digest := strings.Repeat("b", 64) + err := requireBoundSecurityConfirmation(ConfigUpdateRequest{}, "", digest) + updateError := assertConfigUpdateError(t, err, configErrorMFAConfirmation) + if updateError.RequestDigest != digest || updateError.HTTPStatus != http.StatusForbidden { + t.Fatalf("missing exact policy digest in MFA challenge: %#v", updateError) + } +} + +func TestSecurityConfirmationIsRemovedBeforeAnyProviderFlow(t *testing.T) { + config := oidcConfigForPolicyTest(true, "restricted", oidcIdentity("oidc_user", "alice")) + config.SecurityConfirmation = "one-time-ticket" + + confirmation := detachSecurityConfirmation(&config) + + if confirmation != "one-time-ticket" { + t.Fatalf("request-scoped confirmation was not captured: %q", confirmation) + } + if config.SecurityConfirmation != "" { + t.Fatal("request-scoped confirmation remained on the persistable configuration") + } +} + +func TestPolicyOnlyUpdateClearsStoredAllowlistWithoutDiscovery(t *testing.T) { + discoveryRequests := 0 + discoveryServer := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) { + discoveryRequests++ + response.WriteHeader(http.StatusInternalServerError) + })) + defer discoveryServer.Close() + + settings := map[string]string{ + allowedIdentitiesSetting: "oidc_user:alice#oidc#oidc_group:operators", + accessModeSetting: "restricted", + securitySetting: "true", + } + var writes []string + var platformServer *httptest.Server + platformServer = httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) { + response.Header().Set("Content-Type", "application/json") + if request.Method == http.MethodGet && request.URL.Path == "/v2-beta" { + response.Header().Set("X-API-Schemas", platformServer.URL+"/v2-beta") + _, _ = fmt.Fprintf(response, `{"data":[{"id":"setting","type":"schema","pluralName":"settings","collectionMethods":["GET"],"resourceMethods":["GET","PUT"],"links":{"collection":%q}}]}`, + platformServer.URL+"/v2-beta/settings") + return + } + prefix := "/v2-beta/settings/" + if !strings.HasPrefix(request.URL.Path, prefix) { + http.Error(response, "unexpected platform path", http.StatusNotFound) + return + } + name := strings.TrimPrefix(request.URL.Path, prefix) + if request.Method == http.MethodGet { + _, _ = fmt.Fprintf(response, `{"id":%q,"type":"setting","activeValue":%q,"value":%q,"links":{"self":%q}}`, + name, settings[name], settings[name], platformServer.URL+request.URL.Path) + return + } + if request.Method == http.MethodPut { + var update struct { + Value string `json:"value"` + } + if err := json.NewDecoder(request.Body).Decode(&update); err != nil { + t.Fatal(err) + } + settings[name] = update.Value + writes = append(writes, name) + _, _ = fmt.Fprintf(response, `{"id":%q,"type":"setting","activeValue":%q,"value":%q,"links":{"self":%q}}`, + name, update.Value, update.Value, platformServer.URL+request.URL.Path) + return + } + http.Error(response, "unexpected platform method", http.StatusMethodNotAllowed) + })) + defer platformServer.Close() + + platformClient, err := newPlatformClient(platformServer.URL, "access", "secret") + if err != nil { + t.Fatal(err) + } + previousPlatformClient := PlatformClient + previousRefreshChannel := refreshReqChannel + previousConfig := authConfigInMemory + PlatformClient = platformClient + refreshReqChannel = nil + defer func() { + PlatformClient = previousPlatformClient + refreshReqChannel = previousRefreshChannel + authConfigInMemory = previousConfig + }() + + current := oidcConfigForPolicyTest(true, "restricted", oidcIdentity("oidc_user", "alice")) + current.OIDCConfig.WellKnownURL = discoveryServer.URL + "/.well-known/openid-configuration" + requested := current + requested.AccessMode = "unrestricted" + requested.AllowedIdentities = []client.Identity{oidcIdentity("oidc_user", "stale")} + if err := normalizeOIDCAccessPolicy(&requested, true); err != nil { + t.Fatal(err) + } + if err := updateOIDCConfigWithoutInitialization(current, requested); err != nil { + t.Fatal(err) + } + + if discoveryRequests != 0 { + t.Fatalf("policy-only update performed %d OIDC discovery requests", discoveryRequests) + } + if settings[allowedIdentitiesSetting] != "" { + t.Fatalf("stored allowlist was not cleared: %q", settings[allowedIdentitiesSetting]) + } + if len(writes) < 2 || writes[0] != allowedIdentitiesSetting || writes[1] != accessModeSetting { + t.Fatalf("allowlist was not cleared before the access mode changed: %#v", writes) + } + reread, err := readCommonSettings([]string{allowedIdentitiesSetting, accessModeSetting}) + if err != nil { + t.Fatal(err) + } + if reread[allowedIdentitiesSetting] != "" || reread[accessModeSetting] != "unrestricted" { + t.Fatalf("stored policy did not round-trip after clearing: %#v", reread) + } +} + +func oidcConfigForPolicyTest(enabled bool, accessMode string, identities ...client.Identity) model.AuthConfig { + return model.AuthConfig{ + Provider: oidcProviderName, + Enabled: enabled, + AccessMode: accessMode, + AllowedIdentities: identities, + OIDCConfig: model.OIDCConfig{ + DisplayName: "Company login", + WellKnownURL: "https://id.example/.well-known/openid-configuration", + ClientID: "client", + ClientSecret: "secret", + ClientSecretSet: true, + Scopes: "openid email", + UsePKCE: true, + UsernameClaim: "username", + DisplayNameClaim: "name", + EmailClaim: "email", + GroupsClaim: "groups", + }, + } +} + +func oidcIdentity(identityType string, externalID string) client.Identity { + return client.Identity{ExternalIdType: identityType, ExternalId: externalID} +} + +func assertConfigUpdateError(t *testing.T, err error, code string) *ConfigUpdateError { + t.Helper() + updateError, ok := err.(*ConfigUpdateError) + if !ok || updateError.Code != code { + t.Fatalf("got error %#v, expected ConfigUpdateError %s", err, code) + } + return updateError +} diff --git a/service/route_handlers.go b/service/route_handlers.go index 8b9bdc4..8cc7afd 100644 --- a/service/route_handlers.go +++ b/service/route_handlers.go @@ -227,9 +227,19 @@ func UpdateConfig(w http.ResponseWriter, r *http.Request) { return } - err = server.UpdateConfig(authConfig) + err = server.UpdateConfigWithRequest(authConfig, server.ConfigUpdateRequest{ + Context: r.Context(), + Authorization: r.Header.Get("Authorization"), + Cookie: r.Header.Get("Cookie"), + }) if err != nil { log.Error("Authentication configuration update failed") + var updateError *server.ConfigUpdateError + if errors.As(err, &updateError) { + returnHTTPError(w, r, updateError.HTTPStatus, updateError.Code, + updateError.Message, updateError.RequestDigest) + return + } ReturnHTTPError(w, r, http.StatusBadRequest, "Bad Request, Please check the request content") return } diff --git a/service/routes.go b/service/routes.go index 27505f0..d90aba5 100644 --- a/service/routes.go +++ b/service/routes.go @@ -81,6 +81,9 @@ func getSchemas() *client.Schemas { authconfig.CollectionMethods = []string{"GET", "POST"} authconfig.ResourceMethods = []string{"GET", "POST"} authconfig.PluralName = "configs" + securityConfirmation := authconfig.ResourceFields["securityConfirmation"] + securityConfirmation.Type = "password" + authconfig.ResourceFields["securityConfirmation"] = securityConfirmation // TestAuthConfig testAuthconfig := schemas.AddType("testAuthConfig", model.TestAuthConfig{}) @@ -114,6 +117,10 @@ func getSchemas() *client.Schemas { // ReturnHTTPError handles sending out CatalogError response func ReturnHTTPError(w http.ResponseWriter, r *http.Request, httpStatus int, errorMessage string) { + returnHTTPError(w, r, httpStatus, "", errorMessage, "") +} + +func returnHTTPError(w http.ResponseWriter, r *http.Request, httpStatus int, code string, errorMessage string, requestDigest string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(httpStatus) @@ -121,8 +128,10 @@ func ReturnHTTPError(w http.ResponseWriter, r *http.Request, httpStatus int, err Resource: client.Resource{ Type: "error", }, - Status: strconv.Itoa(httpStatus), - Message: errorMessage, + Status: strconv.Itoa(httpStatus), + Code: code, + Message: errorMessage, + RequestDigest: requestDigest, } api.CreateApiContext(w, r, schemas) diff --git a/service/routes_test.go b/service/routes_test.go index 37f460c..aa89e94 100644 --- a/service/routes_test.go +++ b/service/routes_test.go @@ -1,6 +1,8 @@ package service import ( + "encoding/json" + "net/http" "net/http/httptest" "strings" "testing" @@ -60,4 +62,25 @@ func TestOIDCSchemaIsRegisteredWithSafeDefaults(t *testing.T) { if clientSecretSet.Create || clientSecretSet.Update { t.Fatal("clientSecretSet must be read-only") } + if field := allSchemas.Schema("config").ResourceFields["securityConfirmation"]; field.Type != "password" { + t.Fatalf("securityConfirmation field type = %q, expected password", field.Type) + } +} + +func TestConfigUpdateErrorIncludesStableCodeAndRequestDigest(t *testing.T) { + schemas = getSchemas() + request := httptest.NewRequest(http.MethodPost, "/v1-auth/config", strings.NewReader("{}")) + response := httptest.NewRecorder() + digest := strings.Repeat("a", 64) + returnHTTPError(response, request, http.StatusForbidden, "MfaConfirmationRequired", + "confirmation required", digest) + + var body map[string]interface{} + if err := json.Unmarshal(response.Body.Bytes(), &body); err != nil { + t.Fatal(err) + } + if response.Code != http.StatusForbidden || body["code"] != "MfaConfirmationRequired" || + body["requestDigest"] != digest { + t.Fatalf("unexpected stable error response: status=%d body=%#v", response.Code, body) + } }