Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/44800-ollama-resolved-in-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Fixed missing `resolved_in_version` for CVE-2025-63389 on Ollama (resolved in v0.12.4), which was absent because the NVD record only provides a `versionEndIncluding` constraint.
39 changes: 39 additions & 0 deletions server/vulnerabilities/nvd/cpe_matching_rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,48 @@ import (
"strconv"
"strings"

feednvd "github.com/fleetdm/fleet/v4/server/vulnerabilities/nvd/tools/cvefeed/nvd"
"github.com/fleetdm/fleet/v4/server/vulnerabilities/nvd/tools/wfn"
)

// resolvedVersionOverride supplies a known upstream fix version for a CVE whose NVD record only
// provides a versionEndIncluding constraint (so the resolved version can't be derived from the
// feed). Like GetKnownNVDBugRules, this works around bad/incomplete data in the NVD dataset, but
// it is consulted only as a fallback - the live NVD feed always takes precedence (see
// getMatchingVersionEndExcluding). See https://github.com/fleetdm/fleet/issues/44800.
type resolvedVersionOverride struct {
vendor string
product string
resolvedInVersion string
}

// knownResolvedVersionOverrides maps a CVE to its known upstream fix version. Add an entry here
// only when NVD reports the CVE without a versionEndExcluding (so resolved_in_version comes back
// empty) but the fix version is known. Remove the entry once NVD publishes the correct data.
var knownResolvedVersionOverrides = map[string]resolvedVersionOverride{
// CVE-2025-63389: NVD lists ollama as vulnerable through (and including) v0.12.3 via
// versionEndIncluding with no versionEndExcluding. The fix shipped in the next release, v0.12.4.
"CVE-2025-63389": {vendor: "ollama", product: "ollama", resolvedInVersion: "0.12.4"},
}

// findResolvedVersionOverride returns the known resolved version for the given CVE and host
// software, if one is configured and applicable, or an empty string otherwise. The caller must
// already have confirmed that the host is affected by the CVE; the version guard here only avoids
// reporting a resolved version for a host that is already at or above the fix version.
func findResolvedVersionOverride(cve string, hostSoftwareMeta *wfn.Attributes) string {
override, ok := knownResolvedVersionOverrides[cve]
if !ok || hostSoftwareMeta == nil {
return ""
}
if hostSoftwareMeta.Vendor != override.vendor || hostSoftwareMeta.Product != override.product {
return ""
}
if feednvd.SmartVerCmp(wfn.StripSlashes(hostSoftwareMeta.Version), override.resolvedInVersion) != -1 {
return ""
}
return override.resolvedInVersion
}

type CPEMatchingRules []CPEMatchingRule

// GetKnownNVDBugRules returns a list of CPEMatchingRules used for
Expand Down
25 changes: 22 additions & 3 deletions server/vulnerabilities/nvd/cve.go
Original file line number Diff line number Diff line change
Expand Up @@ -688,10 +688,29 @@ func expandCPEAliases(cpeItem *wfn.Attributes) []*wfn.Attributes {
return cpeItems
}

// Returns the versionEndExcluding string for the given CVE and host software meta
// data, if it exists in the NVD feed. This effectively gives us the version of the
// software it needs to upgrade to in order to address the CVE.
// getMatchingVersionEndExcluding returns the version of the software it needs to upgrade to in
// order to address the CVE. It is derived from the NVD feed's versionEndExcluding when available;
// otherwise, as a fallback, it consults knownResolvedVersionOverrides for CVEs whose NVD record
// only provides versionEndIncluding. Authoritative NVD data always takes precedence over the
// fallback. The caller must already have confirmed that the host is affected by the CVE.
func getMatchingVersionEndExcluding(ctx context.Context, cve string, hostSoftwareMeta *wfn.Attributes, dict cvefeed.Dictionary, logger *slog.Logger) (string, error) {
resolved, err := versionEndExcludingFromFeed(ctx, cve, hostSoftwareMeta, dict, logger)
if err != nil {
return "", err
}
if resolved != "" {
return resolved, nil
}

// The NVD feed yielded no resolved version (e.g. the record only has versionEndIncluding).
// Fall back to a known upstream fix version, if one is configured for this CVE.
// See https://github.com/fleetdm/fleet/issues/44800.
return findResolvedVersionOverride(cve, hostSoftwareMeta), nil
}

// versionEndExcludingFromFeed returns the versionEndExcluding string for the given CVE and host
// software meta data, if it exists in the NVD feed.
func versionEndExcludingFromFeed(ctx context.Context, cve string, hostSoftwareMeta *wfn.Attributes, dict cvefeed.Dictionary, logger *slog.Logger) (string, error) {
vuln, ok := dict[cve].(*feednvd.Vuln)
if !ok {
return "", nil
Expand Down
46 changes: 46 additions & 0 deletions server/vulnerabilities/nvd/cve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1123,6 +1123,52 @@ func TestGetMatchingVersionEndExcluding(t *testing.T) {
want: "6.72.10.07",
wantErr: false,
},
{
// NVD only provides versionEndIncluding for this CVE, so the resolved version comes
// from knownResolvedVersionOverrides. See #44800.
name: "versionEndIncluding-only CVE uses resolved version override",
cve: "CVE-2025-63389",
meta: &wfn.Attributes{
Vendor: "ollama",
Product: "ollama",
Version: "0.12.3",
},
want: "0.12.4",
wantErr: false,
},
{
name: "resolved version override applies to older vulnerable versions",
cve: "CVE-2025-63389",
meta: &wfn.Attributes{
Vendor: "ollama",
Product: "ollama",
Version: "0.12.0",
},
want: "0.12.4",
wantErr: false,
},
{
name: "resolved version override does not apply at or above the fix version",
cve: "CVE-2025-63389",
meta: &wfn.Attributes{
Vendor: "ollama",
Product: "ollama",
Version: "0.12.4",
},
want: "",
wantErr: false,
},
{
name: "resolved version override does not apply to other products",
cve: "CVE-2025-63389",
meta: &wfn.Attributes{
Vendor: "notollama",
Product: "notollama",
Version: "0.12.0",
},
want: "",
wantErr: false,
},
}

for _, tt := range tests {
Expand Down
Loading