diff --git a/.github/workflows/build-fleetd-base-msi.yml b/.github/workflows/build-fleetd-base-msi.yml index c3149f524d72..4af9e3f6abf6 100644 --- a/.github/workflows/build-fleetd-base-msi.yml +++ b/.github/workflows/build-fleetd-base-msi.yml @@ -83,6 +83,11 @@ jobs: needs: [build, code-sign] runs-on: ubuntu-latest steps: + - name: Harden Runner + uses: step-security/harden-runner@v2 + with: + egress-policy: audit + - name: Download signed artifact uses: actions/download-artifact@9c19ed7fe5d278cd354c7dfd5d3b88589c7e2395 # v4.1.6 with: diff --git a/.github/workflows/dogfood-automated-policy-updates.yml b/.github/workflows/dogfood-automated-policy-updates.yml index 460ae24679b1..57564962154f 100644 --- a/.github/workflows/dogfood-automated-policy-updates.yml +++ b/.github/workflows/dogfood-automated-policy-updates.yml @@ -5,13 +5,21 @@ on: - cron: '0 */6 * * *' # Run every 6 hours workflow_dispatch: # Allow manual trigger +permissions: + contents: read + jobs: update-macos-versions: runs-on: ubuntu-latest steps: + - name: Harden Runner + uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + with: + egress-policy: audit + - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Git run: | diff --git a/.github/workflows/randokiller-go.yml b/.github/workflows/randokiller-go.yml index c89809f09c3d..b4ad83665b26 100644 --- a/.github/workflows/randokiller-go.yml +++ b/.github/workflows/randokiller-go.yml @@ -33,6 +33,11 @@ jobs: outputs: json: ${{steps.get_config_json.outputs.json}} steps: + - name: Harden Runner + uses: step-security/harden-runner@v2 + with: + egress-policy: audit + - name: Checkout Code uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 diff --git a/.github/workflows/test-go.yaml b/.github/workflows/test-go.yaml index 1a65e08d65ad..d418e14167b4 100644 --- a/.github/workflows/test-go.yaml +++ b/.github/workflows/test-go.yaml @@ -310,6 +310,11 @@ jobs: needs: [test-go, test-go-nanomdm] runs-on: ubuntu-latest steps: + - name: Harden Runner + uses: step-security/harden-runner@v2 + with: + egress-policy: audit + - name: Checkout Code uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: Download artifacts diff --git a/.github/workflows/update-osquery-versions.yml b/.github/workflows/update-osquery-versions.yml index 1f0b89c0c518..f78d79d895f1 100644 --- a/.github/workflows/update-osquery-versions.yml +++ b/.github/workflows/update-osquery-versions.yml @@ -5,6 +5,9 @@ on: - cron: "0 0 * * *" # Run daily at midnight UTC workflow_dispatch: # Allow manual triggering +permissions: + contents: read + jobs: update-versions: permissions: @@ -12,6 +15,11 @@ jobs: pull-requests: write # for peter-evans/create-pull-request to create a PR runs-on: ubuntu-latest steps: + - name: Harden Runner + uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + with: + egress-policy: audit + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - name: Set up Python uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236 # v4.7.1 diff --git a/server/service/osquery_utils/queries.go b/server/service/osquery_utils/queries.go index 7ec132f8add6..0e0744603695 100644 --- a/server/service/osquery_utils/queries.go +++ b/server/service/osquery_utils/queries.go @@ -1770,6 +1770,35 @@ var ( s.Version = fmt.Sprintf("%d.%d.%s.%s", yearBasedMajorVersion, yearBasedMinorVersion, "99", eapMinorAndPatchVersion) }, }, + { + // Python versions on Windows encode ABI and release information in a way that's incompatible with NVD lookups + checkSoftware: func(h *fleet.Host, s *fleet.Software) bool { + return s.Source == "programs" && strings.HasPrefix(s.Name, "Python 3.") + }, + mutateSoftware: func(s *fleet.Software, logger log.Logger) { + versionComponents := strings.Split(s.Version, ".") + patchVersion := versionComponents[2][0 : len(versionComponents[2])-3] + releaseLevel := versionComponents[2][len(versionComponents[2])-3 : len(versionComponents[2])-1] + releaseSerial := versionComponents[2][len(versionComponents[2])-1 : len(versionComponents[2])] + + candidateSuffix := "" + switch releaseLevel { // see https://github.com/python/cpython/issues/100829#issuecomment-1374656643 + case "10": + candidateSuffix = "-alpha" + releaseSerial + case "11": + candidateSuffix = "-beta" + releaseSerial + case "12": + candidateSuffix = "-rc" + releaseSerial + } // default + + if patchVersion == "" { // dot-zero patch releases have a 3-digit patch + build number + patchVersion = "0" + } + + versionComponents[2] = patchVersion + candidateSuffix + s.Version = strings.Join(versionComponents[0:3], ".") + }, + }, } ) diff --git a/server/service/osquery_utils/queries_test.go b/server/service/osquery_utils/queries_test.go index a71b1deb806d..8292832fd6d3 100644 --- a/server/service/osquery_utils/queries_test.go +++ b/server/service/osquery_utils/queries_test.go @@ -1975,6 +1975,76 @@ func TestSanitizeSoftware(t *testing.T) { BundleIdentifier: "com.jetbrains.intellij-EAP", }, }, + { + name: "Python for Windows GA dot-zero", + h: &fleet.Host{}, + s: &fleet.Software{ + Name: "Python 3.12 (64-bit)", + Version: "3.12.150.1013", + Source: "programs", + }, + sanitized: &fleet.Software{ + Name: "Python 3.12 (64-bit)", + Version: "3.12.0", + Source: "programs", + }, + }, + { + name: "Python for Windows GA patch release", + h: &fleet.Host{}, + s: &fleet.Software{ + Name: "Python 3.12.8 (64-bit)", + Version: "3.12.8150.0", + Source: "programs", + }, + sanitized: &fleet.Software{ + Name: "Python 3.12.8 (64-bit)", + Version: "3.12.8", + Source: "programs", + }, + }, + { + name: "Python for Windows alpha", + h: &fleet.Host{}, + s: &fleet.Software{ + Name: "Python 3.14.0a4 (64-bit)", + Version: "3.14.104.1013", + Source: "programs", + }, + sanitized: &fleet.Software{ + Name: "Python 3.14.0a4 (64-bit)", + Version: "3.14.0-alpha4", + Source: "programs", + }, + }, + { + name: "Python for Windows beta", + h: &fleet.Host{}, + s: &fleet.Software{ + Name: "Python 3.14.0b3 (64-bit)", + Version: "3.14.113.1013", + Source: "programs", + }, + sanitized: &fleet.Software{ + Name: "Python 3.14.0b3 (64-bit)", + Version: "3.14.0-beta3", + Source: "programs", + }, + }, + { + name: "Python for Windows RC", + h: &fleet.Host{}, + s: &fleet.Software{ + Name: "Python 3.14.0rc2 (64-bit)", + Version: "3.14.122.1013", + Source: "programs", + }, + sanitized: &fleet.Software{ + Name: "Python 3.14.0rc2 (64-bit)", + Version: "3.14.0-rc2", + Source: "programs", + }, + }, } { t.Run(tc.name, func(t *testing.T) { sanitizeSoftware(tc.h, tc.s, log.NewNopLogger()) diff --git a/server/vulnerabilities/nvd/cpe_test.go b/server/vulnerabilities/nvd/cpe_test.go index 8a669d81c9bd..380aa89c488b 100644 --- a/server/vulnerabilities/nvd/cpe_test.go +++ b/server/vulnerabilities/nvd/cpe_test.go @@ -894,10 +894,19 @@ func TestCPEFromSoftwareIntegration(t *testing.T) { software: fleet.Software{ Name: "Python 3.10.6 (64-bit)", Source: "programs", - Version: "3.10.6150.0", + Version: "3.10.6", Vendor: "Python Software Foundation", BundleIdentifier: "", - }, cpe: "cpe:2.3:a:python:python:3.10.6150.0:*:*:*:*:windows:*:*", + }, cpe: "cpe:2.3:a:python:python:3.10.6:*:*:*:*:windows:*:*", + }, + { + software: fleet.Software{ + Name: "Python 3.14.0a1 (64-bit)", + Source: "programs", + Version: "3.14.0-alpha1", + Vendor: "Python Software Foundation", + // should be "cpe:2.3:a:python:python:3.14.0:alpha1:*:*:*:windows:*:*"; see #24810 + }, cpe: "cpe:2.3:a:python:python:3.14.0-alpha1:*:*:*:*:windows:*:*", }, { software: fleet.Software{ diff --git a/server/vulnerabilities/nvd/cpe_translations.json b/server/vulnerabilities/nvd/cpe_translations.json index 00ea56732d1b..ee81548e5c70 100644 --- a/server/vulnerabilities/nvd/cpe_translations.json +++ b/server/vulnerabilities/nvd/cpe_translations.json @@ -70,6 +70,16 @@ "vendor": ["7-zip"] } }, + { + "software": { + "name": ["/^Python 3\\.\\d{1,2}/"], + "source": ["programs"] + }, + "filter": { + "product": ["python"], + "vendor": ["python"] + } + }, { "software": { "name": ["Docs"],