diff --git a/PROJECTS/intermediate/security-news-scraper/cmd/nadezhda/enrich.go b/PROJECTS/intermediate/security-news-scraper/cmd/nadezhda/enrich.go index 0a35040d..7b041561 100644 --- a/PROJECTS/intermediate/security-news-scraper/cmd/nadezhda/enrich.go +++ b/PROJECTS/intermediate/security-news-scraper/cmd/nadezhda/enrich.go @@ -13,6 +13,7 @@ import ( "github.com/spf13/cobra" + "github.com/CarterPerez-dev/nadezhda/internal/config" "github.com/CarterPerez-dev/nadezhda/internal/cve" "github.com/CarterPerez-dev/nadezhda/internal/enrich" "github.com/CarterPerez-dev/nadezhda/internal/store" @@ -22,7 +23,8 @@ const nvdAPIKeyEnv = "NVD_API_KEY" var enrichCmd = &cobra.Command{ Use: "enrich", - Short: "Enrich extracted CVEs with NVD, CISA KEV, and EPSS intelligence", + Short: "Refresh CVE intelligence (CVE List / NVD, CISA KEV, EPSS) for extracted CVEs", + Long: "Refresh CVE intelligence for extracted CVEs. Keyless by default (CVE Program, CISA KEV, EPSS); uses NVD only when NVD_API_KEY is set. scrape already runs this automatically, so this command is for manually refreshing.", RunE: runEnrich, } @@ -41,27 +43,39 @@ func runEnrich(cmd *cobra.Command, args []string) error { } defer st.Close() - httpClient := &http.Client{Timeout: time.Duration(cfg.Fetch.TimeoutSeconds) * time.Second} - apiKey := os.Getenv(nvdAPIKeyEnv) - if apiKey == "" { - apiKey = cfg.Enrich.NVDAPIKey - } - clients := enrich.Clients{ - NVD: cve.NewNVDClient(httpClient, cve.NVDEndpoint, apiKey), - KEV: cve.NewKEVClient(httpClient, cve.KEVEndpoint), - EPSS: cve.NewEPSSClient(httpClient, cve.EPSSEndpoint), - } - ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) defer stop() - stats, err := enrich.Run(ctx, st, clients, time.Now(), cfg.Enrich.CacheTTLHours, cfg.Enrich.NegativeTTLHours) + stats, err := enrich.Run(ctx, st, buildEnrichClients(cfg), time.Now(), cfg.Enrich.CacheTTLHours, cfg.Enrich.NegativeTTLHours) if err != nil { return err } fmt.Fprintf(cmd.OutOrStdout(), - "enriched %d/%d CVEs (%d not in NVD, %d KEV, %d errors)\n", + "enriched %d/%d CVEs (%d not found, %d KEV, %d errors)\n", stats.Enriched, stats.Total, stats.NotFound, stats.KEVHits, stats.Errors) return nil } + +func buildEnrichClients(cfg config.Config) enrich.Clients { + httpClient := &http.Client{Timeout: time.Duration(cfg.Fetch.TimeoutSeconds) * time.Second} + return enrich.Clients{ + Core: buildCoreSource(httpClient, nvdAPIKey(cfg)), + KEV: cve.NewKEVClient(httpClient, cve.KEVEndpoint), + EPSS: cve.NewEPSSClient(httpClient, cve.EPSSEndpoint), + } +} + +func buildCoreSource(httpClient *http.Client, apiKey string) cve.CVESource { + if apiKey != "" { + return cve.NewNVDClient(httpClient, cve.NVDEndpoint, apiKey) + } + return cve.NewCVEListClient(httpClient, cve.CVEListEndpoint) +} + +func nvdAPIKey(cfg config.Config) string { + if k := os.Getenv(nvdAPIKeyEnv); k != "" { + return k + } + return cfg.Enrich.NVDAPIKey +} diff --git a/PROJECTS/intermediate/security-news-scraper/cmd/nadezhda/scrape.go b/PROJECTS/intermediate/security-news-scraper/cmd/nadezhda/scrape.go index 5bcbf4d4..fbb1c0f8 100644 --- a/PROJECTS/intermediate/security-news-scraper/cmd/nadezhda/scrape.go +++ b/PROJECTS/intermediate/security-news-scraper/cmd/nadezhda/scrape.go @@ -13,6 +13,8 @@ import ( "github.com/spf13/cobra" "github.com/CarterPerez-dev/nadezhda/internal/cluster" + "github.com/CarterPerez-dev/nadezhda/internal/config" + "github.com/CarterPerez-dev/nadezhda/internal/enrich" "github.com/CarterPerez-dev/nadezhda/internal/fetch" "github.com/CarterPerez-dev/nadezhda/internal/ingest" "github.com/CarterPerez-dev/nadezhda/internal/source" @@ -21,6 +23,8 @@ import ( const secondsPerHour = 3600 +const enrichBudget = 5 * time.Minute + const ( statusNotModified = "304" statusError = "error" @@ -28,7 +32,10 @@ const ( dash = "-" ) -var scrapeSource string +var ( + scrapeSource string + scrapeNoEnrich bool +) var scrapeCmd = &cobra.Command{ Use: "scrape", @@ -38,6 +45,7 @@ var scrapeCmd = &cobra.Command{ func init() { scrapeCmd.Flags().StringVar(&scrapeSource, "source", "", "ingest only this source by name") + scrapeCmd.Flags().BoolVar(&scrapeNoEnrich, "no-enrich", false, "skip the keyless CVE enrichment pass") rootCmd.AddCommand(scrapeCmd) } @@ -88,9 +96,34 @@ func runScrape(cmd *cobra.Command, args []string) error { } fmt.Fprintf(cmd.OutOrStdout(), "%d clusters (%d multi-source, largest %d)\n", stats.Total, stats.MultiSource, stats.LargestSize) + + if !scrapeNoEnrich { + enrichAfterScrape(ctx, cmd, cfg, st) + } return nil } +func enrichAfterScrape(ctx context.Context, cmd *cobra.Command, cfg config.Config, st *store.Store) { + out := cmd.OutOrStdout() + ectx, cancel := context.WithTimeout(ctx, enrichBudget) + defer cancel() + + stats, err := enrich.Run(ectx, st, buildEnrichClients(cfg), time.Now(), cfg.Enrich.CacheTTLHours, cfg.Enrich.NegativeTTLHours) + if err != nil { + if done := stats.Enriched + stats.NotFound; done > 0 { + fmt.Fprintf(out, "enriched %d/%d CVEs before stopping: %v\n", done, stats.Total, err) + } else { + fmt.Fprintf(out, "enrich skipped: %v (news is unaffected)\n", err) + } + return + } + if stats.Total == 0 { + return + } + fmt.Fprintf(out, "enriched %d/%d CVEs (%d KEV, %d not found)\n", + stats.Enriched, stats.Total, stats.KEVHits, stats.NotFound) +} + func selectTargets(srcs []source.Source, only string) ([]source.Source, error) { if only != "" { for _, s := range srcs { diff --git a/PROJECTS/intermediate/security-news-scraper/internal/config/config.go b/PROJECTS/intermediate/security-news-scraper/internal/config/config.go index 3a2c925d..030567f7 100644 --- a/PROJECTS/intermediate/security-news-scraper/internal/config/config.go +++ b/PROJECTS/intermediate/security-news-scraper/internal/config/config.go @@ -33,13 +33,13 @@ const ( defaultHalfLifeHours = 48 defaultVelocityNorm = 0.5 - defaultWeightRecency = 0.20 - defaultWeightCVSS = 0.15 - defaultWeightKEV = 0.25 - defaultWeightEPSS = 0.15 - defaultWeightVelocity = 0.15 - defaultWeightSource = 0.05 - defaultWeightKeyword = 0.05 + defaultWeightRecency = 0.30 + defaultWeightVelocity = 0.20 + defaultWeightKEV = 0.12 + defaultWeightCVSS = 0.10 + defaultWeightSource = 0.10 + defaultWeightKeyword = 0.10 + defaultWeightEPSS = 0.08 defaultAIProvider = "qwen" defaultQwenBaseURL = "http://localhost:11434/v1" diff --git a/PROJECTS/intermediate/security-news-scraper/internal/cve/cvelist.go b/PROJECTS/intermediate/security-news-scraper/internal/cve/cvelist.go new file mode 100644 index 00000000..2d4401a9 --- /dev/null +++ b/PROJECTS/intermediate/security-news-scraper/internal/cve/cvelist.go @@ -0,0 +1,249 @@ +// ©AngelaMos | 2026 +// cvelist.go + +package cve + +import ( + "context" + "errors" + "fmt" + "net/http" + "strings" + "time" + + "golang.org/x/time/rate" +) + +const ( + CVEListEndpoint = "https://raw.githubusercontent.com/CVEProject/cvelistV5/main/cves" + + cvelistRate = 15 + cvelistMaxRetries = 2 + cvelistBackoff = time.Second + cvelistBucketTail = 3 + cveIDParts = 3 + langEnPrefix = "en" + + cvssCriticalMin = 9.0 + cvssHighMin = 7.0 + cvssMediumMin = 4.0 + + cvssVersion2Prefix = "2" + + sevCritical = "CRITICAL" + sevHigh = "HIGH" + sevMedium = "MEDIUM" + sevLow = "LOW" + sevNone = "NONE" +) + +type CoreResult struct { + Found bool + Description string + CVSSScore *float64 + CVSSVersion string + CVSSSeverity string + CVSSVector string + CWE string + Published string + Modified string +} + +type CVESource interface { + Fetch(ctx context.Context, cveID string) (CoreResult, error) +} + +type CVEListClient struct { + http *http.Client + baseURL string + limiter *rate.Limiter + backoffBase time.Duration +} + +func NewCVEListClient(client *http.Client, baseURL string) *CVEListClient { + return &CVEListClient{ + http: client, + baseURL: strings.TrimRight(baseURL, "/"), + limiter: rate.NewLimiter(rate.Limit(cvelistRate), 1), + backoffBase: cvelistBackoff, + } +} + +func (c *CVEListClient) Fetch(ctx context.Context, cveID string) (CoreResult, error) { + endpoint, err := c.recordURL(cveID) + if err != nil { + return CoreResult{}, err + } + + var rec cvelistRecord + for attempt := 0; attempt <= cvelistMaxRetries; attempt++ { + if attempt > 0 { + if err := sleep(ctx, c.backoffBase*time.Duration(1<<(attempt-1))); err != nil { + return CoreResult{}, err + } + } + if err := c.limiter.Wait(ctx); err != nil { + return CoreResult{}, err + } + err := getJSON(ctx, c.http, endpoint, nil, &rec) + if err == nil { + return rec.toResult(), nil + } + var se *statusError + if errors.As(err, &se) && se.code == http.StatusNotFound { + return CoreResult{Found: false}, nil + } + if !retriable(err) || attempt == cvelistMaxRetries { + return CoreResult{}, err + } + } + return CoreResult{Found: false}, nil +} + +func (c *CVEListClient) recordURL(cveID string) (string, error) { + parts := strings.Split(cveID, "-") + if len(parts) != cveIDParts || parts[0] != "CVE" { + return "", fmt.Errorf("cve: malformed id %q", cveID) + } + num := parts[2] + if len(num) <= cvelistBucketTail { + return "", fmt.Errorf("cve: short id %q", cveID) + } + bucket := num[:len(num)-cvelistBucketTail] + "xxx" + return fmt.Sprintf("%s/%s/%s/%s.json", c.baseURL, parts[1], bucket, cveID), nil +} + +type cvelistRecord struct { + CVEMetadata struct { + DatePublished string `json:"datePublished"` + DateUpdated string `json:"dateUpdated"` + } `json:"cveMetadata"` + Containers struct { + CNA cvelistContainer `json:"cna"` + ADP []cvelistContainer `json:"adp"` + } `json:"containers"` +} + +type cvelistContainer struct { + Descriptions []cvelistLangValue `json:"descriptions"` + ProblemTypes []struct { + Descriptions []struct { + Lang string `json:"lang"` + CweID string `json:"cweId"` + } `json:"descriptions"` + } `json:"problemTypes"` + Metrics []cvelistMetric `json:"metrics"` +} + +type cvelistLangValue struct { + Lang string `json:"lang"` + Value string `json:"value"` +} + +type cvelistMetric struct { + V40 *cvelistCVSS `json:"cvssV4_0"` + V31 *cvelistCVSS `json:"cvssV3_1"` + V30 *cvelistCVSS `json:"cvssV3_0"` + V2 *cvelistCVSS `json:"cvssV2_0"` +} + +type cvelistCVSS struct { + Version string `json:"version"` + BaseScore float64 `json:"baseScore"` + BaseSeverity string `json:"baseSeverity"` + VectorString string `json:"vectorString"` +} + +func (rec cvelistRecord) containers() []cvelistContainer { + out := make([]cvelistContainer, 0, len(rec.Containers.ADP)+1) + out = append(out, rec.Containers.CNA) + out = append(out, rec.Containers.ADP...) + return out +} + +func (rec cvelistRecord) toResult() CoreResult { + res := CoreResult{ + Found: true, + Description: rec.description(), + CWE: rec.cwe(), + Published: rec.CVEMetadata.DatePublished, + Modified: rec.CVEMetadata.DateUpdated, + } + if cv := rec.cvss(); cv != nil { + score := cv.BaseScore + res.CVSSScore = &score + res.CVSSVersion = cv.Version + res.CVSSVector = cv.VectorString + res.CVSSSeverity = cv.BaseSeverity + if res.CVSSSeverity == "" { + res.CVSSSeverity = severityFromScore(score, cv.Version) + } + } + return res +} + +func (rec cvelistRecord) cvss() *cvelistCVSS { + tiers := []func(cvelistMetric) *cvelistCVSS{ + func(m cvelistMetric) *cvelistCVSS { return m.V40 }, + func(m cvelistMetric) *cvelistCVSS { return m.V31 }, + func(m cvelistMetric) *cvelistCVSS { return m.V30 }, + func(m cvelistMetric) *cvelistCVSS { return m.V2 }, + } + containers := rec.containers() + for _, pick := range tiers { + for _, c := range containers { + for _, m := range c.Metrics { + if cv := pick(m); cv != nil { + return cv + } + } + } + } + return nil +} + +func (rec cvelistRecord) cwe() string { + for _, c := range rec.containers() { + for _, pt := range c.ProblemTypes { + for _, d := range pt.Descriptions { + if d.CweID != "" { + return d.CweID + } + } + } + } + return "" +} + +func (rec cvelistRecord) description() string { + for _, c := range rec.containers() { + for _, d := range c.Descriptions { + if strings.HasPrefix(d.Lang, langEnPrefix) && strings.TrimSpace(d.Value) != "" { + return d.Value + } + } + } + for _, c := range rec.containers() { + for _, d := range c.Descriptions { + if strings.TrimSpace(d.Value) != "" { + return d.Value + } + } + } + return "" +} + +func severityFromScore(score float64, version string) string { + switch { + case score <= 0: + return sevNone + case score >= cvssCriticalMin && !strings.HasPrefix(version, cvssVersion2Prefix): + return sevCritical + case score >= cvssHighMin: + return sevHigh + case score >= cvssMediumMin: + return sevMedium + default: + return sevLow + } +} diff --git a/PROJECTS/intermediate/security-news-scraper/internal/cve/cvelist_test.go b/PROJECTS/intermediate/security-news-scraper/internal/cve/cvelist_test.go new file mode 100644 index 00000000..6d9b4e03 --- /dev/null +++ b/PROJECTS/intermediate/security-news-scraper/internal/cve/cvelist_test.go @@ -0,0 +1,132 @@ +// ©AngelaMos | 2026 +// cvelist_test.go + +package cve + +import ( + "context" + "net/http" + "net/http/httptest" + "os" + "strings" + "testing" +) + +func TestCVEListParsesLog4Shell(t *testing.T) { + body, err := os.ReadFile("../../testdata/cvelist/CVE-2021-44228.json") + if err != nil { + t.Fatalf("read fixture: %v", err) + } + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write(body) + })) + defer srv.Close() + + client := NewCVEListClient(srv.Client(), srv.URL) + res, err := client.Fetch(context.Background(), "CVE-2021-44228") + if err != nil { + t.Fatalf("Fetch: %v", err) + } + if !res.Found { + t.Fatal("Found = false, want true") + } + if res.CVSSScore == nil || *res.CVSSScore != 10.0 { + t.Errorf("CVSSScore = %v, want 10.0", res.CVSSScore) + } + if res.CVSSVersion != "3.1" || res.CVSSSeverity != "CRITICAL" { + t.Errorf("cvss = %q/%q, want 3.1/CRITICAL", res.CVSSVersion, res.CVSSSeverity) + } + if res.CVSSVector != "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H" { + t.Errorf("vector = %q", res.CVSSVector) + } + if res.CWE != "CWE-502" { + t.Errorf("CWE = %q, want CWE-502 (first problemType)", res.CWE) + } + if !strings.Contains(res.Description, "Log4j") { + t.Errorf("description missing Log4j: %q", res.Description) + } + if res.Published == "" || res.Modified == "" { + t.Errorf("published/modified empty: %q / %q", res.Published, res.Modified) + } +} + +func TestCVEListNotFound(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotFound) + })) + defer srv.Close() + + client := NewCVEListClient(srv.Client(), srv.URL) + res, err := client.Fetch(context.Background(), "CVE-2099-99999") + if err != nil { + t.Fatalf("Fetch: %v", err) + } + if res.Found { + t.Error("Found = true on 404, want false") + } +} + +func TestCVEListRecordURL(t *testing.T) { + client := NewCVEListClient(http.DefaultClient, "https://example.com/cves") + cases := map[string]string{ + "CVE-2021-44228": "https://example.com/cves/2021/44xxx/CVE-2021-44228.json", + "CVE-2021-1234": "https://example.com/cves/2021/1xxx/CVE-2021-1234.json", + "CVE-2023-12345": "https://example.com/cves/2023/12xxx/CVE-2023-12345.json", + } + for id, want := range cases { + got, err := client.recordURL(id) + if err != nil { + t.Errorf("recordURL(%q): %v", id, err) + continue + } + if got != want { + t.Errorf("recordURL(%q) = %q, want %q", id, got, want) + } + } + if _, err := client.recordURL("not-a-cve"); err == nil { + t.Error("expected error for malformed id") + } + if _, err := client.recordURL("CVE-2021-12"); err == nil { + t.Error("expected error for a too-short cve number") + } +} + +func serveJSON(t *testing.T, body string) *httptest.Server { + t.Helper() + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write([]byte(body)) + })) + t.Cleanup(srv.Close) + return srv +} + +func TestCVEListCNAMetrics(t *testing.T) { + srv := serveJSON(t, `{"cveMetadata":{"datePublished":"2020-01-01T00:00:00Z","dateUpdated":"2020-02-01T00:00:00Z"},"containers":{"cna":{"descriptions":[{"lang":"en","value":"cna container path"}],"problemTypes":[{"descriptions":[{"lang":"en","cweId":"CWE-79"}]}],"metrics":[{"cvssV3_1":{"version":"3.1","baseScore":7.5,"baseSeverity":"HIGH","vectorString":"CVSS:3.1/AV:N/AC:L"}}]}}}`) + res, err := NewCVEListClient(srv.Client(), srv.URL).Fetch(context.Background(), "CVE-2020-0001") + if err != nil { + t.Fatalf("Fetch: %v", err) + } + if res.CVSSScore == nil || *res.CVSSScore != 7.5 || res.CVSSVersion != "3.1" || res.CVSSSeverity != "HIGH" { + t.Errorf("cna metrics = %v/%q/%q, want 7.5/3.1/HIGH", res.CVSSScore, res.CVSSVersion, res.CVSSSeverity) + } + if res.CWE != "CWE-79" { + t.Errorf("CWE = %q, want CWE-79", res.CWE) + } +} + +func TestCVEListV2SeverityNotCritical(t *testing.T) { + srv := serveJSON(t, `{"cveMetadata":{"datePublished":"2005-01-01T00:00:00Z","dateUpdated":"2005-01-01T00:00:00Z"},"containers":{"cna":{"descriptions":[{"lang":"en","value":"v2 only"}],"metrics":[{"cvssV2_0":{"version":"2.0","baseScore":9.0,"vectorString":"AV:N/AC:L/Au:N/C:C/I:C/A:C"}}]}}}`) + res, err := NewCVEListClient(srv.Client(), srv.URL).Fetch(context.Background(), "CVE-2005-0001") + if err != nil { + t.Fatalf("Fetch: %v", err) + } + if res.CVSSVersion != "2.0" || res.CVSSScore == nil || *res.CVSSScore != 9.0 { + t.Errorf("v2 = %q/%v, want 2.0/9.0", res.CVSSVersion, res.CVSSScore) + } + if res.CVSSSeverity != "HIGH" { + t.Errorf("v2 severity = %q, want HIGH (CVSS v2 has no CRITICAL tier)", res.CVSSSeverity) + } +} + +var _ CVESource = (*CVEListClient)(nil) +var _ CVESource = (*NVDClient)(nil) diff --git a/PROJECTS/intermediate/security-news-scraper/internal/cve/nvd.go b/PROJECTS/intermediate/security-news-scraper/internal/cve/nvd.go index 6e2be481..74f063ee 100644 --- a/PROJECTS/intermediate/security-news-scraper/internal/cve/nvd.go +++ b/PROJECTS/intermediate/security-news-scraper/internal/cve/nvd.go @@ -24,18 +24,6 @@ const ( langEnglish = "en" ) -type NVDResult struct { - Found bool - Description string - CVSSScore *float64 - CVSSVersion string - CVSSSeverity string - CVSSVector string - CWE string - Published string - Modified string -} - type NVDClient struct { http *http.Client baseURL string @@ -58,7 +46,7 @@ func NewNVDClient(client *http.Client, baseURL, apiKey string) *NVDClient { } } -func (c *NVDClient) Fetch(ctx context.Context, cveID string) (NVDResult, error) { +func (c *NVDClient) Fetch(ctx context.Context, cveID string) (CoreResult, error) { endpoint := c.baseURL + "?" + url.Values{"cveId": {cveID}}.Encode() header := http.Header{} if c.apiKey != "" { @@ -69,23 +57,23 @@ func (c *NVDClient) Fetch(ctx context.Context, cveID string) (NVDResult, error) for attempt := 0; attempt <= nvdMaxRetries; attempt++ { if attempt > 0 { if err := sleep(ctx, c.backoffBase*time.Duration(1<<(attempt-1))); err != nil { - return NVDResult{}, err + return CoreResult{}, err } } if err := c.limiter.Wait(ctx); err != nil { - return NVDResult{}, err + return CoreResult{}, err } err := getJSON(ctx, c.http, endpoint, header, &env) if err == nil { break } if !retriable(err) || attempt == nvdMaxRetries { - return NVDResult{}, err + return CoreResult{}, err } } if env.TotalResults == 0 || len(env.Vulnerabilities) == 0 { - return NVDResult{Found: false}, nil + return CoreResult{Found: false}, nil } return env.Vulnerabilities[0].CVE.toResult(), nil } @@ -140,8 +128,8 @@ type nvdCVSSData struct { BaseSeverity string `json:"baseSeverity"` } -func (v nvdCVE) toResult() NVDResult { - res := NVDResult{ +func (v nvdCVE) toResult() CoreResult { + res := CoreResult{ Found: true, Description: english(v.Descriptions), Published: v.Published, diff --git a/PROJECTS/intermediate/security-news-scraper/internal/enrich/enrich.go b/PROJECTS/intermediate/security-news-scraper/internal/enrich/enrich.go index 584ab983..51bd23de 100644 --- a/PROJECTS/intermediate/security-news-scraper/internal/enrich/enrich.go +++ b/PROJECTS/intermediate/security-news-scraper/internal/enrich/enrich.go @@ -14,7 +14,7 @@ import ( const secondsPerHour = 3600 type Clients struct { - NVD *cve.NVDClient + Core cve.CVESource KEV *cve.KEVClient EPSS *cve.EPSSClient } @@ -51,7 +51,7 @@ func Run(ctx context.Context, st *store.Store, clients Clients, now time.Time, p stats := Stats{Total: len(ids)} for _, id := range ids { - nvdRes, err := clients.NVD.Fetch(ctx, id) + coreRes, err := clients.Core.Fetch(ctx, id) if err != nil { if ctx.Err() != nil { return stats, ctx.Err() @@ -61,16 +61,16 @@ func Run(ctx context.Context, st *store.Store, clients Clients, now time.Time, p } rec := store.CVE{ID: id, EnrichedAt: now.Unix()} - if nvdRes.Found { + if coreRes.Found { rec.EnrichStatus = store.EnrichStatusOK - rec.Description = nvdRes.Description - rec.CVSSScore = nvdRes.CVSSScore - rec.CVSSVersion = nvdRes.CVSSVersion - rec.CVSSSeverity = nvdRes.CVSSSeverity - rec.CVSSVector = nvdRes.CVSSVector - rec.CWE = nvdRes.CWE - rec.NVDPublished = nvdRes.Published - rec.NVDModified = nvdRes.Modified + rec.Description = coreRes.Description + rec.CVSSScore = coreRes.CVSSScore + rec.CVSSVersion = coreRes.CVSSVersion + rec.CVSSSeverity = coreRes.CVSSSeverity + rec.CVSSVector = coreRes.CVSSVector + rec.CWE = coreRes.CWE + rec.NVDPublished = coreRes.Published + rec.NVDModified = coreRes.Modified } else { rec.EnrichStatus = store.EnrichStatusNotFound } @@ -92,7 +92,7 @@ func Run(ctx context.Context, st *store.Store, clients Clients, now time.Time, p stats.Errors++ continue } - if nvdRes.Found { + if coreRes.Found { stats.Enriched++ } else { stats.NotFound++ diff --git a/PROJECTS/intermediate/security-news-scraper/internal/enrich/enrich_test.go b/PROJECTS/intermediate/security-news-scraper/internal/enrich/enrich_test.go index 6a1bdd06..03745e9c 100644 --- a/PROJECTS/intermediate/security-news-scraper/internal/enrich/enrich_test.go +++ b/PROJECTS/intermediate/security-news-scraper/internal/enrich/enrich_test.go @@ -50,7 +50,7 @@ func TestRunEnrichesLog4Shell(t *testing.T) { } clients := Clients{ - NVD: cve.NewNVDClient(nvd.Client(), nvd.URL, ""), + Core: cve.NewNVDClient(nvd.Client(), nvd.URL, ""), KEV: cve.NewKEVClient(kev.Client(), kev.URL), EPSS: cve.NewEPSSClient(epss.Client(), epss.URL), } @@ -97,7 +97,7 @@ func TestRunSkipsFreshAndMarksNotFound(t *testing.T) { t.Fatal(err) } clients := Clients{ - NVD: cve.NewNVDClient(nvd.Client(), nvd.URL, ""), + Core: cve.NewNVDClient(nvd.Client(), nvd.URL, ""), KEV: cve.NewKEVClient(kev.Client(), kev.URL), EPSS: cve.NewEPSSClient(epss.Client(), epss.URL), } diff --git a/PROJECTS/intermediate/security-news-scraper/testdata/cvelist/CVE-2021-44228.json b/PROJECTS/intermediate/security-news-scraper/testdata/cvelist/CVE-2021-44228.json new file mode 100644 index 00000000..be61eac0 --- /dev/null +++ b/PROJECTS/intermediate/security-news-scraper/testdata/cvelist/CVE-2021-44228.json @@ -0,0 +1,796 @@ +{ + "dataType": "CVE_RECORD", + "dataVersion": "5.1", + "cveMetadata": { + "state": "PUBLISHED", + "cveId": "CVE-2021-44228", + "assignerOrgId": "f0158376-9dc2-43b6-827c-5f631a4d8d09", + "assignerShortName": "apache", + "dateUpdated": "2025-10-21T23:25:23.121Z", + "dateReserved": "2021-11-26T00:00:00.000Z", + "datePublished": "2021-12-10T00:00:00.000Z" + }, + "containers": { + "cna": { + "title": "Apache Log4j2 JNDI features do not protect against attacker controlled LDAP and other JNDI related endpoints", + "providerMetadata": { + "orgId": "f0158376-9dc2-43b6-827c-5f631a4d8d09", + "shortName": "apache", + "dateUpdated": "2023-04-03T00:00:00.000Z" + }, + "descriptions": [ + { + "lang": "en", + "value": "Apache Log4j2 2.0-beta9 through 2.15.0 (excluding security releases 2.12.2, 2.12.3, and 2.3.1) JNDI features used in configuration, log messages, and parameters do not protect against attacker controlled LDAP and other JNDI related endpoints. An attacker who can control log messages or log message parameters can execute arbitrary code loaded from LDAP servers when message lookup substitution is enabled. From log4j 2.15.0, this behavior has been disabled by default. From version 2.16.0 (along with 2.12.2, 2.12.3, and 2.3.1), this functionality has been completely removed. Note that this vulnerability is specific to log4j-core and does not affect log4net, log4cxx, or other Apache Logging Services projects." + } + ], + "affected": [ + { + "vendor": "Apache Software Foundation", + "product": "Apache Log4j2", + "versions": [ + { + "version": "2.0-beta9", + "status": "affected", + "lessThan": "log4j-core*", + "versionType": "custom", + "changes": [ + { + "at": "2.3.1", + "status": "unaffected" + }, + { + "at": "2.4", + "status": "affected" + }, + { + "at": "2.12.2", + "status": "unaffected" + }, + { + "at": "2.13.0", + "status": "affected" + }, + { + "at": "2.15.0", + "status": "unaffected" + } + ] + } + ] + } + ], + "references": [ + { + "url": "https://logging.apache.org/log4j/2.x/security.html" + }, + { + "name": "[oss-security] 20211210 CVE-2021-44228: Apache Log4j2 JNDI features do not protect against attacker controlled LDAP and other JNDI related endpoints", + "tags": [ + "mailing-list" + ], + "url": "http://www.openwall.com/lists/oss-security/2021/12/10/1" + }, + { + "name": "[oss-security] 20211210 Re: CVE-2021-44228: Apache Log4j2 JNDI features do not protect against attacker controlled LDAP and other JNDI related endpoints", + "tags": [ + "mailing-list" + ], + "url": "http://www.openwall.com/lists/oss-security/2021/12/10/2" + }, + { + "name": "20211210 Vulnerability in Apache Log4j Library Affecting Cisco Products: December 2021", + "tags": [ + "vendor-advisory" + ], + "url": "https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-apache-log4j-qRuKNEbd" + }, + { + "name": "[oss-security] 20211210 Re: CVE-2021-44228: Apache Log4j2 JNDI features do not protect against attacker controlled LDAP and other JNDI related endpoints", + "tags": [ + "mailing-list" + ], + "url": "http://www.openwall.com/lists/oss-security/2021/12/10/3" + }, + { + "url": "https://security.netapp.com/advisory/ntap-20211210-0007/" + }, + { + "url": "http://packetstormsecurity.com/files/165225/Apache-Log4j2-2.14.1-Remote-Code-Execution.html" + }, + { + "url": "https://psirt.global.sonicwall.com/vuln-detail/SNWLID-2021-0032" + }, + { + "url": "https://www.oracle.com/security-alerts/alert-cve-2021-44228.html" + }, + { + "name": "DSA-5020", + "tags": [ + "vendor-advisory" + ], + "url": "https://www.debian.org/security/2021/dsa-5020" + }, + { + "name": "[debian-lts-announce] 20211212 [SECURITY] [DLA 2842-1] apache-log4j2 security update", + "tags": [ + "mailing-list" + ], + "url": "https://lists.debian.org/debian-lts-announce/2021/12/msg00007.html" + }, + { + "name": "FEDORA-2021-f0f501d01f", + "tags": [ + "vendor-advisory" + ], + "url": "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/VU57UJDCFIASIO35GC55JMKSRXJMCDFM/" + }, + { + "name": "Microsoft’s Response to CVE-2021-44228 Apache Log4j 2", + "tags": [ + "vendor-advisory" + ], + "url": "https://msrc-blog.microsoft.com/2021/12/11/microsofts-response-to-cve-2021-44228-apache-log4j2/" + }, + { + "name": "[oss-security] 20211213 Re: CVE-2021-4104: Deserialization of untrusted data in JMSAppender in Apache Log4j 1.2", + "tags": [ + "mailing-list" + ], + "url": "http://www.openwall.com/lists/oss-security/2021/12/13/2" + }, + { + "name": "[oss-security] 20211213 CVE-2021-4104: Deserialization of untrusted data in JMSAppender in Apache Log4j 1.2", + "tags": [ + "mailing-list" + ], + "url": "http://www.openwall.com/lists/oss-security/2021/12/13/1" + }, + { + "name": "[oss-security] 20211214 CVE-2021-45046: Apache Log4j2 Thread Context Message Pattern and Context Lookup Pattern vulnerable to a denial of service attack", + "tags": [ + "mailing-list" + ], + "url": "http://www.openwall.com/lists/oss-security/2021/12/14/4" + }, + { + "name": "20211210 A Vulnerability in Apache Log4j Library Affecting Cisco Products: December 2021", + "tags": [ + "vendor-advisory" + ], + "url": "https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-apache-log4j-qRuKNEbd" + }, + { + "name": "VU#930724", + "tags": [ + "third-party-advisory" + ], + "url": "https://www.kb.cert.org/vuls/id/930724" + }, + { + "url": "https://twitter.com/kurtseifried/status/1469345530182455296" + }, + { + "url": "https://cert-portal.siemens.com/productcert/pdf/ssa-661247.pdf" + }, + { + "url": "http://packetstormsecurity.com/files/165260/VMware-Security-Advisory-2021-0028.html" + }, + { + "url": "http://packetstormsecurity.com/files/165270/Apache-Log4j2-2.14.1-Remote-Code-Execution.html" + }, + { + "url": "http://packetstormsecurity.com/files/165261/Apache-Log4j2-2.14.1-Information-Disclosure.html" + }, + { + "url": "https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00646.html" + }, + { + "name": "20211210 Vulnerabilities in Apache Log4j Library Affecting Cisco Products: December 2021", + "tags": [ + "vendor-advisory" + ], + "url": "https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-apache-log4j-qRuKNEbd" + }, + { + "name": "[oss-security] 20211215 Re: CVE-2021-45046: Apache Log4j2 Thread Context Message Pattern and Context Lookup Pattern vulnerable to a denial of service attack", + "tags": [ + "mailing-list" + ], + "url": "http://www.openwall.com/lists/oss-security/2021/12/15/3" + }, + { + "url": "http://packetstormsecurity.com/files/165282/Log4j-Payload-Generator.html" + }, + { + "url": "http://packetstormsecurity.com/files/165281/Log4j2-Log4Shell-Regexes.html" + }, + { + "url": "http://packetstormsecurity.com/files/165307/Log4j-Remote-Code-Execution-Word-Bypassing.html" + }, + { + "url": "http://packetstormsecurity.com/files/165311/log4j-scan-Extensive-Scanner.html" + }, + { + "url": "http://packetstormsecurity.com/files/165306/L4sh-Log4j-Remote-Code-Execution.html" + }, + { + "url": "https://cert-portal.siemens.com/productcert/pdf/ssa-714170.pdf" + }, + { + "name": "FEDORA-2021-66d6c484f3", + "tags": [ + "vendor-advisory" + ], + "url": "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/M5CSVUNV4HWZZXGOKNSK6L7RPM7BOKIB/" + }, + { + "url": "http://packetstormsecurity.com/files/165371/VMware-Security-Advisory-2021-0028.4.html" + }, + { + "url": "https://cert-portal.siemens.com/productcert/pdf/ssa-397453.pdf" + }, + { + "url": "https://cert-portal.siemens.com/productcert/pdf/ssa-479842.pdf" + }, + { + "url": "https://www.oracle.com/security-alerts/cpujan2022.html" + }, + { + "url": "http://packetstormsecurity.com/files/165532/Log4Shell-HTTP-Header-Injection.html" + }, + { + "url": "https://github.com/cisagov/log4j-affected-db/blob/develop/SOFTWARE-LIST.md" + }, + { + "url": "http://packetstormsecurity.com/files/165642/VMware-vCenter-Server-Unauthenticated-Log4Shell-JNDI-Injection-Remote-Code-Execution.html" + }, + { + "url": "http://packetstormsecurity.com/files/165673/UniFi-Network-Application-Unauthenticated-Log4Shell-Remote-Code-Execution.html" + }, + { + "name": "20220314 APPLE-SA-2022-03-14-7 Xcode 13.3", + "tags": [ + "mailing-list" + ], + "url": "http://seclists.org/fulldisclosure/2022/Mar/23" + }, + { + "url": "https://www.bentley.com/en/common-vulnerability-exposure/be-2022-0001" + }, + { + "url": "https://github.com/cisagov/log4j-affected-db" + }, + { + "url": "https://support.apple.com/kb/HT213189" + }, + { + "url": "https://www.oracle.com/security-alerts/cpuapr2022.html" + }, + { + "url": "https://github.com/nu11secur1ty/CVE-mitre/tree/main/CVE-2021-44228" + }, + { + "url": "https://www.nu11secur1ty.com/2021/12/cve-2021-44228.html" + }, + { + "name": "20220721 Open-Xchange Security Advisory 2022-07-21", + "tags": [ + "mailing-list" + ], + "url": "http://seclists.org/fulldisclosure/2022/Jul/11" + }, + { + "url": "http://packetstormsecurity.com/files/167794/Open-Xchange-App-Suite-7.10.x-Cross-Site-Scripting-Command-Injection.html" + }, + { + "url": "http://packetstormsecurity.com/files/167917/MobileIron-Log4Shell-Remote-Command-Execution.html" + }, + { + "name": "20221208 Intel Data Center Manager <= 5.1 Local Privileges Escalation", + "tags": [ + "mailing-list" + ], + "url": "http://seclists.org/fulldisclosure/2022/Dec/2" + }, + { + "url": "http://packetstormsecurity.com/files/171626/AD-Manager-Plus-7122-Remote-Code-Execution.html" + } + ], + "credits": [ + { + "lang": "en", + "value": "This issue was discovered by Chen Zhaojun of Alibaba Cloud Security Team." + } + ], + "metrics": [ + { + "other": { + "type": "unknown", + "content": { + "other": "critical" + } + } + } + ], + "problemTypes": [ + { + "descriptions": [ + { + "type": "CWE", + "lang": "en", + "description": "CWE-502 Deserialization of Untrusted Data", + "cweId": "CWE-502" + } + ] + }, + { + "descriptions": [ + { + "type": "CWE", + "lang": "en", + "description": "CWE-400 Uncontrolled Resource Consumption", + "cweId": "CWE-400" + } + ] + }, + { + "descriptions": [ + { + "type": "CWE", + "lang": "en", + "description": "CWE-20 Improper Input Validation", + "cweId": "CWE-20" + } + ] + } + ], + "x_generator": { + "engine": "Vulnogram 0.0.9" + }, + "source": { + "discovery": "UNKNOWN" + } + }, + "adp": [ + { + "providerMetadata": { + "orgId": "af854a3a-2127-422b-91ae-364da2661108", + "shortName": "CVE", + "dateUpdated": "2024-08-04T04:17:24.696Z" + }, + "title": "CVE Program Container", + "references": [ + { + "url": "https://logging.apache.org/log4j/2.x/security.html", + "tags": [ + "x_transferred" + ] + }, + { + "name": "[oss-security] 20211210 CVE-2021-44228: Apache Log4j2 JNDI features do not protect against attacker controlled LDAP and other JNDI related endpoints", + "tags": [ + "mailing-list", + "x_transferred" + ], + "url": "http://www.openwall.com/lists/oss-security/2021/12/10/1" + }, + { + "name": "[oss-security] 20211210 Re: CVE-2021-44228: Apache Log4j2 JNDI features do not protect against attacker controlled LDAP and other JNDI related endpoints", + "tags": [ + "mailing-list", + "x_transferred" + ], + "url": "http://www.openwall.com/lists/oss-security/2021/12/10/2" + }, + { + "name": "20211210 Vulnerability in Apache Log4j Library Affecting Cisco Products: December 2021", + "tags": [ + "vendor-advisory", + "x_transferred" + ], + "url": "https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-apache-log4j-qRuKNEbd" + }, + { + "name": "[oss-security] 20211210 Re: CVE-2021-44228: Apache Log4j2 JNDI features do not protect against attacker controlled LDAP and other JNDI related endpoints", + "tags": [ + "mailing-list", + "x_transferred" + ], + "url": "http://www.openwall.com/lists/oss-security/2021/12/10/3" + }, + { + "url": "https://security.netapp.com/advisory/ntap-20211210-0007/", + "tags": [ + "x_transferred" + ] + }, + { + "url": "http://packetstormsecurity.com/files/165225/Apache-Log4j2-2.14.1-Remote-Code-Execution.html", + "tags": [ + "x_transferred" + ] + }, + { + "url": "https://psirt.global.sonicwall.com/vuln-detail/SNWLID-2021-0032", + "tags": [ + "x_transferred" + ] + }, + { + "url": "https://www.oracle.com/security-alerts/alert-cve-2021-44228.html", + "tags": [ + "x_transferred" + ] + }, + { + "name": "DSA-5020", + "tags": [ + "vendor-advisory", + "x_transferred" + ], + "url": "https://www.debian.org/security/2021/dsa-5020" + }, + { + "name": "[debian-lts-announce] 20211212 [SECURITY] [DLA 2842-1] apache-log4j2 security update", + "tags": [ + "mailing-list", + "x_transferred" + ], + "url": "https://lists.debian.org/debian-lts-announce/2021/12/msg00007.html" + }, + { + "name": "FEDORA-2021-f0f501d01f", + "tags": [ + "vendor-advisory", + "x_transferred" + ], + "url": "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/VU57UJDCFIASIO35GC55JMKSRXJMCDFM/" + }, + { + "name": "Microsoft’s Response to CVE-2021-44228 Apache Log4j 2", + "tags": [ + "vendor-advisory", + "x_transferred" + ], + "url": "https://msrc-blog.microsoft.com/2021/12/11/microsofts-response-to-cve-2021-44228-apache-log4j2/" + }, + { + "name": "[oss-security] 20211213 Re: CVE-2021-4104: Deserialization of untrusted data in JMSAppender in Apache Log4j 1.2", + "tags": [ + "mailing-list", + "x_transferred" + ], + "url": "http://www.openwall.com/lists/oss-security/2021/12/13/2" + }, + { + "name": "[oss-security] 20211213 CVE-2021-4104: Deserialization of untrusted data in JMSAppender in Apache Log4j 1.2", + "tags": [ + "mailing-list", + "x_transferred" + ], + "url": "http://www.openwall.com/lists/oss-security/2021/12/13/1" + }, + { + "name": "[oss-security] 20211214 CVE-2021-45046: Apache Log4j2 Thread Context Message Pattern and Context Lookup Pattern vulnerable to a denial of service attack", + "tags": [ + "mailing-list", + "x_transferred" + ], + "url": "http://www.openwall.com/lists/oss-security/2021/12/14/4" + }, + { + "name": "20211210 A Vulnerability in Apache Log4j Library Affecting Cisco Products: December 2021", + "tags": [ + "vendor-advisory", + "x_transferred" + ], + "url": "https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-apache-log4j-qRuKNEbd" + }, + { + "name": "VU#930724", + "tags": [ + "third-party-advisory", + "x_transferred" + ], + "url": "https://www.kb.cert.org/vuls/id/930724" + }, + { + "url": "https://twitter.com/kurtseifried/status/1469345530182455296", + "tags": [ + "x_transferred" + ] + }, + { + "url": "https://cert-portal.siemens.com/productcert/pdf/ssa-661247.pdf", + "tags": [ + "x_transferred" + ] + }, + { + "url": "http://packetstormsecurity.com/files/165260/VMware-Security-Advisory-2021-0028.html", + "tags": [ + "x_transferred" + ] + }, + { + "url": "http://packetstormsecurity.com/files/165270/Apache-Log4j2-2.14.1-Remote-Code-Execution.html", + "tags": [ + "x_transferred" + ] + }, + { + "url": "http://packetstormsecurity.com/files/165261/Apache-Log4j2-2.14.1-Information-Disclosure.html", + "tags": [ + "x_transferred" + ] + }, + { + "url": "https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00646.html", + "tags": [ + "x_transferred" + ] + }, + { + "name": "20211210 Vulnerabilities in Apache Log4j Library Affecting Cisco Products: December 2021", + "tags": [ + "vendor-advisory", + "x_transferred" + ], + "url": "https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-apache-log4j-qRuKNEbd" + }, + { + "name": "[oss-security] 20211215 Re: CVE-2021-45046: Apache Log4j2 Thread Context Message Pattern and Context Lookup Pattern vulnerable to a denial of service attack", + "tags": [ + "mailing-list", + "x_transferred" + ], + "url": "http://www.openwall.com/lists/oss-security/2021/12/15/3" + }, + { + "url": "http://packetstormsecurity.com/files/165282/Log4j-Payload-Generator.html", + "tags": [ + "x_transferred" + ] + }, + { + "url": "http://packetstormsecurity.com/files/165281/Log4j2-Log4Shell-Regexes.html", + "tags": [ + "x_transferred" + ] + }, + { + "url": "http://packetstormsecurity.com/files/165307/Log4j-Remote-Code-Execution-Word-Bypassing.html", + "tags": [ + "x_transferred" + ] + }, + { + "url": "http://packetstormsecurity.com/files/165311/log4j-scan-Extensive-Scanner.html", + "tags": [ + "x_transferred" + ] + }, + { + "url": "http://packetstormsecurity.com/files/165306/L4sh-Log4j-Remote-Code-Execution.html", + "tags": [ + "x_transferred" + ] + }, + { + "url": "https://cert-portal.siemens.com/productcert/pdf/ssa-714170.pdf", + "tags": [ + "x_transferred" + ] + }, + { + "name": "FEDORA-2021-66d6c484f3", + "tags": [ + "vendor-advisory", + "x_transferred" + ], + "url": "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/M5CSVUNV4HWZZXGOKNSK6L7RPM7BOKIB/" + }, + { + "url": "http://packetstormsecurity.com/files/165371/VMware-Security-Advisory-2021-0028.4.html", + "tags": [ + "x_transferred" + ] + }, + { + "url": "https://cert-portal.siemens.com/productcert/pdf/ssa-397453.pdf", + "tags": [ + "x_transferred" + ] + }, + { + "url": "https://cert-portal.siemens.com/productcert/pdf/ssa-479842.pdf", + "tags": [ + "x_transferred" + ] + }, + { + "url": "https://www.oracle.com/security-alerts/cpujan2022.html", + "tags": [ + "x_transferred" + ] + }, + { + "url": "http://packetstormsecurity.com/files/165532/Log4Shell-HTTP-Header-Injection.html", + "tags": [ + "x_transferred" + ] + }, + { + "url": "https://github.com/cisagov/log4j-affected-db/blob/develop/SOFTWARE-LIST.md", + "tags": [ + "x_transferred" + ] + }, + { + "url": "http://packetstormsecurity.com/files/165642/VMware-vCenter-Server-Unauthenticated-Log4Shell-JNDI-Injection-Remote-Code-Execution.html", + "tags": [ + "x_transferred" + ] + }, + { + "url": "http://packetstormsecurity.com/files/165673/UniFi-Network-Application-Unauthenticated-Log4Shell-Remote-Code-Execution.html", + "tags": [ + "x_transferred" + ] + }, + { + "name": "20220314 APPLE-SA-2022-03-14-7 Xcode 13.3", + "tags": [ + "mailing-list", + "x_transferred" + ], + "url": "http://seclists.org/fulldisclosure/2022/Mar/23" + }, + { + "url": "https://www.bentley.com/en/common-vulnerability-exposure/be-2022-0001", + "tags": [ + "x_transferred" + ] + }, + { + "url": "https://github.com/cisagov/log4j-affected-db", + "tags": [ + "x_transferred" + ] + }, + { + "url": "https://support.apple.com/kb/HT213189", + "tags": [ + "x_transferred" + ] + }, + { + "url": "https://www.oracle.com/security-alerts/cpuapr2022.html", + "tags": [ + "x_transferred" + ] + }, + { + "url": "https://github.com/nu11secur1ty/CVE-mitre/tree/main/CVE-2021-44228", + "tags": [ + "x_transferred" + ] + }, + { + "url": "https://www.nu11secur1ty.com/2021/12/cve-2021-44228.html", + "tags": [ + "x_transferred" + ] + }, + { + "name": "20220721 Open-Xchange Security Advisory 2022-07-21", + "tags": [ + "mailing-list", + "x_transferred" + ], + "url": "http://seclists.org/fulldisclosure/2022/Jul/11" + }, + { + "url": "http://packetstormsecurity.com/files/167794/Open-Xchange-App-Suite-7.10.x-Cross-Site-Scripting-Command-Injection.html", + "tags": [ + "x_transferred" + ] + }, + { + "url": "http://packetstormsecurity.com/files/167917/MobileIron-Log4Shell-Remote-Command-Execution.html", + "tags": [ + "x_transferred" + ] + }, + { + "name": "20221208 Intel Data Center Manager <= 5.1 Local Privileges Escalation", + "tags": [ + "mailing-list", + "x_transferred" + ], + "url": "http://seclists.org/fulldisclosure/2022/Dec/2" + }, + { + "url": "http://packetstormsecurity.com/files/171626/AD-Manager-Plus-7122-Remote-Code-Execution.html", + "tags": [ + "x_transferred" + ] + } + ] + }, + { + "metrics": [ + { + "cvssV3_1": { + "scope": "CHANGED", + "version": "3.1", + "baseScore": 10, + "attackVector": "NETWORK", + "baseSeverity": "CRITICAL", + "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", + "integrityImpact": "HIGH", + "userInteraction": "NONE", + "attackComplexity": "LOW", + "availabilityImpact": "HIGH", + "privilegesRequired": "NONE", + "confidentialityImpact": "HIGH" + } + }, + { + "other": { + "type": "ssvc", + "content": { + "id": "CVE-2021-44228", + "role": "CISA Coordinator", + "options": [ + { + "Exploitation": "active" + }, + { + "Automatable": "yes" + }, + { + "Technical Impact": "total" + } + ], + "version": "2.0.3", + "timestamp": "2025-02-04T14:25:34.416117Z" + } + } + }, + { + "other": { + "type": "kev", + "content": { + "dateAdded": "2021-12-10", + "reference": "https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2021-44228" + } + } + } + ], + "references": [ + { + "url": "https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2021-44228", + "tags": [ + "government-resource" + ] + } + ], + "timeline": [ + { + "time": "2021-12-10T00:00:00.000Z", + "lang": "en", + "value": "CVE-2021-44228 added to CISA KEV" + } + ], + "title": "CISA ADP Vulnrichment", + "providerMetadata": { + "orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0", + "shortName": "CISA-ADP", + "dateUpdated": "2025-10-21T23:25:23.121Z" + } + } + ] + } +}