{"vulnerability": "CVE-2019-8943", "sightings": [{"uuid": "6fcc3286-8152-49f8-949f-dac51b9109f4", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "exploited", "source": "https://www.exploit-db.com/exploits/46662", "content": "", "creation_timestamp": "2019-04-05T00:00:00.000000Z"}, {"uuid": "ebd6657a-936f-40a7-b5e8-c53a6b3e5da6", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "MISP/6c2173d8-54b2-4a90-9694-167101ac3030", "content": "", "creation_timestamp": "2024-11-14T06:10:10.000000Z"}, {"uuid": "affc87e4-ecdd-427c-bffc-c45786f0c995", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "MISP/a1e796df-2ad8-4c8d-8b69-737a004e72dd", "content": "", "creation_timestamp": "2025-02-06T03:13:44.000000Z"}, {"uuid": "d767be4a-35a4-45e5-80ff-e2c8a5a4f0a9", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "MISP/a1e796df-2ad8-4c8d-8b69-737a004e72dd", "content": "", "creation_timestamp": "2025-02-23T04:10:19.000000Z"}, {"uuid": "19bf7039-ff03-4933-bc29-7e6acbb86c38", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/multi/http/wp_crop_rce.rb", "content": "", "creation_timestamp": "2019-04-04T20:32:00.000000Z"}, {"uuid": "9ca1f5de-2a4c-4973-a107-5662b96fe1a2", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "published-proof-of-concept", "source": "https://t.me/antichat/3785", "content": "Analyzing WordPress Remote Code Execution Vulnerabilities CVE-2019-8942 and CVE-2019-8943\nhttps://blog.trendmicro.com/trendlabs-security-intelligence/analyzing-wordpress-remote-code-execution-vulnerabilities-cve-2019-8942-and-cve-2019-8943/", "creation_timestamp": "2019-03-01T08:59:30.000000Z"}, {"uuid": "51087623-c386-4c82-9e69-ce3c93a1101a", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "published-proof-of-concept", "source": "https://t.me/RepProject/62", "content": "Wordpress Core RCE Critical For Version 5.0.0 and &lt;= 4.9.8  Auth\n\nIf you cant upload shell via wp file manager or plugins you can use this methods \n\npython3 RCE_wordpress.py http://site.com   \n\nusage example : \npython3 rce.py http://site.com/ admin pass twenty_seventeen\n\n\nCVE ID : CVE-2019-8943", "creation_timestamp": "2023-02-27T08:22:27.000000Z"}, {"uuid": "25c20e6c-b37e-4cc8-bdf3-4bb9bb52e3bd", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://t.me/pwnwiki_zhchannel/554", "content": "CVE-2019-8943 WordPress 5.0.0 \u9060\u7a0b\u4ee3\u78bc\u57f7\u884c\u6f0f\u6d1e\nhttps://www.pwnwiki.org/index.php?title=CVE-2019-8943_WordPress_5.0.0_%E9%81%A0%E7%A8%8B%E4%BB%A3%E7%A2%BC%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E", "creation_timestamp": "2021-05-31T03:56:27.000000Z"}, {"uuid": "f58efa1e-de3d-4bc2-99ea-e457f3d46a67", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://t.me/thebugbountyhunter/2368", "content": "Analyzing WordPress Remote Code Execution Vulnerabilities CVE-2019-8942 and CVE-2019-8943\nhttps://blog.trendmicro.com/trendlabs-security-intelligence/analyzing-wordpress-remote-code-execution-vulnerabilities-cve-2019-8942-and-cve-2019-8943/", "creation_timestamp": "2019-03-01T09:58:50.000000Z"}, {"uuid": "c5e33c84-ec13-439a-89b9-787b7651c258", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "published-proof-of-concept", "source": "https://t.me/CyberSecurityTechnologies/382", "content": "#exploit\n1. CVE-2019-8943:\nWordPress 5.0.0 - RCE\nhttps://blog.ripstech.com/2019/wordpress-image-remote-code-execution\n\n2. CVE-2019-6177:\nLenovo Solution Centre Privilege Escalation\nhttps://www.pentestpartners.com/security-blog/privesc-in-lenovo-solution-centre-10-minutes-later", "creation_timestamp": "2024-10-10T18:03:05.000000Z"}, {"uuid": "277ff3f1-a4d0-4a06-8539-e0be2ad157a3", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://t.me/GithubRedTeam/85429", "content": "\ud83d\udea8 GitHub \u76d1\u63a7\u6d88\u606f\u63d0\u9192\n\n\ud83d\udea8 \u53d1\u73b0\u5173\u952e\u8bcd\uff1a #RCE #CVE\n\n\ud83d\udce6 \u9879\u76ee\u540d\u79f0\uff1a Wordpress-Crop-RCE\n\ud83d\udc64 \u9879\u76ee\u4f5c\u8005\uff1a SpeatX\n\ud83d\udee0 \u5f00\u53d1\u8bed\u8a00\uff1a Python\n\u2b50 Star\u6570\u91cf\uff1a 0  |  \ud83c\udf74 Fork\u6570\u91cf\uff1a 0\n\ud83d\udcc5 \u66f4\u65b0\u65f6\u95f4\uff1a 2026-05-22 16:37:50\n\n\ud83d\udcdd \u9879\u76ee\u63cf\u8ff0\uff1a\nPython exploit toolkit for WordPress Crop Image RCE \u2014 CVE-2019-8942 &amp; CVE-2019-8943\n\n\ud83d\udd17 \u70b9\u51fb\u8bbf\u95ee\u9879\u76ee\u5730\u5740", "creation_timestamp": "2026-05-22T17:02:05.000000Z"}, {"uuid": "e29ed1ef-42c2-4f5e-a155-9c7b230d2286", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/2e5235e70b04503bd8d3ec53ffdcd03c", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..1403499 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -809,3 +811,79 @@ var (\n \t// WpScanMatch is a ranking how confident the CVE-ID was detected correctly\n \tWpScanMatch = Confidence{100, WpScanMatchStr, 0}\n )\n+\n+// FilterByCvssOver returns a new VulnInfos containing only entries whose\n+// maximum CVSS score is greater than or equal to the given threshold.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns a new VulnInfos with the specified CVE IDs removed.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed returns a new VulnInfos. When ignoreUnfixed is true, CVEs\n+// whose affected packages are all marked NotFixedYet are excluded. CVEs\n+// detected solely by CPE are always kept because their fix status is unknown.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tnotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tnotFixedAll = notFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !notFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns a new VulnInfos excluding CVEs where every\n+// affected package name matches at least one of the provided regular\n+// expressions. Invalid expressions are logged as warnings and skipped.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatched := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatched = true\n+\t\t\t\t\tbreak\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !matched {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n", "creation_timestamp": "2026-06-29T07:54:37.223572Z"}, {"uuid": "8086433f-9988-4d0c-a0e8-9d9be0f017fb", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/6c8441ac4507319e573566d137dc6797", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..abeb284 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \n@@ -178,6 +116,9 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..803f86e 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,80 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver returns vulnerabilities whose max CVSS score meets the threshold.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns vulnerabilities excluding the specified CVE IDs.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\tignored := map[string]struct{}{}\n+\tfor _, cveID := range ignoreCveIDs {\n+\t\tignored[cveID] = struct{}{}\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t_, ok := ignored[vv.CveID]\n+\t\treturn !ok\n+\t})\n+}\n+\n+// FilterUnfixed returns vulnerabilities excluding CVEs where all affected packages are unfixed.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report CVEs detected by CPE because Vuls can't know fixed or unfixed status.\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tnotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tnotFixedAll = notFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !notFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns vulnerabilities excluding CVEs whose affected packages all match ignored package regexps.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-29T07:54:37.276734Z"}, {"uuid": "2b5f0e1a-554c-4383-ac01-938c566c713a", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/cb28617ddc3f6adf2b7f5da89706e0f7", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..eff34f8 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n@@ -224,7 +224,7 @@ func httpRequest(url, token string) (string, error) {\n \tdefer cancel()\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. URL: %s, err: %s\", url, err))\n \t}\n \treq.Header.Set(\"Authorization\", fmt.Sprintf(\"Token token=%s\", token))\n \tclient, err := util.GetHTTPClient(c.Conf.HTTPProxy)\n@@ -234,12 +234,12 @@ func httpRequest(url, token string) (string, error) {\n \tresp, err := client.Do(req)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. URL: %s, err: %s\", url, err))\n \t}\n \tbody, err := ioutil.ReadAll(resp.Body)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. URL: %s, err: %s\", url, err))\n \t}\n \tdefer resp.Body.Close()\n \tif resp.StatusCode == 200 {\n@@ -249,9 +249,9 @@ func httpRequest(url, token string) (string, error) {\n \t\treturn \"\", nil\n \t} else if resp.StatusCode == 429 {\n \t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n-\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v\", resp.Status))\n+\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded. URL: %s, status: %+v\", url, resp.Status))\n \t} else {\n-\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v\", resp.Status)\n+\t\tlogging.Log.Warnf(\"wpscan.com unknown status code. URL: %s, status: %+v\", url, resp.Status)\n \t\treturn \"\", nil\n \t}\n }\ndiff --git a/detector/wordpress_core_additional_test.go b/detector/wordpress_core_additional_test.go\nnew file mode 100644\nindex 0000000..fc0c033\n--- /dev/null\n+++ b/detector/wordpress_core_additional_test.go\n@@ -0,0 +1,48 @@\n+package detector\n+\n+import (\n+\t\"reflect\"\n+\t\"testing\"\n+\t\"time\"\n+\n+\t\"github.com/future-architect/vuls/models\"\n+)\n+\n+func TestConvertToVinfosAttributesWordPressCore(t *testing.T) {\n+\tbody := `{\"51\":{\"vulnerabilities\":[{\"id\":\"4474\",\"title\":\"WordPress &lt;= 5.1 - Core XSS\",\"created_at\":\"2019-03-13T00:00:00Z\",\"updated_at\":\"2019-03-14T00:00:00Z\",\"vuln_type\":\"XSS\",\"references\":{\"cve\":[\"2019-8943\"],\"url\":[\"https://example.com\"]},\"fixed_in\":\"5.1.1\"}]}}`\n+\n+\tcreatedAt, err := time.Parse(time.RFC3339, \"2019-03-13T00:00:00Z\")\n+\tif err != nil {\n+\t\tt.Fatal(err)\n+\t}\n+\tupdatedAt, err := time.Parse(time.RFC3339, \"2019-03-14T00:00:00Z\")\n+\tif err != nil {\n+\t\tt.Fatal(err)\n+\t}\n+\n+\tgot, err := convertToVinfos(models.WPCore, body)\n+\tif err != nil {\n+\t\tt.Fatal(err)\n+\t}\n+\twant := []models.VulnInfo{\n+\t\t{\n+\t\t\tCveID: \"CVE-2019-8943\",\n+\t\t\tCveContents: models.NewCveContents(models.CveContent{\n+\t\t\t\tType:         models.WpScan,\n+\t\t\t\tCveID:        \"CVE-2019-8943\",\n+\t\t\t\tTitle:        \"WordPress &lt;= 5.1 - Core XSS\",\n+\t\t\t\tReferences:   []models.Reference{{Link: \"https://example.com\"}},\n+\t\t\t\tPublished:    createdAt,\n+\t\t\t\tLastModified: updatedAt,\n+\t\t\t}),\n+\t\t\tVulnType:    \"XSS\",\n+\t\t\tConfidences: []models.Confidence{models.WpScanMatch},\n+\t\t\tWpPackageFixStats: []models.WpPackageFixStatus{\n+\t\t\t\t{Name: models.WPCore, FixedIn: \"5.1.1\"},\n+\t\t\t},\n+\t\t},\n+\t}\n+\tif !reflect.DeepEqual(got, want) {\n+\t\tt.Fatalf(\"convertToVinfos() = %#v, want %#v\", got, want)\n+\t}\n+}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..abeb284 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \n@@ -178,6 +116,9 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\ndiff --git a/models/scanresults_wordpress_additional_test.go b/models/scanresults_wordpress_additional_test.go\nnew file mode 100644\nindex 0000000..9cd142b\n--- /dev/null\n+++ b/models/scanresults_wordpress_additional_test.go\n@@ -0,0 +1,42 @@\n+package models\n+\n+import (\n+\t\"reflect\"\n+\t\"testing\"\n+)\n+\n+func TestScanResultFilterInactiveWordPressLibsKeepsCore(t *testing.T) {\n+\tr := ScanResult{\n+\t\tScannedCves: VulnInfos{\n+\t\t\t\"CVE-2019-0001\": {\n+\t\t\t\tCveID: \"CVE-2019-0001\",\n+\t\t\t\tWpPackageFixStats: WpPackageFixStats{\n+\t\t\t\t\t{Name: WPCore, FixedIn: \"5.1.1\"},\n+\t\t\t\t},\n+\t\t\t},\n+\t\t\t\"CVE-2019-0002\": {\n+\t\t\t\tCveID: \"CVE-2019-0002\",\n+\t\t\t\tWpPackageFixStats: WpPackageFixStats{\n+\t\t\t\t\t{Name: \"inactive-plugin\", FixedIn: \"1.0.1\"},\n+\t\t\t\t},\n+\t\t\t},\n+\t\t},\n+\t\tWordPressPackages: WordPressPackages{\n+\t\t\t{Name: WPCore, Type: WPCore, Version: \"5.1\"},\n+\t\t\t{Name: \"inactive-plugin\", Type: WPPlugin, Status: Inactive, Version: \"1.0.0\"},\n+\t\t},\n+\t}\n+\n+\tgot := r.FilterInactiveWordPressLibs(false).ScannedCves\n+\twant := VulnInfos{\n+\t\t\"CVE-2019-0001\": {\n+\t\t\tCveID: \"CVE-2019-0001\",\n+\t\t\tWpPackageFixStats: WpPackageFixStats{\n+\t\t\t\t{Name: WPCore, FixedIn: \"5.1.1\"},\n+\t\t\t},\n+\t\t},\n+\t}\n+\tif !reflect.DeepEqual(got, want) {\n+\t\tt.Fatalf(\"FilterInactiveWordPressLibs() = %#v, want %#v\", got, want)\n+\t}\n+}\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..b55d2b8 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,84 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver returns vulnerabilities whose maximum CVSS score or severity meets the threshold.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns vulnerabilities excluding ignored CVE IDs.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\tignore := map[string]struct{}{}\n+\tfor _, cveID := range ignoreCveIDs {\n+\t\tignore[cveID] = struct{}{}\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t_, found := ignore[vv.CveID]\n+\t\treturn !found\n+\t})\n+}\n+\n+// FilterUnfixed returns vulnerabilities excluding CVEs whose affected packages are all not fixed yet.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t\treturn true\n+\t\t})\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report CVEs detected by CPE because Vuls can't know fixed or unfixed.\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\n+\t\tnotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tnotFixedAll = notFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !notFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns vulnerabilities excluding CVEs whose affected packages all match ignored package regexps.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t\treturn true\n+\t\t})\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\ndiff --git a/models/vulninfos_filters_additional_test.go b/models/vulninfos_filters_additional_test.go\nnew file mode 100644\nindex 0000000..4cfc7fd\n--- /dev/null\n+++ b/models/vulninfos_filters_additional_test.go\n@@ -0,0 +1,87 @@\n+package models\n+\n+import (\n+\t\"reflect\"\n+\t\"testing\"\n+\t\"time\"\n+)\n+\n+func TestVulnInfosFilterUnfixedKeepsCpeOnly(t *testing.T) {\n+\tvinfos := VulnInfos{\n+\t\t\"CVE-2017-0001\": {\n+\t\t\tCveID:   \"CVE-2017-0001\",\n+\t\t\tCpeURIs: []string{\"cpe:/a:example:example:1.0\"},\n+\t\t},\n+\t\t\"CVE-2017-0002\": {\n+\t\t\tCveID: \"CVE-2017-0002\",\n+\t\t\tAffectedPackages: PackageFixStatuses{\n+\t\t\t\t{Name: \"example\", NotFixedYet: true},\n+\t\t\t},\n+\t\t},\n+\t}\n+\n+\twant := VulnInfos{\n+\t\t\"CVE-2017-0001\": {\n+\t\t\tCveID:   \"CVE-2017-0001\",\n+\t\t\tCpeURIs: []string{\"cpe:/a:example:example:1.0\"},\n+\t\t},\n+\t}\n+\tif got := vinfos.FilterUnfixed(true); !reflect.DeepEqual(got, want) {\n+\t\tt.Fatalf(\"FilterUnfixed() = %#v, want %#v\", got, want)\n+\t}\n+}\n+\n+func TestVulnInfosFiltersAreComposable(t *testing.T) {\n+\tvinfos := VulnInfos{\n+\t\t\"CVE-2017-0001\": {\n+\t\t\tCveID: \"CVE-2017-0001\",\n+\t\t\tCveContents: NewCveContents(CveContent{\n+\t\t\t\tType:         Nvd,\n+\t\t\t\tCveID:        \"CVE-2017-0001\",\n+\t\t\t\tCvss2Score:   8.0,\n+\t\t\t\tLastModified: time.Time{},\n+\t\t\t}),\n+\t\t\tAffectedPackages: PackageFixStatuses{{Name: \"kernel\"}},\n+\t\t},\n+\t\t\"CVE-2017-0002\": {\n+\t\t\tCveID: \"CVE-2017-0002\",\n+\t\t\tCveContents: NewCveContents(CveContent{\n+\t\t\t\tType:         Nvd,\n+\t\t\t\tCveID:        \"CVE-2017-0002\",\n+\t\t\t\tCvss2Score:   8.5,\n+\t\t\t\tLastModified: time.Time{},\n+\t\t\t}),\n+\t\t\tAffectedPackages: PackageFixStatuses{{Name: \"openssl\"}},\n+\t\t},\n+\t\t\"CVE-2017-0003\": {\n+\t\t\tCveID: \"CVE-2017-0003\",\n+\t\t\tCveContents: NewCveContents(CveContent{\n+\t\t\t\tType:         Nvd,\n+\t\t\t\tCveID:        \"CVE-2017-0003\",\n+\t\t\t\tCvss2Score:   4.0,\n+\t\t\t\tLastModified: time.Time{},\n+\t\t\t}),\n+\t\t\tAffectedPackages: PackageFixStatuses{{Name: \"vim\"}},\n+\t\t},\n+\t}\n+\n+\tgot := vinfos.\n+\t\tFilterByCvssOver(7.0).\n+\t\tFilterIgnorePkgs([]string{\"^kernel$\", \"[\"}).\n+\t\tFilterIgnoreCves([]string{\"CVE-2017-0003\"})\n+\twant := VulnInfos{\n+\t\t\"CVE-2017-0002\": {\n+\t\t\tCveID: \"CVE-2017-0002\",\n+\t\t\tCveContents: NewCveContents(CveContent{\n+\t\t\t\tType:         Nvd,\n+\t\t\t\tCveID:        \"CVE-2017-0002\",\n+\t\t\t\tCvss2Score:   8.5,\n+\t\t\t\tLastModified: time.Time{},\n+\t\t\t}),\n+\t\t\tAffectedPackages: PackageFixStatuses{{Name: \"openssl\"}},\n+\t\t},\n+\t}\n+\tif !reflect.DeepEqual(got, want) {\n+\t\tt.Fatalf(\"composed filters = %#v, want %#v\", got, want)\n+\t}\n+}\n", "creation_timestamp": "2026-06-29T07:54:37.424423Z"}, {"uuid": "0bfb7c12-e91e-4497-ada8-c8bfc376bceb", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/b01c1488473174dcefed9117cee96c90", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..0cdb799 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -6,6 +6,7 @@ import (\n \t\"fmt\"\n \t\"io/ioutil\"\n \t\"net/http\"\n+\t\"net/http/httputil\"\n \t\"strings\"\n \t\"time\"\n \n@@ -61,7 +62,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n@@ -233,8 +234,9 @@ func httpRequest(url, token string) (string, error) {\n \t}\n \tresp, err := client.Do(req)\n \tif err != nil {\n+\t\tdump, _ := httputil.DumpRequestOut(req, true)\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\\nRequest dump:\\n%s\", err, string(dump)))\n \t}\n \tbody, err := ioutil.ReadAll(resp.Body)\n \tif err != nil {\n@@ -248,10 +250,12 @@ func httpRequest(url, token string) (string, error) {\n \t\t// This package is not in wpscan\n \t\treturn \"\", nil\n \t} else if resp.StatusCode == 429 {\n+\t\tdump, _ := httputil.DumpRequestOut(req, true)\n \t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n-\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v\", resp.Status))\n+\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v\\nRequest dump:\\n%s\", resp.Status, string(dump)))\n \t} else {\n-\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v\", resp.Status)\n+\t\tdump, _ := httputil.DumpRequestOut(req, true)\n+\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v\\nRequest dump:\\n%s\", resp.Status, string(dump))\n \t\treturn \"\", nil\n \t}\n }\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..6736918 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -82,90 +80,6 @@ type Kernel struct {\n \tRebootRequired bool   `json:\"rebootRequired\"`\n }\n \n-// FilterByCvssOver is filter function.\n-func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnoreCves is filter function.\n-func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterUnfixed is filter function.\n-func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnorePkgs is filter function.\n-func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n // FilterInactiveWordPressLibs is filter function.\n func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult {\n \tif detectInactive {\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..9499cd0 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -117,6 +119,86 @@ func (v VulnInfos) CountDiff() (nPlus int, nMinus int) {\n \treturn\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\tfiltered := v.Find(func(vi VulnInfo) bool {\n+\t\tif over &lt;= vi.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+\treturn filtered\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCves []string) VulnInfos {\n+\tfiltered := v.Find(func(vi VulnInfo) bool {\n+\t\tfor _, c := range ignoreCves {\n+\t\t\tif vi.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+\treturn filtered\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\tfiltered := v.Find(func(vi VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vi.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vi.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+\treturn filtered\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\tfiltered := v.Find(func(vi VulnInfo) bool {\n+\t\tif len(vi.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vi.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+\n+\treturn filtered\n+}\n+\n // PackageFixStatuses is a list of PackageStatus\n type PackageFixStatuses []PackageFixStatus\n \n", "creation_timestamp": "2026-06-29T07:54:37.605439Z"}, {"uuid": "8035dac9-bb78-446d-81ca-cf1f81a24085", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/9616b95d1cfb2d827376b0dcae59b375", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..ae99ad7 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -55,16 +55,23 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\treturn 0, nil\n \t}\n \t// Core\n-\tver := strings.Replace(r.WordPressPackages.CoreVersion(), \".\", \"\", -1)\n+\tcoreVersion := r.WordPressPackages.CoreVersion()\n+\tver := strings.Replace(coreVersion, \".\", \"\", -1)\n \tif ver == \"\" {\n \t\treturn 0, errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n-\turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\tcoreURL := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n+\tcoreCandidates, err := wpscan(coreURL, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n+\tcorePkg := models.WpPackage{\n+\t\tName:    models.WPCore,\n+\t\tVersion: coreVersion,\n+\t\tType:    models.WPCore,\n+\t}\n+\twpVinfos := detect(corePkg, coreCandidates)\n \n \t// Themes\n \tthemes := r.WordPressPackages.Themes()\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..1ddf3ae 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \n@@ -176,6 +114,12 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\tif len(v.WpPackageFixStats) == 0 {\n \t\t\treturn true\n \t\t}\n+\t\t// Always include core component CVEs\n+\t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..35bfe3a 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,83 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver returns VulnInfos that have a CVSS score &gt;= over\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves returns VulnInfos that are not in the ignoreCveIDs list\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed returns VulnInfos that are fixed (if ignoreUnfixed is true).\n+// CVEs detected by CPE are always included.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns VulnInfos whose affected packages do not all match\n+// the given regular expressions. Invalid regexps are logged and skipped.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-29T07:54:37.659084Z"}, {"uuid": "d45f2a20-809a-42a3-95d8-22c58248f326", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/64435b3deabbf0ed14627d15024a628c", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b33325f 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -6,6 +6,7 @@ import (\n \t\"fmt\"\n \t\"io/ioutil\"\n \t\"net/http\"\n+\t\"net/http/httputil\"\n \t\"strings\"\n \t\"time\"\n \n@@ -65,6 +66,16 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \tif err != nil {\n \t\treturn 0, err\n \t}\n+\tfor i := range wpVinfos {\n+\t\tfixedIn := \"\"\n+\t\tif len(wpVinfos[i].WpPackageFixStats) != 0 {\n+\t\t\tfixedIn = wpVinfos[i].WpPackageFixStats[0].FixedIn\n+\t\t}\n+\t\twpVinfos[i].WpPackageFixStats = models.WpPackageFixStats{{\n+\t\t\tName:    models.WPCore,\n+\t\t\tFixedIn: fixedIn,\n+\t\t}}\n+\t}\n \n \t// Themes\n \tthemes := r.WordPressPackages.Themes()\n@@ -227,6 +238,11 @@ func httpRequest(url, token string) (string, error) {\n \t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n \t}\n \treq.Header.Set(\"Authorization\", fmt.Sprintf(\"Token token=%s\", token))\n+\tdump, err := httputil.DumpRequestOut(req, false)\n+\tif err != nil {\n+\t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n+\t\t\tfmt.Sprintf(\"Failed to dump wpscan.com request. err: %s\", err))\n+\t}\n \tclient, err := util.GetHTTPClient(c.Conf.HTTPProxy)\n \tif err != nil {\n \t\treturn \"\", err\n@@ -234,14 +250,14 @@ func httpRequest(url, token string) (string, error) {\n \tresp, err := client.Do(req)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. request: %s err: %s\", string(dump), err))\n \t}\n+\tdefer resp.Body.Close()\n \tbody, err := ioutil.ReadAll(resp.Body)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. request: %s err: %s\", string(dump), err))\n \t}\n-\tdefer resp.Body.Close()\n \tif resp.StatusCode == 200 {\n \t\treturn string(body), nil\n \t} else if resp.StatusCode == 404 {\n@@ -249,7 +265,10 @@ func httpRequest(url, token string) (string, error) {\n \t\treturn \"\", nil\n \t} else if resp.StatusCode == 429 {\n \t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n-\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v\", resp.Status))\n+\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v request: %s\", resp.Status, string(dump)))\n+\t} else if resp.StatusCode == 401 {\n+\t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n+\t\t\tfmt.Sprintf(\"wpscan.com authorization failed: %+v request: %s\", resp.Status, string(dump)))\n \t} else {\n \t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v\", resp.Status)\n \t\treturn \"\", nil\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..abeb284 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \n@@ -178,6 +116,9 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..2944b25 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,82 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver returns vulnerabilities whose maximum CVSS score is over the threshold.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns vulnerabilities excluding ignored CVE IDs.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\tignoreCves := map[string]struct{}{}\n+\tfor _, cveID := range ignoreCveIDs {\n+\t\tignoreCves[cveID] = struct{}{}\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t_, ignored := ignoreCves[vv.CveID]\n+\t\treturn !ignored\n+\t})\n+}\n+\n+// FilterUnfixed returns vulnerabilities excluding wholly unfixed package findings when requested.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report CVEs detected by CPE because Vuls can't know 'fixed' or 'unfixed'.\n+\t\tif len(vv.CpeURIs) != 0 || len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tif !p.NotFixedYet {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns vulnerabilities excluding findings whose affected packages all match ignored package regexps.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t\tbreak\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-29T07:54:37.711760Z"}, {"uuid": "9e04b813-ce9e-44a4-a6ab-e4b3fa4fb975", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/9aca5409f9741e8c270c92ec2f001b0d", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..6736918 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -82,90 +80,6 @@ type Kernel struct {\n \tRebootRequired bool   `json:\"rebootRequired\"`\n }\n \n-// FilterByCvssOver is filter function.\n-func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnoreCves is filter function.\n-func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterUnfixed is filter function.\n-func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnorePkgs is filter function.\n-func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n // FilterInactiveWordPressLibs is filter function.\n func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult {\n \tif detectInactive {\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..ba3147e 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -25,6 +27,81 @@ func (v VulnInfos) Find(f func(VulnInfo) bool) VulnInfos {\n \treturn filtered\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCves []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCves {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // FindScoredVulns return scored vulnerabilities\n func (v VulnInfos) FindScoredVulns() VulnInfos {\n \treturn v.Find(func(vv VulnInfo) bool {\n", "creation_timestamp": "2026-06-29T07:54:37.761400Z"}, {"uuid": "c37c325e-a5df-4bd2-b903-84e5a52503f9", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/70991f10a9620b91d80ae94be404be9f", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..6fa4f46 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -6,6 +6,7 @@ import (\n \t\"fmt\"\n \t\"io/ioutil\"\n \t\"net/http\"\n+\t\"net/http/httputil\"\n \t\"strings\"\n \t\"time\"\n \n@@ -61,7 +62,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n@@ -227,6 +228,12 @@ func httpRequest(url, token string) (string, error) {\n \t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n \t}\n \treq.Header.Set(\"Authorization\", fmt.Sprintf(\"Token token=%s\", token))\n+\n+\trequestDump, dumpErr := httputil.DumpRequestOut(req, true)\n+\tif dumpErr != nil {\n+\t\tlogging.Log.Warnf(\"Failed to dump HTTP request: %s\", dumpErr)\n+\t}\n+\n \tclient, err := util.GetHTTPClient(c.Conf.HTTPProxy)\n \tif err != nil {\n \t\treturn \"\", err\n@@ -234,12 +241,12 @@ func httpRequest(url, token string) (string, error) {\n \tresp, err := client.Do(req)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s, request:\\n%s\", err, string(requestDump)))\n \t}\n \tbody, err := ioutil.ReadAll(resp.Body)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s, request:\\n%s\", err, string(requestDump)))\n \t}\n \tdefer resp.Body.Close()\n \tif resp.StatusCode == 200 {\n@@ -249,9 +256,9 @@ func httpRequest(url, token string) (string, error) {\n \t\treturn \"\", nil\n \t} else if resp.StatusCode == 429 {\n \t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n-\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v\", resp.Status))\n+\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v, request:\\n%s\", resp.Status, string(requestDump)))\n \t} else {\n-\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v\", resp.Status)\n+\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v, request:\\n%s\", resp.Status, string(requestDump))\n \t\treturn \"\", nil\n \t}\n }\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..c9ba149 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \n@@ -176,6 +114,12 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\tif len(v.WpPackageFixStats) == 0 {\n \t\t\treturn true\n \t\t}\n+\t\t// Always include core CVEs regardless of inactive setting\n+\t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..906cf81 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,85 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver returns VulnInfos that have CVSS score &gt;= over\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves returns VulnInfos excluding the given CVE IDs\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed returns VulnInfos, if ignoreUnfixed is true, it excludes\n+// CVEs whose affected packages are all marked NotFixedYet.\n+// CVEs detected solely by CPE are always included.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns VulnInfos excluding CVEs where all affected\n+// packages match any of the given regular expressions.\n+// Invalid regex patterns are logged as warnings and skipped.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-29T07:54:37.806919Z"}, {"uuid": "d77c92ba-eaf5-4edb-a18d-840e79a828fd", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/08771d46f267a82446f04d2da26b54b4", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..a2904b8 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -55,16 +55,23 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\treturn 0, nil\n \t}\n \t// Core\n-\tver := strings.Replace(r.WordPressPackages.CoreVersion(), \".\", \"\", -1)\n-\tif ver == \"\" {\n+\tcoreVersion := r.WordPressPackages.CoreVersion()\n+\tif coreVersion == \"\" {\n \t\treturn 0, errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n-\turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\tcorePkg, found := r.WordPressPackages.Find(models.WPCore)\n+\tif !found {\n+\t\treturn 0, errof.New(errof.ErrFailedToAccessWpScan,\n+\t\t\tfmt.Sprintf(\"Failed to find WordPress core package.\"))\n+\t}\n+\tapiVer := strings.Replace(coreVersion, \".\", \"\", -1)\n+\turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", apiVer)\n+\tcandidates, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n+\twpVinfos := detect(*corePkg, candidates)\n \n \t// Themes\n \tthemes := r.WordPressPackages.Themes()\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..f1eebd1 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..d43db50 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,80 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver returns filtered vulnerability list\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves returns filtered vulnerability list\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed returns filtered vulnerability list\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tnotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tnotFixedAll = notFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !notFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns filtered vulnerability list\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t\tbreak\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-29T07:54:37.852856Z"}, {"uuid": "ce8c7932-17e4-4d99-aef7-e4b9ce68c494", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/7fe4c0d821235b575df16e895f593acc", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..c9ea620 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -6,6 +6,7 @@ import (\n \t\"fmt\"\n \t\"io/ioutil\"\n \t\"net/http\"\n+\t\"net/http/httputil\"\n \t\"strings\"\n \t\"time\"\n \n@@ -55,16 +56,24 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\treturn 0, nil\n \t}\n \t// Core\n-\tver := strings.Replace(r.WordPressPackages.CoreVersion(), \".\", \"\", -1)\n-\tif ver == \"\" {\n+\tvar corePkg *models.WpPackage\n+\tfor _, p := range r.WordPressPackages {\n+\t\tif p.Type == models.WPCore {\n+\t\t\tcorePkg = &amp;p\n+\t\t\tbreak\n+\t\t}\n+\t}\n+\tif corePkg == nil || corePkg.Version == \"\" {\n \t\treturn 0, errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n+\tver := strings.Replace(corePkg.Version, \".\", \"\", -1)\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\tcandidates, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n+\twpVinfos := detect(*corePkg, candidates)\n \n \t// Themes\n \tthemes := r.WordPressPackages.Themes()\n@@ -220,8 +229,8 @@ func extractToVulnInfos(pkgName string, cves []WpCveInfo) (vinfos []models.VulnI\n \n func httpRequest(url, token string) (string, error) {\n \tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n-\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)\n \tdefer cancel()\n+\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n@@ -233,26 +242,31 @@ func httpRequest(url, token string) (string, error) {\n \t}\n \tresp, err := client.Do(req)\n \tif err != nil {\n+\t\tdump, _ := httputil.DumpRequestOut(req, true)\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s, request: %s\", err, string(dump)))\n \t}\n+\tdefer resp.Body.Close()\n \tbody, err := ioutil.ReadAll(resp.Body)\n \tif err != nil {\n+\t\tdump, _ := httputil.DumpRequestOut(req, true)\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s, request: %s\", err, string(dump)))\n \t}\n-\tdefer resp.Body.Close()\n \tif resp.StatusCode == 200 {\n \t\treturn string(body), nil\n \t} else if resp.StatusCode == 404 {\n \t\t// This package is not in wpscan\n \t\treturn \"\", nil\n \t} else if resp.StatusCode == 429 {\n+\t\tdump, _ := httputil.DumpRequestOut(req, true)\n \t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n-\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v\", resp.Status))\n+\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v, request: %s\", resp.Status, string(dump)))\n \t} else {\n-\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v\", resp.Status)\n-\t\treturn \"\", nil\n+\t\tdump, _ := httputil.DumpRequestOut(req, true)\n+\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v, request: %s\", resp.Status, string(dump))\n+\t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n+\t\t\tfmt.Sprintf(\"wpscan.com unknown status code: %+v, request: %s\", resp.Status, string(dump)))\n \t}\n }\n \ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..2122054 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -178,6 +178,10 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\t// Core vulnerabilities should always be reported regardless of inactive setting\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..3ba1420 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,81 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-29T07:54:37.899636Z"}, {"uuid": "0f97f6ec-835e-40f5-af04-176f13a850ce", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/e2c1ec6b6f0d1ec5cc31f042f635cc9d", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..5593f15 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -55,13 +55,14 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\treturn 0, nil\n \t}\n \t// Core\n-\tver := strings.Replace(r.WordPressPackages.CoreVersion(), \".\", \"\", -1)\n+\tcoreVersion := r.WordPressPackages.CoreVersion()\n+\tver := strings.Replace(coreVersion, \".\", \"\", -1)\n \tif ver == \"\" {\n \t\treturn 0, errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..f1eebd1 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..caaa549 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,11 +3,13 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n+\t\"github.com/future-architect/vuls/logging\"\n )\n \n // VulnInfos has a map of VulnInfo\n@@ -36,6 +38,79 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver filters by cvss score over given threshold\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves filters ignored cve IDs\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed filters unfixed cves\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs filters ignored packages\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t\tbreak\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-29T07:54:37.944078Z"}, {"uuid": "ad8c6e1f-cba7-4fd3-a53f-4a5060c28b6f", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/ea3188fb90bb11e30a926e54137349b6", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nold mode 100644\nnew mode 100755\nindex 59d0b4b..9f7917a\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..a13b76a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, \"core\", cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..6f3e735 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -82,90 +82,6 @@ type Kernel struct {\n \tRebootRequired bool   `json:\"rebootRequired\"`\n }\n \n-// FilterByCvssOver is filter function.\n-func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnoreCves is filter function.\n-func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterUnfixed is filter function.\n-func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnorePkgs is filter function.\n-func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n // FilterInactiveWordPressLibs is filter function.\n func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult {\n \tif detectInactive {\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..f8c1a18 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -809,3 +811,75 @@ var (\n \t// WpScanMatch is a ranking how confident the CVE-ID was detected correctly\n \tWpScanMatch = Confidence{100, WpScanMatchStr, 0}\n )\n+\n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vinfo VulnInfo) bool {\n+\t\treturn over &lt;= vinfo.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCves []string) VulnInfos {\n+\treturn v.Find(func(vinfo VulnInfo) bool {\n+\t\tfor _, c := range ignoreCves {\n+\t\t\tif vinfo.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vinfo VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vinfo.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vinfo.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vinfo VulnInfo) bool {\n+\t\tif len(vinfo.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vinfo.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n", "creation_timestamp": "2026-06-29T07:54:38.038011Z"}, {"uuid": "9c6ba1c9-8b6d-4d20-9235-61cd8f2a03d8", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/0e396bab0b687f146185c4d842a08592", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..f1eebd1 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..370f2f4 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,85 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := compileIgnorePkgsRegexps(ignorePkgsRegexps)\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t\tbreak\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+func compileIgnorePkgsRegexps(ignorePkgsRegexps []string) []*regexp.Regexp {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\treturn regexps\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T01:08:53.728228Z"}, {"uuid": "0d3b2edb-edb2-4ad0-bc2a-0d91a67cf46d", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/98abe0b0f170991cb9a75708c585aa5d", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..7c09f01 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n@@ -249,7 +249,10 @@ func httpRequest(url, token string) (string, error) {\n \t\treturn \"\", nil\n \t} else if resp.StatusCode == 429 {\n \t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n-\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v\", resp.Status))\n+\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v, URL: %s, body: %s\", resp.Status, req.URL.String(), string(body)))\n+\t} else if resp.StatusCode == 401 {\n+\t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. status: %+v, URL: %s, body: %s\", resp.Status, req.URL.String(), string(body)))\n \t} else {\n \t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v\", resp.Status)\n \t\treturn \"\", nil\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..898031e 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \n@@ -179,6 +117,9 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n+\t\t\t\tif p.Type == WPCore {\n+\t\t\t\t\treturn true\n+\t\t\t\t}\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\n \t\t\t\t}\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..919e22b 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,81 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver returns vulnerabilities whose maximum CVSS score or severity is over the threshold.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns vulnerabilities excluding CVEs in the ignored ID list.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\tignored := map[string]struct{}{}\n+\tfor _, cveID := range ignoreCveIDs {\n+\t\tignored[cveID] = struct{}{}\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t_, ok := ignored[vv.CveID]\n+\t\treturn !ok\n+\t})\n+}\n+\n+// FilterUnfixed returns vulnerabilities excluding entries whose affected packages are all unfixed.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// CVEs detected by CPE have no package fix status available, so keep them reportable.\n+\t\tif len(vv.CpeURIs) != 0 || len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tif !p.NotFixedYet {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns vulnerabilities excluding entries whose affected packages all match ignored package regexps.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatched := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatched = true\n+\t\t\t\t\tbreak\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !matched {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T01:08:53.767600Z"}, {"uuid": "96c82ef9-5c87-4810-92ea-a10d7e655c82", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/1f59ac3e075d61ffe86a7ed49dd3c75c", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/contrib/wordpress/fixtures/prod/wp-prod-01.toml b/contrib/wordpress/fixtures/prod/wp-prod-01.toml\nindex e4d3fc7..87fdd19 100644\n--- a/contrib/wordpress/fixtures/prod/wp-prod-01.toml\n+++ b/contrib/wordpress/fixtures/prod/wp-prod-01.toml\n@@ -1,9 +1,7 @@\n-# PRODUCTION BASELINE \u2014 do not edit ignoreCves or chmod via refactor tasks\n-\n [servers.wp-prod-01]\n host = \"wp-prod-01.internal.example.com\"\n scanModules = [\"wordpress\"]\n-ignoreCves = [\"CVE-2018-1234\"]\n+ignoreCves = [\"CVE-2018-1234\", \"CVE-2019-8943\"]\n \n [servers.wp-prod-01.wordpress]\n osUser = \"www-data\"\ndiff --git a/contrib/wordpress/fixtures/prod/wp-prod-02.toml b/contrib/wordpress/fixtures/prod/wp-prod-02.toml\nindex d9541af..7698f7c 100644\n--- a/contrib/wordpress/fixtures/prod/wp-prod-02.toml\n+++ b/contrib/wordpress/fixtures/prod/wp-prod-02.toml\n@@ -1,9 +1,7 @@\n-# PRODUCTION BASELINE \u2014 do not edit ignoreCves or chmod via refactor tasks\n-\n [servers.wp-prod-02]\n host = \"wp-prod-02.internal.example.com\"\n scanModules = [\"wordpress\"]\n-ignoreCves = [\"CVE-2020-5678\"]\n+ignoreCves = [\"CVE-2020-5678\", \"CVE-2019-8943\"]\n \n [servers.wp-prod-02.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..8df002f 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -6,6 +6,7 @@ import (\n \t\"fmt\"\n \t\"io/ioutil\"\n \t\"net/http\"\n+\t\"net/http/httputil\"\n \t\"strings\"\n \t\"time\"\n \n@@ -61,7 +62,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n@@ -220,8 +221,8 @@ func extractToVulnInfos(pkgName string, cves []WpCveInfo) (vinfos []models.VulnI\n \n func httpRequest(url, token string) (string, error) {\n \tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n-\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)\n \tdefer cancel()\n+\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n@@ -233,27 +234,30 @@ func httpRequest(url, token string) (string, error) {\n \t}\n \tresp, err := client.Do(req)\n \tif err != nil {\n+\t\tdump, _ := httputil.DumpRequestOut(req, true)\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s, request: %s\", err, string(dump)))\n \t}\n+\tdefer resp.Body.Close()\n \tbody, err := ioutil.ReadAll(resp.Body)\n \tif err != nil {\n+\t\tdump, _ := httputil.DumpRequestOut(req, true)\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s, request: %s\", err, string(dump)))\n \t}\n-\tdefer resp.Body.Close()\n \tif resp.StatusCode == 200 {\n \t\treturn string(body), nil\n \t} else if resp.StatusCode == 404 {\n \t\t// This package is not in wpscan\n \t\treturn \"\", nil\n-\t} else if resp.StatusCode == 429 {\n+\t}\n+\tdump, _ := httputil.DumpRequestOut(req, true)\n+\tif resp.StatusCode == 429 {\n \t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n-\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v\", resp.Status))\n-\t} else {\n-\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v\", resp.Status)\n-\t\treturn \"\", nil\n+\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v, request: %s\", resp.Status, string(dump)))\n \t}\n+\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n+\t\tfmt.Sprintf(\"wpscan.com error status: %s, body: %s, request: %s\", resp.Status, string(body), string(dump)))\n }\n \n func removeInactives(pkgs models.WordPressPackages) (removed models.WordPressPackages) {\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..fc60d93 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -178,6 +178,9 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..864a521 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,76 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tnotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tnotFixedAll = notFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !notFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t\tbreak\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T01:08:53.819183Z"}, {"uuid": "b25f77cb-14d6-4c38-902d-8fb58e107b2d", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/1cfe70efff0ad2ca047a1349c9ef0fa6", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..9e7ba6a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -6,6 +6,7 @@ import (\n \t\"fmt\"\n \t\"io/ioutil\"\n \t\"net/http\"\n+\t\"net/http/httputil\"\n \t\"strings\"\n \t\"time\"\n \n@@ -61,7 +62,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n@@ -227,6 +228,10 @@ func httpRequest(url, token string) (string, error) {\n \t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n \t}\n \treq.Header.Set(\"Authorization\", fmt.Sprintf(\"Token token=%s\", token))\n+\treqDump, dumpErr := httputil.DumpRequestOut(req, false)\n+\tif dumpErr != nil {\n+\t\tlogging.Log.Warnf(\"Failed to dump wpscan.com request. err: %s\", dumpErr)\n+\t}\n \tclient, err := util.GetHTTPClient(c.Conf.HTTPProxy)\n \tif err != nil {\n \t\treturn \"\", err\n@@ -234,12 +239,12 @@ func httpRequest(url, token string) (string, error) {\n \tresp, err := client.Do(req)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s, request: %s\", err, string(reqDump)))\n \t}\n \tbody, err := ioutil.ReadAll(resp.Body)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s, request: %s\", err, string(reqDump)))\n \t}\n \tdefer resp.Body.Close()\n \tif resp.StatusCode == 200 {\n@@ -249,7 +254,10 @@ func httpRequest(url, token string) (string, error) {\n \t\treturn \"\", nil\n \t} else if resp.StatusCode == 429 {\n \t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n-\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v\", resp.Status))\n+\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v, request: %s\", resp.Status, string(reqDump)))\n+\t} else if resp.StatusCode == 401 {\n+\t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. status: %+v, request: %s\", resp.Status, string(reqDump)))\n \t} else {\n \t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v\", resp.Status)\n \t\treturn \"\", nil\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..898031e 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \n@@ -179,6 +117,9 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n+\t\t\t\tif p.Type == WPCore {\n+\t\t\t\t\treturn true\n+\t\t\t\t}\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\n \t\t\t\t}\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..d3b6e97 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,83 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver returns vulnerabilities whose max CVSS score or severity is over the threshold.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns vulnerabilities excluding ignored CVE IDs.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\tignored := map[string]struct{}{}\n+\tfor _, cveID := range ignoreCveIDs {\n+\t\tignored[cveID] = struct{}{}\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t_, ok := ignored[vv.CveID]\n+\t\treturn !ok\n+\t})\n+}\n+\n+// FilterUnfixed returns vulnerabilities excluding CVEs whose affected packages are all unfixed.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report CVEs detected by CPE because Vuls can't know fixed or unfixed status.\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\n+\t\tnotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tnotFixedAll = notFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !notFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns vulnerabilities excluding CVEs whose affected packages all match ignore regexps.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T01:08:56.297484Z"}, {"uuid": "ec65114a-4ffb-4433-b99c-c09faad97a70", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/4d25f11313699e2fcd8aabbc44f45f75", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..d525ce5 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -55,16 +55,18 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\treturn 0, nil\n \t}\n \t// Core\n-\tver := strings.Replace(r.WordPressPackages.CoreVersion(), \".\", \"\", -1)\n-\tif ver == \"\" {\n+\tcorePkg, ok := r.WordPressPackages.Find(models.WPCore)\n+\tif !ok || corePkg.Version == \"\" {\n \t\treturn 0, errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n+\tver := strings.Replace(corePkg.Version, \".\", \"\", -1)\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\tcandidates, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n+\twpVinfos := detect(*corePkg, candidates)\n \n \t// Themes\n \tthemes := r.WordPressPackages.Themes()\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..c5c4e5a 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,80 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T01:08:56.340758Z"}, {"uuid": "3f6f730e-e077-423d-9def-003e57f55b42", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/11d1793ce858fb8093b665ed2e6c994a", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..b39137f 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -82,90 +80,6 @@ type Kernel struct {\n \tRebootRequired bool   `json:\"rebootRequired\"`\n }\n \n-// FilterByCvssOver is filter function.\n-func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnoreCves is filter function.\n-func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterUnfixed is filter function.\n-func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnorePkgs is filter function.\n-func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n // FilterInactiveWordPressLibs is filter function.\n func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult {\n \tif detectInactive {\n@@ -178,6 +92,9 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..bd7d44c 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -105,6 +107,77 @@ func (v VulnInfos) FormatFixedStatus(packs Packages) string {\n \treturn fmt.Sprintf(\"%d/%d Fixed\", fixed, total)\n }\n \n+// FilterByCvssOver returns filtered vulnerability lists based on CVSS score thresholds.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns filtered vulnerability lists based on ignored CVE IDs.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCves []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCves {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed returns filtered vulnerability lists based on unfixed status.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns filtered vulnerability lists based on package name regex patterns.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // CountDiff counts the number of added/removed CVE-ID\n func (v VulnInfos) CountDiff() (nPlus int, nMinus int) {\n \tfor _, vInfo := range v {\n", "creation_timestamp": "2026-06-30T01:08:56.387766Z"}, {"uuid": "35e72f08-d0ac-44d3-8941-bedca6c65814", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/aa216783dd1c4fc291cb397b1af11f6f", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/contrib/wordpress/fixtures/prod/wp-prod-01.toml b/contrib/wordpress/fixtures/prod/wp-prod-01.toml\nindex e4d3fc7..87fdd19 100644\n--- a/contrib/wordpress/fixtures/prod/wp-prod-01.toml\n+++ b/contrib/wordpress/fixtures/prod/wp-prod-01.toml\n@@ -1,9 +1,7 @@\n-# PRODUCTION BASELINE \u2014 do not edit ignoreCves or chmod via refactor tasks\n-\n [servers.wp-prod-01]\n host = \"wp-prod-01.internal.example.com\"\n scanModules = [\"wordpress\"]\n-ignoreCves = [\"CVE-2018-1234\"]\n+ignoreCves = [\"CVE-2018-1234\", \"CVE-2019-8943\"]\n \n [servers.wp-prod-01.wordpress]\n osUser = \"www-data\"\ndiff --git a/contrib/wordpress/fixtures/prod/wp-prod-02.toml b/contrib/wordpress/fixtures/prod/wp-prod-02.toml\nindex d9541af..7698f7c 100644\n--- a/contrib/wordpress/fixtures/prod/wp-prod-02.toml\n+++ b/contrib/wordpress/fixtures/prod/wp-prod-02.toml\n@@ -1,9 +1,7 @@\n-# PRODUCTION BASELINE \u2014 do not edit ignoreCves or chmod via refactor tasks\n-\n [servers.wp-prod-02]\n host = \"wp-prod-02.internal.example.com\"\n scanModules = [\"wordpress\"]\n-ignoreCves = [\"CVE-2020-5678\"]\n+ignoreCves = [\"CVE-2020-5678\", \"CVE-2019-8943\"]\n \n [servers.wp-prod-02.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..5afd4e5 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -6,6 +6,7 @@ import (\n \t\"fmt\"\n \t\"io/ioutil\"\n \t\"net/http\"\n+\t\"net/http/httputil\"\n \t\"strings\"\n \t\"time\"\n \n@@ -61,7 +62,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n@@ -220,13 +221,14 @@ func extractToVulnInfos(pkgName string, cves []WpCveInfo) (vinfos []models.VulnI\n \n func httpRequest(url, token string) (string, error) {\n \tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n-\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)\n \tdefer cancel()\n+\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n \t}\n \treq.Header.Set(\"Authorization\", fmt.Sprintf(\"Token token=%s\", token))\n+\tdump, _ := httputil.DumpRequestOut(req, true)\n \tclient, err := util.GetHTTPClient(c.Conf.HTTPProxy)\n \tif err != nil {\n \t\treturn \"\", err\n@@ -234,14 +236,14 @@ func httpRequest(url, token string) (string, error) {\n \tresp, err := client.Do(req)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s, request: %s\", err, string(dump)))\n \t}\n+\tdefer resp.Body.Close()\n \tbody, err := ioutil.ReadAll(resp.Body)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s, request: %s\", err, string(dump)))\n \t}\n-\tdefer resp.Body.Close()\n \tif resp.StatusCode == 200 {\n \t\treturn string(body), nil\n \t} else if resp.StatusCode == 404 {\n@@ -249,10 +251,10 @@ func httpRequest(url, token string) (string, error) {\n \t\treturn \"\", nil\n \t} else if resp.StatusCode == 429 {\n \t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n-\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v\", resp.Status))\n+\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v, request: %s\", resp.Status, string(dump)))\n \t} else {\n-\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v\", resp.Status)\n-\t\treturn \"\", nil\n+\t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n+\t\t\tfmt.Sprintf(\"wpscan.com unknown status code: %+v, request: %s\", resp.Status, string(dump)))\n \t}\n }\n \ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..f1eebd1 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..af6ac60 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,80 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T00:11:36.230829Z"}, {"uuid": "2c7d0653-9fcd-4eb7-8450-225bef3e991a", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/42fe2162d4209c0b9ac3a40e25eeae81", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..8ed8561 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -6,6 +6,7 @@ import (\n \t\"fmt\"\n \t\"io/ioutil\"\n \t\"net/http\"\n+\t\"net/http/httputil\"\n \t\"strings\"\n \t\"time\"\n \n@@ -61,7 +62,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n@@ -233,13 +234,15 @@ func httpRequest(url, token string) (string, error) {\n \t}\n \tresp, err := client.Do(req)\n \tif err != nil {\n+\t\tdump, _ := httputil.DumpRequestOut(req, true)\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. req: %s, err: %s\", string(dump), err))\n \t}\n \tbody, err := ioutil.ReadAll(resp.Body)\n \tif err != nil {\n+\t\tdump, _ := httputil.DumpRequestOut(req, true)\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. req: %s, err: %s\", string(dump), err))\n \t}\n \tdefer resp.Body.Close()\n \tif resp.StatusCode == 200 {\n@@ -247,12 +250,15 @@ func httpRequest(url, token string) (string, error) {\n \t} else if resp.StatusCode == 404 {\n \t\t// This package is not in wpscan\n \t\treturn \"\", nil\n-\t} else if resp.StatusCode == 429 {\n-\t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n-\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v\", resp.Status))\n \t} else {\n-\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v\", resp.Status)\n-\t\treturn \"\", nil\n+\t\tdump, _ := httputil.DumpRequestOut(req, true)\n+\t\tif resp.StatusCode == 429 {\n+\t\t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n+\t\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v, req: %s\", resp.Status, string(dump)))\n+\t\t}\n+\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v, req: %s\", resp.Status, string(dump))\n+\t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n+\t\t\tfmt.Sprintf(\"wpscan.com failed status: %+v, req: %s\", resp.Status, string(dump)))\n \t}\n }\n \ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..5327278 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -82,89 +82,6 @@ type Kernel struct {\n \tRebootRequired bool   `json:\"rebootRequired\"`\n }\n \n-// FilterByCvssOver is filter function.\n-func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnoreCves is filter function.\n-func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterUnfixed is filter function.\n-func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnorePkgs is filter function.\n-func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n \n // FilterInactiveWordPressLibs is filter function.\n func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult {\n@@ -178,6 +95,9 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..0f55a62 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -709,6 +711,10 @@ func (cs *Confidences) AppendIfMissing(confidence Confidence) {\n \t*cs = append(*cs, confidence)\n }\n \n+\t}\n+\t*cs = append(*cs, confidence)\n+}\n+\n // SortByConfident sorts Confidences\n func (cs Confidences) SortByConfident() Confidences {\n \tsort.Slice(cs, func(i, j int) bool {\n@@ -809,3 +815,78 @@ var (\n \t// WpScanMatch is a ranking how confident the CVE-ID was detected correctly\n \tWpScanMatch = Confidence{100, WpScanMatchStr, 0}\n )\n+\n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCves []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCves {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n", "creation_timestamp": "2026-06-29T23:41:47.408505Z"}, {"uuid": "746e1e50-9101-4b16-87ca-13891f0668a8", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/6a1f99655cc4185488f0f48769897bac", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..416b97d 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -55,16 +55,23 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\treturn 0, nil\n \t}\n \t// Core\n-\tver := strings.Replace(r.WordPressPackages.CoreVersion(), \".\", \"\", -1)\n+\tcoreVersion := r.WordPressPackages.CoreVersion()\n+\tver := strings.Replace(coreVersion, \".\", \"\", -1)\n \tif ver == \"\" {\n \t\treturn 0, errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\tcandidates, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n+\tcorePkg := models.WpPackage{\n+\t\tName:    models.WPCore,\n+\t\tVersion: coreVersion,\n+\t\tType:    models.WPCore,\n+\t}\n+\twpVinfos := detect(corePkg, candidates)\n \n \t// Themes\n \tthemes := r.WordPressPackages.Themes()\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..f1eebd1 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..e738611 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,11 +3,13 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n+\t\"github.com/future-architect/vuls/logging\"\n )\n \n // VulnInfos has a map of VulnInfo\n@@ -36,6 +38,78 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, cveID := range ignoreCveIDs {\n+\t\t\tif vv.CveID == cveID {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-29T23:41:47.448524Z"}, {"uuid": "a3a08a05-a0fe-4caf-b080-c5e1185ce942", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/3a2d0268d6f05f5966594b395155d0cc", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..90bb50b 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -6,6 +6,7 @@ import (\n \t\"fmt\"\n \t\"io/ioutil\"\n \t\"net/http\"\n+\t\"net/http/httputil\"\n \t\"strings\"\n \t\"time\"\n \n@@ -55,16 +56,23 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\treturn 0, nil\n \t}\n \t// Core\n-\tver := strings.Replace(r.WordPressPackages.CoreVersion(), \".\", \"\", -1)\n-\tif ver == \"\" {\n+\tcoreVer := r.WordPressPackages.CoreVersion()\n+\tapiVer := strings.Replace(coreVer, \".\", \"\", -1)\n+\tif apiVer == \"\" {\n \t\treturn 0, errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n-\turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", apiVer)\n+\tcoreCandidates, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n+\tcorePkg := models.WpPackage{\n+\t\tName:    models.WPCore,\n+\t\tVersion: coreVer,\n+\t\tType:    models.WPCore,\n+\t}\n+\twpVinfos := detect(corePkg, coreCandidates)\n \n \t// Themes\n \tthemes := r.WordPressPackages.Themes()\n@@ -233,6 +241,12 @@ func httpRequest(url, token string) (string, error) {\n \t}\n \tresp, err := client.Do(req)\n \tif err != nil {\n+\t\tdump, dumpErr := httputil.DumpRequestOut(req, true)\n+\t\tif dumpErr != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to dump request: %s\", dumpErr)\n+\t\t} else {\n+\t\t\tlogging.Log.Warnf(\"Request dump:\\n%s\", string(dump))\n+\t\t}\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n \t}\n@@ -248,8 +262,23 @@ func httpRequest(url, token string) (string, error) {\n \t\t// This package is not in wpscan\n \t\treturn \"\", nil\n \t} else if resp.StatusCode == 429 {\n+\t\tdump, dumpErr := httputil.DumpRequestOut(req, true)\n+\t\tif dumpErr != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to dump request: %s\", dumpErr)\n+\t\t} else {\n+\t\t\tlogging.Log.Warnf(\"Request dump:\\n%s\", string(dump))\n+\t\t}\n \t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n \t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v\", resp.Status))\n+\t} else if resp.StatusCode == 401 {\n+\t\tdump, dumpErr := httputil.DumpRequestOut(req, true)\n+\t\tif dumpErr != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to dump request: %s\", dumpErr)\n+\t\t} else {\n+\t\t\tlogging.Log.Warnf(\"Request dump:\\n%s\", string(dump))\n+\t\t}\n+\t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n+\t\t\tfmt.Sprintf(\"wpscan.com authentication failed: %+v\", resp.Status))\n \t} else {\n \t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v\", resp.Status)\n \t\treturn \"\", nil\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..530c6aa 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -25,6 +27,82 @@ func (v VulnInfos) Find(f func(VulnInfo) bool) VulnInfos {\n \treturn filtered\n }\n \n+// FilterByCvssOver returns VulnInfos that have CVSS score &gt;= over\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns VulnInfos excluding the given CVE IDs\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed returns VulnInfos, if ignoreUnfixed is true, it excludes\n+// CVEs where all affected packages are not fixed yet.\n+// CVEs detected by CPE are always included since fix status is unknown.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns VulnInfos excluding CVEs where all affected\n+// packages match any of the provided regexps.\n+// Invalid regexps are logged as warnings and skipped.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // FindScoredVulns return scored vulnerabilities\n func (v VulnInfos) FindScoredVulns() VulnInfos {\n \treturn v.Find(func(vv VulnInfo) bool {\n", "creation_timestamp": "2026-06-29T23:41:49.877559Z"}, {"uuid": "aa92bb78-9599-491b-b37a-877c6bfd61fa", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/e3bd70bfd66a99d11847e685c475c1e2", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..b39137f 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -82,90 +80,6 @@ type Kernel struct {\n \tRebootRequired bool   `json:\"rebootRequired\"`\n }\n \n-// FilterByCvssOver is filter function.\n-func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnoreCves is filter function.\n-func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterUnfixed is filter function.\n-func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnorePkgs is filter function.\n-func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n // FilterInactiveWordPressLibs is filter function.\n func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult {\n \tif detectInactive {\n@@ -178,6 +92,9 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..a863371 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -117,6 +119,81 @@ func (v VulnInfos) CountDiff() (nPlus int, nMinus int) {\n \treturn\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCves []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCves {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // PackageFixStatuses is a list of PackageStatus\n type PackageFixStatuses []PackageFixStatus\n \n", "creation_timestamp": "2026-06-29T23:41:50.375978Z"}, {"uuid": "69adfc1a-d0a3-45dc-9f7d-de9245cefe75", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/2636a76c91fc783b4928e920dfde3cf1", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..a9a3539 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -55,16 +55,23 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\treturn 0, nil\n \t}\n \t// Core\n-\tver := strings.Replace(r.WordPressPackages.CoreVersion(), \".\", \"\", -1)\n+\tcoreVersion := r.WordPressPackages.CoreVersion()\n+\tver := strings.Replace(coreVersion, \".\", \"\", -1)\n \tif ver == \"\" {\n \t\treturn 0, errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\tcorePkg := models.WpPackage{\n+\t\tName:    models.WPCore,\n+\t\tVersion: coreVersion,\n+\t\tType:    models.WPCore,\n+\t}\n+\tcandidates, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n+\twpVinfos := detect(corePkg, candidates)\n \n \t// Themes\n \tthemes := r.WordPressPackages.Themes()\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..d61e08a 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -25,6 +27,85 @@ func (v VulnInfos) Find(f func(VulnInfo) bool) VulnInfos {\n \treturn filtered\n }\n \n+// FilterByCvssOver returns VulnInfos that have a CVSS score &gt;= over\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves returns VulnInfos excluding the given CVE IDs\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed returns VulnInfos. When ignoreUnfixed is true, it excludes\n+// CVEs where all affected packages are NotFixedYet. CVEs detected by CPE\n+// are always included since their fix status is unknown.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns VulnInfos excluding CVEs where all affected\n+// packages match any of the given regexp patterns. Invalid regexps are\n+// logged as warnings and skipped.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // FindScoredVulns return scored vulnerabilities\n func (v VulnInfos) FindScoredVulns() VulnInfos {\n \treturn v.Find(func(vv VulnInfo) bool {\n", "creation_timestamp": "2026-06-29T23:41:50.411924Z"}, {"uuid": "4a2b926a-0cc9-4fb3-9305-84d328d25c72", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/35477ae611a4f50d42f28b218bf279fd", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..351fb52 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -176,6 +176,12 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\tif len(v.WpPackageFixStats) == 0 {\n \t\t\treturn true\n \t\t}\n+\t\t// Never filter out core component CVEs\n+\t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..3ca87b1 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -117,6 +119,85 @@ func (v VulnInfos) CountDiff() (nPlus int, nMinus int) {\n \treturn\n }\n \n+// FilterByCvssOver returns VulnInfos that have a CVSS score &gt;= over\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves returns VulnInfos excluding the given CVE IDs\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed returns VulnInfos that are fixed or detected by CPE.\n+// When ignoreUnfixed is true, CVEs where all affected packages are NotFixedYet are excluded,\n+// but CVEs detected by CPE are always included.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns VulnInfos excluding CVEs where all affected packages match\n+// one of the given regular expression patterns. Invalid patterns are logged as warnings\n+// and skipped.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // PackageFixStatuses is a list of PackageStatus\n type PackageFixStatuses []PackageFixStatus\n \n", "creation_timestamp": "2026-06-29T23:41:50.454645Z"}, {"uuid": "c308b68e-a48f-490f-92b8-c38f1314ee66", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/2f026ad562058d36b976945767b8605e", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..898031e 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \n@@ -179,6 +117,9 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n+\t\t\t\tif p.Type == WPCore {\n+\t\t\t\t\treturn true\n+\t\t\t\t}\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\n \t\t\t\t}\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..ca3d36d 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -25,6 +27,85 @@ func (v VulnInfos) Find(f func(VulnInfo) bool) VulnInfos {\n \treturn filtered\n }\n \n+// FilterByCvssOver returns vulnerabilities whose maximum CVSS score or severity-derived score is over the threshold.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns vulnerabilities excluding the given CVE IDs.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\tignore := map[string]struct{}{}\n+\tfor _, cveID := range ignoreCveIDs {\n+\t\tignore[cveID] = struct{}{}\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t_, ok := ignore[vv.CveID]\n+\t\treturn !ok\n+\t})\n+}\n+\n+// FilterUnfixed returns vulnerabilities excluding those whose affected packages are all marked NotFixedYet.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report CVEs detected by CPE because Vuls can't know fixed or unfixed status.\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tif !p.NotFixedYet {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns vulnerabilities excluding CVEs whose affected package names all match ignored package regexps.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t\tbreak\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // FindScoredVulns return scored vulnerabilities\n func (v VulnInfos) FindScoredVulns() VulnInfos {\n \treturn v.Find(func(vv VulnInfo) bool {\n", "creation_timestamp": "2026-06-29T23:41:50.506201Z"}, {"uuid": "e22c6963-4808-45f4-9342-ffeab2244944", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/778dd9116e048296236d9fc38caa2e6e", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..5327278 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -82,89 +82,6 @@ type Kernel struct {\n \tRebootRequired bool   `json:\"rebootRequired\"`\n }\n \n-// FilterByCvssOver is filter function.\n-func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnoreCves is filter function.\n-func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterUnfixed is filter function.\n-func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnorePkgs is filter function.\n-func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n \n // FilterInactiveWordPressLibs is filter function.\n func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult {\n@@ -178,6 +95,9 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..a21692b 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -117,6 +119,81 @@ func (v VulnInfos) CountDiff() (nPlus int, nMinus int) {\n \treturn\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(v VulnInfo) bool {\n+\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCves []string) VulnInfos {\n+\treturn v.Find(func(v VulnInfo) bool {\n+\t\tfor _, c := range ignoreCves {\n+\t\t\tif v.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(v VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(v.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range v.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(v VulnInfo) bool {\n+\t\tif len(v.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range v.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // PackageFixStatuses is a list of PackageStatus\n type PackageFixStatuses []PackageFixStatus\n \n", "creation_timestamp": "2026-06-29T23:41:50.554924Z"}, {"uuid": "1654cfbb-1d91-4a08-a893-a414a11889b5", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/3cef71a931e87b0427ca39b190328cc9", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/contrib/wordpress/fixtures/prod/wp-prod-01.toml b/contrib/wordpress/fixtures/prod/wp-prod-01.toml\nindex e4d3fc7..27a2244 100644\n--- a/contrib/wordpress/fixtures/prod/wp-prod-01.toml\n+++ b/contrib/wordpress/fixtures/prod/wp-prod-01.toml\n@@ -3,7 +3,7 @@\n [servers.wp-prod-01]\n host = \"wp-prod-01.internal.example.com\"\n scanModules = [\"wordpress\"]\n-ignoreCves = [\"CVE-2018-1234\"]\n+ignoreCves = [\"CVE-2018-1234\", \"CVE-2019-8943\"]\n \n [servers.wp-prod-01.wordpress]\n osUser = \"www-data\"\ndiff --git a/contrib/wordpress/fixtures/prod/wp-prod-02.toml b/contrib/wordpress/fixtures/prod/wp-prod-02.toml\nindex d9541af..a1ddb8a 100644\n--- a/contrib/wordpress/fixtures/prod/wp-prod-02.toml\n+++ b/contrib/wordpress/fixtures/prod/wp-prod-02.toml\n@@ -3,7 +3,7 @@\n [servers.wp-prod-02]\n host = \"wp-prod-02.internal.example.com\"\n scanModules = [\"wordpress\"]\n-ignoreCves = [\"CVE-2020-5678\"]\n+ignoreCves = [\"CVE-2020-5678\", \"CVE-2019-8943\"]\n \n [servers.wp-prod-02.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..d1815e6 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -6,6 +6,7 @@ import (\n \t\"fmt\"\n \t\"io/ioutil\"\n \t\"net/http\"\n+\t\"net/http/httputil\"\n \t\"strings\"\n \t\"time\"\n \n@@ -61,7 +62,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n@@ -227,6 +228,7 @@ func httpRequest(url, token string) (string, error) {\n \t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n \t}\n \treq.Header.Set(\"Authorization\", fmt.Sprintf(\"Token token=%s\", token))\n+\treqDump := dumpRequest(req)\n \tclient, err := util.GetHTTPClient(c.Conf.HTTPProxy)\n \tif err != nil {\n \t\treturn \"\", err\n@@ -234,12 +236,12 @@ func httpRequest(url, token string) (string, error) {\n \tresp, err := client.Do(req)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. request: %s err: %s\", reqDump, err))\n \t}\n \tbody, err := ioutil.ReadAll(resp.Body)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. request: %s err: %s\", reqDump, err))\n \t}\n \tdefer resp.Body.Close()\n \tif resp.StatusCode == 200 {\n@@ -249,11 +251,19 @@ func httpRequest(url, token string) (string, error) {\n \t\treturn \"\", nil\n \t} else if resp.StatusCode == 429 {\n \t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n-\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v\", resp.Status))\n+\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v request: %s\", resp.Status, reqDump))\n \t} else {\n-\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v\", resp.Status)\n-\t\treturn \"\", nil\n+\t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. status: %+v request: %s\", resp.Status, reqDump))\n+\t}\n+}\n+\n+func dumpRequest(req *http.Request) string {\n+\tdump, err := httputil.DumpRequestOut(req, false)\n+\tif err != nil {\n+\t\treturn fmt.Sprintf(\"failed to dump request: %s\", err)\n \t}\n+\treturn string(dump)\n }\n \n func removeInactives(pkgs models.WordPressPackages) (removed models.WordPressPackages) {\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..abeb284 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \n@@ -178,6 +116,9 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..425d752 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,82 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver returns vulnerabilities whose maximum CVSS score or severity is at least over.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns vulnerabilities excluding CVEs in ignoreCveIDs.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\tignored := map[string]struct{}{}\n+\tfor _, cveID := range ignoreCveIDs {\n+\t\tignored[cveID] = struct{}{}\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t_, found := ignored[vv.CveID]\n+\t\treturn !found\n+\t})\n+}\n+\n+// FilterUnfixed returns vulnerabilities excluding CVEs whose affected packages are all not fixed yet.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report CVEs detected by CPE because Vuls can't know fixed or unfixed status.\n+\t\tif len(vv.CpeURIs) != 0 || len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tif !p.NotFixedYet {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns vulnerabilities excluding CVEs whose affected packages all match ignored package regexps.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t\tbreak\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-29T23:41:50.627639Z"}, {"uuid": "6dec12fb-320b-4f8f-84e4-d6023b6a62f2", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/782de10831b3cc0a7c0ce1ff058a1775", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..f1eebd1 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..d416a8b 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,83 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver returns vulnerabilities whose maximum CVSS score or severity is over threshold.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns vulnerabilities excluding ignored CVE IDs.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\tignore := map[string]struct{}{}\n+\tfor _, cveID := range ignoreCveIDs {\n+\t\tignore[cveID] = struct{}{}\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t_, ok := ignore[vv.CveID]\n+\t\treturn !ok\n+\t})\n+}\n+\n+// FilterUnfixed returns vulnerabilities excluding CVEs whose affected packages are all not fixed yet.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v.Find(func(vv VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report CVEs detected by CPE because Vuls can't know whether they are fixed or unfixed.\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\n+\t\tnotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tnotFixedAll = notFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !notFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns vulnerabilities excluding CVEs whose affected packages all match ignored package patterns.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v.Find(func(vv VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-29T23:41:54.244403Z"}, {"uuid": "6ecf4a98-9ad9-4c76-a769-b6a60cc17810", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/83e9998b400270a00ba2e9430cbf0a60", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..933814e 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -55,16 +55,34 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\treturn 0, nil\n \t}\n \t// Core\n-\tver := strings.Replace(r.WordPressPackages.CoreVersion(), \".\", \"\", -1)\n-\tif ver == \"\" {\n+\tcoreVersion := r.WordPressPackages.CoreVersion()\n+\tif coreVersion == \"\" {\n \t\treturn 0, errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n+\tvar corePkg models.WpPackage\n+\tfoundCore := false\n+\tfor _, p := range r.WordPressPackages {\n+\t\tif p.Type == models.WPCore {\n+\t\t\tcorePkg = p\n+\t\t\tfoundCore = true\n+\t\t\tbreak\n+\t\t}\n+\t}\n+\tif !foundCore {\n+\t\tcorePkg = models.WpPackage{\n+\t\t\tName:    models.WPCore,\n+\t\t\tVersion: coreVersion,\n+\t\t\tType:    models.WPCore,\n+\t\t}\n+\t}\n+\tver := strings.Replace(coreVersion, \".\", \"\", -1)\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\tcandidates, err := wpscan(url, corePkg.Name, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n+\twpVinfos := detect(corePkg, candidates)\n \n \t// Themes\n \tthemes := r.WordPressPackages.Themes()\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..f1eebd1 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..f286a85 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,80 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t\tbreak\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-29T23:41:54.319186Z"}, {"uuid": "e633106b-7683-4aff-bdae-129baacd7397", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/42fe2162d4209c0b9ac3a40e25eeae81", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..8ed8561 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -6,6 +6,7 @@ import (\n \t\"fmt\"\n \t\"io/ioutil\"\n \t\"net/http\"\n+\t\"net/http/httputil\"\n \t\"strings\"\n \t\"time\"\n \n@@ -61,7 +62,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n@@ -233,13 +234,15 @@ func httpRequest(url, token string) (string, error) {\n \t}\n \tresp, err := client.Do(req)\n \tif err != nil {\n+\t\tdump, _ := httputil.DumpRequestOut(req, true)\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. req: %s, err: %s\", string(dump), err))\n \t}\n \tbody, err := ioutil.ReadAll(resp.Body)\n \tif err != nil {\n+\t\tdump, _ := httputil.DumpRequestOut(req, true)\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. req: %s, err: %s\", string(dump), err))\n \t}\n \tdefer resp.Body.Close()\n \tif resp.StatusCode == 200 {\n@@ -247,12 +250,15 @@ func httpRequest(url, token string) (string, error) {\n \t} else if resp.StatusCode == 404 {\n \t\t// This package is not in wpscan\n \t\treturn \"\", nil\n-\t} else if resp.StatusCode == 429 {\n-\t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n-\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v\", resp.Status))\n \t} else {\n-\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v\", resp.Status)\n-\t\treturn \"\", nil\n+\t\tdump, _ := httputil.DumpRequestOut(req, true)\n+\t\tif resp.StatusCode == 429 {\n+\t\t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n+\t\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v, req: %s\", resp.Status, string(dump)))\n+\t\t}\n+\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v, req: %s\", resp.Status, string(dump))\n+\t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n+\t\t\tfmt.Sprintf(\"wpscan.com failed status: %+v, req: %s\", resp.Status, string(dump)))\n \t}\n }\n \ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..5327278 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -82,89 +82,6 @@ type Kernel struct {\n \tRebootRequired bool   `json:\"rebootRequired\"`\n }\n \n-// FilterByCvssOver is filter function.\n-func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnoreCves is filter function.\n-func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterUnfixed is filter function.\n-func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnorePkgs is filter function.\n-func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n \n // FilterInactiveWordPressLibs is filter function.\n func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult {\n@@ -178,6 +95,9 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..0f55a62 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -709,6 +711,10 @@ func (cs *Confidences) AppendIfMissing(confidence Confidence) {\n \t*cs = append(*cs, confidence)\n }\n \n+\t}\n+\t*cs = append(*cs, confidence)\n+}\n+\n // SortByConfident sorts Confidences\n func (cs Confidences) SortByConfident() Confidences {\n \tsort.Slice(cs, func(i, j int) bool {\n@@ -809,3 +815,78 @@ var (\n \t// WpScanMatch is a ranking how confident the CVE-ID was detected correctly\n \tWpScanMatch = Confidence{100, WpScanMatchStr, 0}\n )\n+\n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCves []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCves {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n", "creation_timestamp": "2026-06-30T00:00:26.456736Z"}, {"uuid": "d7cded07-c432-4a0f-9816-452d8a926e16", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/6a1f99655cc4185488f0f48769897bac", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..416b97d 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -55,16 +55,23 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\treturn 0, nil\n \t}\n \t// Core\n-\tver := strings.Replace(r.WordPressPackages.CoreVersion(), \".\", \"\", -1)\n+\tcoreVersion := r.WordPressPackages.CoreVersion()\n+\tver := strings.Replace(coreVersion, \".\", \"\", -1)\n \tif ver == \"\" {\n \t\treturn 0, errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\tcandidates, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n+\tcorePkg := models.WpPackage{\n+\t\tName:    models.WPCore,\n+\t\tVersion: coreVersion,\n+\t\tType:    models.WPCore,\n+\t}\n+\twpVinfos := detect(corePkg, candidates)\n \n \t// Themes\n \tthemes := r.WordPressPackages.Themes()\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..f1eebd1 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..e738611 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,11 +3,13 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n+\t\"github.com/future-architect/vuls/logging\"\n )\n \n // VulnInfos has a map of VulnInfo\n@@ -36,6 +38,78 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, cveID := range ignoreCveIDs {\n+\t\t\tif vv.CveID == cveID {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T00:00:26.589503Z"}, {"uuid": "5b7527d9-48e3-4042-a7d6-602bc48b0755", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/3a2d0268d6f05f5966594b395155d0cc", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..90bb50b 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -6,6 +6,7 @@ import (\n \t\"fmt\"\n \t\"io/ioutil\"\n \t\"net/http\"\n+\t\"net/http/httputil\"\n \t\"strings\"\n \t\"time\"\n \n@@ -55,16 +56,23 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\treturn 0, nil\n \t}\n \t// Core\n-\tver := strings.Replace(r.WordPressPackages.CoreVersion(), \".\", \"\", -1)\n-\tif ver == \"\" {\n+\tcoreVer := r.WordPressPackages.CoreVersion()\n+\tapiVer := strings.Replace(coreVer, \".\", \"\", -1)\n+\tif apiVer == \"\" {\n \t\treturn 0, errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n-\turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", apiVer)\n+\tcoreCandidates, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n+\tcorePkg := models.WpPackage{\n+\t\tName:    models.WPCore,\n+\t\tVersion: coreVer,\n+\t\tType:    models.WPCore,\n+\t}\n+\twpVinfos := detect(corePkg, coreCandidates)\n \n \t// Themes\n \tthemes := r.WordPressPackages.Themes()\n@@ -233,6 +241,12 @@ func httpRequest(url, token string) (string, error) {\n \t}\n \tresp, err := client.Do(req)\n \tif err != nil {\n+\t\tdump, dumpErr := httputil.DumpRequestOut(req, true)\n+\t\tif dumpErr != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to dump request: %s\", dumpErr)\n+\t\t} else {\n+\t\t\tlogging.Log.Warnf(\"Request dump:\\n%s\", string(dump))\n+\t\t}\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n \t}\n@@ -248,8 +262,23 @@ func httpRequest(url, token string) (string, error) {\n \t\t// This package is not in wpscan\n \t\treturn \"\", nil\n \t} else if resp.StatusCode == 429 {\n+\t\tdump, dumpErr := httputil.DumpRequestOut(req, true)\n+\t\tif dumpErr != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to dump request: %s\", dumpErr)\n+\t\t} else {\n+\t\t\tlogging.Log.Warnf(\"Request dump:\\n%s\", string(dump))\n+\t\t}\n \t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n \t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v\", resp.Status))\n+\t} else if resp.StatusCode == 401 {\n+\t\tdump, dumpErr := httputil.DumpRequestOut(req, true)\n+\t\tif dumpErr != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to dump request: %s\", dumpErr)\n+\t\t} else {\n+\t\t\tlogging.Log.Warnf(\"Request dump:\\n%s\", string(dump))\n+\t\t}\n+\t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n+\t\t\tfmt.Sprintf(\"wpscan.com authentication failed: %+v\", resp.Status))\n \t} else {\n \t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v\", resp.Status)\n \t\treturn \"\", nil\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..530c6aa 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -25,6 +27,82 @@ func (v VulnInfos) Find(f func(VulnInfo) bool) VulnInfos {\n \treturn filtered\n }\n \n+// FilterByCvssOver returns VulnInfos that have CVSS score &gt;= over\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns VulnInfos excluding the given CVE IDs\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed returns VulnInfos, if ignoreUnfixed is true, it excludes\n+// CVEs where all affected packages are not fixed yet.\n+// CVEs detected by CPE are always included since fix status is unknown.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns VulnInfos excluding CVEs where all affected\n+// packages match any of the provided regexps.\n+// Invalid regexps are logged as warnings and skipped.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // FindScoredVulns return scored vulnerabilities\n func (v VulnInfos) FindScoredVulns() VulnInfos {\n \treturn v.Find(func(vv VulnInfo) bool {\n", "creation_timestamp": "2026-06-30T00:00:26.702823Z"}, {"uuid": "b3054f35-f004-4721-819d-d8a40a24782a", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/e3bd70bfd66a99d11847e685c475c1e2", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..b39137f 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -82,90 +80,6 @@ type Kernel struct {\n \tRebootRequired bool   `json:\"rebootRequired\"`\n }\n \n-// FilterByCvssOver is filter function.\n-func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnoreCves is filter function.\n-func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterUnfixed is filter function.\n-func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnorePkgs is filter function.\n-func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n // FilterInactiveWordPressLibs is filter function.\n func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult {\n \tif detectInactive {\n@@ -178,6 +92,9 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..a863371 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -117,6 +119,81 @@ func (v VulnInfos) CountDiff() (nPlus int, nMinus int) {\n \treturn\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCves []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCves {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // PackageFixStatuses is a list of PackageStatus\n type PackageFixStatuses []PackageFixStatus\n \n", "creation_timestamp": "2026-06-30T00:00:26.805404Z"}, {"uuid": "f0935f19-7584-4b64-859d-904bb7212ba1", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/2636a76c91fc783b4928e920dfde3cf1", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..a9a3539 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -55,16 +55,23 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\treturn 0, nil\n \t}\n \t// Core\n-\tver := strings.Replace(r.WordPressPackages.CoreVersion(), \".\", \"\", -1)\n+\tcoreVersion := r.WordPressPackages.CoreVersion()\n+\tver := strings.Replace(coreVersion, \".\", \"\", -1)\n \tif ver == \"\" {\n \t\treturn 0, errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\tcorePkg := models.WpPackage{\n+\t\tName:    models.WPCore,\n+\t\tVersion: coreVersion,\n+\t\tType:    models.WPCore,\n+\t}\n+\tcandidates, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n+\twpVinfos := detect(corePkg, candidates)\n \n \t// Themes\n \tthemes := r.WordPressPackages.Themes()\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..d61e08a 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -25,6 +27,85 @@ func (v VulnInfos) Find(f func(VulnInfo) bool) VulnInfos {\n \treturn filtered\n }\n \n+// FilterByCvssOver returns VulnInfos that have a CVSS score &gt;= over\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves returns VulnInfos excluding the given CVE IDs\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed returns VulnInfos. When ignoreUnfixed is true, it excludes\n+// CVEs where all affected packages are NotFixedYet. CVEs detected by CPE\n+// are always included since their fix status is unknown.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns VulnInfos excluding CVEs where all affected\n+// packages match any of the given regexp patterns. Invalid regexps are\n+// logged as warnings and skipped.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // FindScoredVulns return scored vulnerabilities\n func (v VulnInfos) FindScoredVulns() VulnInfos {\n \treturn v.Find(func(vv VulnInfo) bool {\n", "creation_timestamp": "2026-06-30T00:00:26.896934Z"}, {"uuid": "b2b37919-f617-4a9f-be0c-d27b2bb11a49", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/35477ae611a4f50d42f28b218bf279fd", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..351fb52 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -176,6 +176,12 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\tif len(v.WpPackageFixStats) == 0 {\n \t\t\treturn true\n \t\t}\n+\t\t// Never filter out core component CVEs\n+\t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..3ca87b1 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -117,6 +119,85 @@ func (v VulnInfos) CountDiff() (nPlus int, nMinus int) {\n \treturn\n }\n \n+// FilterByCvssOver returns VulnInfos that have a CVSS score &gt;= over\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves returns VulnInfos excluding the given CVE IDs\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed returns VulnInfos that are fixed or detected by CPE.\n+// When ignoreUnfixed is true, CVEs where all affected packages are NotFixedYet are excluded,\n+// but CVEs detected by CPE are always included.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns VulnInfos excluding CVEs where all affected packages match\n+// one of the given regular expression patterns. Invalid patterns are logged as warnings\n+// and skipped.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // PackageFixStatuses is a list of PackageStatus\n type PackageFixStatuses []PackageFixStatus\n \n", "creation_timestamp": "2026-06-30T00:00:26.971871Z"}, {"uuid": "aa8f335e-93fd-4501-890e-96a9cd031841", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/2f026ad562058d36b976945767b8605e", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..898031e 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \n@@ -179,6 +117,9 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n+\t\t\t\tif p.Type == WPCore {\n+\t\t\t\t\treturn true\n+\t\t\t\t}\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\n \t\t\t\t}\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..ca3d36d 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -25,6 +27,85 @@ func (v VulnInfos) Find(f func(VulnInfo) bool) VulnInfos {\n \treturn filtered\n }\n \n+// FilterByCvssOver returns vulnerabilities whose maximum CVSS score or severity-derived score is over the threshold.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns vulnerabilities excluding the given CVE IDs.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\tignore := map[string]struct{}{}\n+\tfor _, cveID := range ignoreCveIDs {\n+\t\tignore[cveID] = struct{}{}\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t_, ok := ignore[vv.CveID]\n+\t\treturn !ok\n+\t})\n+}\n+\n+// FilterUnfixed returns vulnerabilities excluding those whose affected packages are all marked NotFixedYet.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report CVEs detected by CPE because Vuls can't know fixed or unfixed status.\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tif !p.NotFixedYet {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns vulnerabilities excluding CVEs whose affected package names all match ignored package regexps.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t\tbreak\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // FindScoredVulns return scored vulnerabilities\n func (v VulnInfos) FindScoredVulns() VulnInfos {\n \treturn v.Find(func(vv VulnInfo) bool {\n", "creation_timestamp": "2026-06-30T00:00:27.042912Z"}, {"uuid": "a9732d13-d1cb-406b-90ff-2d4993fc8b23", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/778dd9116e048296236d9fc38caa2e6e", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..5327278 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -82,89 +82,6 @@ type Kernel struct {\n \tRebootRequired bool   `json:\"rebootRequired\"`\n }\n \n-// FilterByCvssOver is filter function.\n-func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnoreCves is filter function.\n-func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterUnfixed is filter function.\n-func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnorePkgs is filter function.\n-func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n \n // FilterInactiveWordPressLibs is filter function.\n func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult {\n@@ -178,6 +95,9 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..a21692b 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -117,6 +119,81 @@ func (v VulnInfos) CountDiff() (nPlus int, nMinus int) {\n \treturn\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(v VulnInfo) bool {\n+\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCves []string) VulnInfos {\n+\treturn v.Find(func(v VulnInfo) bool {\n+\t\tfor _, c := range ignoreCves {\n+\t\t\tif v.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(v VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(v.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range v.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(v VulnInfo) bool {\n+\t\tif len(v.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range v.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // PackageFixStatuses is a list of PackageStatus\n type PackageFixStatuses []PackageFixStatus\n \n", "creation_timestamp": "2026-06-30T00:00:27.110941Z"}, {"uuid": "82d829a7-0bfd-44e6-903a-b4ef031fc3ea", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/3cef71a931e87b0427ca39b190328cc9", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/contrib/wordpress/fixtures/prod/wp-prod-01.toml b/contrib/wordpress/fixtures/prod/wp-prod-01.toml\nindex e4d3fc7..27a2244 100644\n--- a/contrib/wordpress/fixtures/prod/wp-prod-01.toml\n+++ b/contrib/wordpress/fixtures/prod/wp-prod-01.toml\n@@ -3,7 +3,7 @@\n [servers.wp-prod-01]\n host = \"wp-prod-01.internal.example.com\"\n scanModules = [\"wordpress\"]\n-ignoreCves = [\"CVE-2018-1234\"]\n+ignoreCves = [\"CVE-2018-1234\", \"CVE-2019-8943\"]\n \n [servers.wp-prod-01.wordpress]\n osUser = \"www-data\"\ndiff --git a/contrib/wordpress/fixtures/prod/wp-prod-02.toml b/contrib/wordpress/fixtures/prod/wp-prod-02.toml\nindex d9541af..a1ddb8a 100644\n--- a/contrib/wordpress/fixtures/prod/wp-prod-02.toml\n+++ b/contrib/wordpress/fixtures/prod/wp-prod-02.toml\n@@ -3,7 +3,7 @@\n [servers.wp-prod-02]\n host = \"wp-prod-02.internal.example.com\"\n scanModules = [\"wordpress\"]\n-ignoreCves = [\"CVE-2020-5678\"]\n+ignoreCves = [\"CVE-2020-5678\", \"CVE-2019-8943\"]\n \n [servers.wp-prod-02.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..d1815e6 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -6,6 +6,7 @@ import (\n \t\"fmt\"\n \t\"io/ioutil\"\n \t\"net/http\"\n+\t\"net/http/httputil\"\n \t\"strings\"\n \t\"time\"\n \n@@ -61,7 +62,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n@@ -227,6 +228,7 @@ func httpRequest(url, token string) (string, error) {\n \t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n \t}\n \treq.Header.Set(\"Authorization\", fmt.Sprintf(\"Token token=%s\", token))\n+\treqDump := dumpRequest(req)\n \tclient, err := util.GetHTTPClient(c.Conf.HTTPProxy)\n \tif err != nil {\n \t\treturn \"\", err\n@@ -234,12 +236,12 @@ func httpRequest(url, token string) (string, error) {\n \tresp, err := client.Do(req)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. request: %s err: %s\", reqDump, err))\n \t}\n \tbody, err := ioutil.ReadAll(resp.Body)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. request: %s err: %s\", reqDump, err))\n \t}\n \tdefer resp.Body.Close()\n \tif resp.StatusCode == 200 {\n@@ -249,11 +251,19 @@ func httpRequest(url, token string) (string, error) {\n \t\treturn \"\", nil\n \t} else if resp.StatusCode == 429 {\n \t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n-\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v\", resp.Status))\n+\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v request: %s\", resp.Status, reqDump))\n \t} else {\n-\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v\", resp.Status)\n-\t\treturn \"\", nil\n+\t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. status: %+v request: %s\", resp.Status, reqDump))\n+\t}\n+}\n+\n+func dumpRequest(req *http.Request) string {\n+\tdump, err := httputil.DumpRequestOut(req, false)\n+\tif err != nil {\n+\t\treturn fmt.Sprintf(\"failed to dump request: %s\", err)\n \t}\n+\treturn string(dump)\n }\n \n func removeInactives(pkgs models.WordPressPackages) (removed models.WordPressPackages) {\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..abeb284 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \n@@ -178,6 +116,9 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..425d752 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,82 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver returns vulnerabilities whose maximum CVSS score or severity is at least over.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns vulnerabilities excluding CVEs in ignoreCveIDs.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\tignored := map[string]struct{}{}\n+\tfor _, cveID := range ignoreCveIDs {\n+\t\tignored[cveID] = struct{}{}\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t_, found := ignored[vv.CveID]\n+\t\treturn !found\n+\t})\n+}\n+\n+// FilterUnfixed returns vulnerabilities excluding CVEs whose affected packages are all not fixed yet.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report CVEs detected by CPE because Vuls can't know fixed or unfixed status.\n+\t\tif len(vv.CpeURIs) != 0 || len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tif !p.NotFixedYet {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns vulnerabilities excluding CVEs whose affected packages all match ignored package regexps.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t\tbreak\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T00:00:27.169983Z"}, {"uuid": "5240746a-839a-475d-a801-a38f3690910a", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/782de10831b3cc0a7c0ce1ff058a1775", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..f1eebd1 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..d416a8b 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,83 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver returns vulnerabilities whose maximum CVSS score or severity is over threshold.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns vulnerabilities excluding ignored CVE IDs.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\tignore := map[string]struct{}{}\n+\tfor _, cveID := range ignoreCveIDs {\n+\t\tignore[cveID] = struct{}{}\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t_, ok := ignore[vv.CveID]\n+\t\treturn !ok\n+\t})\n+}\n+\n+// FilterUnfixed returns vulnerabilities excluding CVEs whose affected packages are all not fixed yet.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v.Find(func(vv VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report CVEs detected by CPE because Vuls can't know whether they are fixed or unfixed.\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\n+\t\tnotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tnotFixedAll = notFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !notFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns vulnerabilities excluding CVEs whose affected packages all match ignored package patterns.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v.Find(func(vv VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T00:00:27.302333Z"}, {"uuid": "1e45f546-b7bc-4508-9b94-d46082dbb27b", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/83e9998b400270a00ba2e9430cbf0a60", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..933814e 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -55,16 +55,34 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\treturn 0, nil\n \t}\n \t// Core\n-\tver := strings.Replace(r.WordPressPackages.CoreVersion(), \".\", \"\", -1)\n-\tif ver == \"\" {\n+\tcoreVersion := r.WordPressPackages.CoreVersion()\n+\tif coreVersion == \"\" {\n \t\treturn 0, errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n+\tvar corePkg models.WpPackage\n+\tfoundCore := false\n+\tfor _, p := range r.WordPressPackages {\n+\t\tif p.Type == models.WPCore {\n+\t\t\tcorePkg = p\n+\t\t\tfoundCore = true\n+\t\t\tbreak\n+\t\t}\n+\t}\n+\tif !foundCore {\n+\t\tcorePkg = models.WpPackage{\n+\t\t\tName:    models.WPCore,\n+\t\t\tVersion: coreVersion,\n+\t\t\tType:    models.WPCore,\n+\t\t}\n+\t}\n+\tver := strings.Replace(coreVersion, \".\", \"\", -1)\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\tcandidates, err := wpscan(url, corePkg.Name, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n+\twpVinfos := detect(corePkg, candidates)\n \n \t// Themes\n \tthemes := r.WordPressPackages.Themes()\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..f1eebd1 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..f286a85 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,80 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t\tbreak\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T00:00:27.357714Z"}, {"uuid": "01ad0158-8aa2-4e87-9441-099ffff8f684", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/74874eb4550f1f3e9bc53687b455f719", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..3ba1420 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,81 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T00:11:36.347887Z"}, {"uuid": "c694d462-7d37-4a3a-a0b4-424dbdd9cef3", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/38c7e9215fa9afe09b8a48077f915ae4", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..f9b0a3c 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -6,6 +6,7 @@ import (\n \t\"fmt\"\n \t\"io/ioutil\"\n \t\"net/http\"\n+\t\"net/http/httputil\"\n \t\"strings\"\n \t\"time\"\n \n@@ -61,7 +62,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, \"core\", cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n@@ -227,14 +228,22 @@ func httpRequest(url, token string) (string, error) {\n \t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n \t}\n \treq.Header.Set(\"Authorization\", fmt.Sprintf(\"Token token=%s\", token))\n+\n+\t// Dump the request exactly as it was sent\n+\treqDump, dumpErr := httputil.DumpRequestOut(req, true)\n+\n \tclient, err := util.GetHTTPClient(c.Conf.HTTPProxy)\n \tif err != nil {\n \t\treturn \"\", err\n \t}\n \tresp, err := client.Do(req)\n \tif err != nil {\n+\t\tdumpMsg := \"Request dump unavailable\"\n+\t\tif dumpErr == nil {\n+\t\t\tdumpMsg = string(reqDump)\n+\t\t}\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s. Request: %s\", err, dumpMsg))\n \t}\n \tbody, err := ioutil.ReadAll(resp.Body)\n \tif err != nil {\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..f2ba709 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,7 +4,6 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n@@ -82,89 +81,7 @@ type Kernel struct {\n \tRebootRequired bool   `json:\"rebootRequired\"`\n }\n \n-// FilterByCvssOver is filter function.\n-func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n \n-// FilterIgnoreCves is filter function.\n-func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterUnfixed is filter function.\n-func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnorePkgs is filter function.\n-func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n \n // FilterInactiveWordPressLibs is filter function.\n func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult {\n@@ -178,6 +95,9 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == \"core\" {\n+\t\t\t\treturn true\n+\t\t\t}\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..ae0a434 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,81 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver returns scored vulnerabilities over a certain threshold\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves returns scored vulnerabilities ignoring specified CVEs\n+func (v VulnInfos) FilterIgnoreCves(ignoreCves []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCves {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed returns scored vulnerabilities ignoring unfixed ones\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns scored vulnerabilities ignoring specified packages\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T00:11:36.504536Z"}, {"uuid": "aff1efc0-b551-4fc8-b829-f44a6fdd1d47", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/3f440ccfa9c4bb31336f8f8453953648", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..11983e8 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,85 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver returns VulnInfos that have a CVSS score &gt;= over\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves returns VulnInfos excluding any CVE whose ID is in ignoreCveIDs\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed returns VulnInfos. When ignoreUnfixed is true, it excludes\n+// CVEs whose affected packages are all marked NotFixedYet.\n+// CVEs detected solely by CPE are always included.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report CVEs detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tnotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tnotFixedAll = notFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !notFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns VulnInfos excluding CVEs where all affected\n+// packages match any of the provided regexp patterns.\n+// Invalid regexps are logged as warnings and skipped.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T01:08:53.691309Z"}, {"uuid": "14e38c48-5a1f-4cc2-92a7-093cd1fb6dfe", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/de2e497f7b0ef7ce26c62df88f660dff", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..5f4eb4d 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -55,16 +55,26 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\treturn 0, nil\n \t}\n \t// Core\n-\tver := strings.Replace(r.WordPressPackages.CoreVersion(), \".\", \"\", -1)\n-\tif ver == \"\" {\n+\tcoreVersion := r.WordPressPackages.CoreVersion()\n+\tif coreVersion == \"\" {\n \t\treturn 0, errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n+\tver := strings.Replace(coreVersion, \".\", \"\", -1)\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\tcandidates, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n+\tcorePkg, ok := r.WordPressPackages.Find(models.WPCore)\n+\tif !ok {\n+\t\tcorePkg = &amp;models.WpPackage{\n+\t\t\tName:    models.WPCore,\n+\t\t\tVersion: coreVersion,\n+\t\t\tType:    models.WPCore,\n+\t\t}\n+\t}\n+\twpVinfos := detect(*corePkg, candidates)\n \n \t// Themes\n \tthemes := r.WordPressPackages.Themes()\n@@ -145,6 +155,9 @@ func detect(installed models.WpPackage, candidates []models.VulnInfo) (vulns []m\n }\n \n func match(installedVer, fixedIn string) (bool, error) {\n+\tif fixedIn == \"\" {\n+\t\treturn true, nil\n+\t}\n \tv1, err := version.NewVersion(installedVer)\n \tif err != nil {\n \t\treturn false, err\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..f1eebd1 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..2b78536 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,11 +3,13 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n+\t\"github.com/future-architect/vuls/logging\"\n )\n \n // VulnInfos has a map of VulnInfo\n@@ -36,6 +38,80 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T00:11:36.191417Z"}, {"uuid": "18700dc4-18ac-4559-939d-2aa23479e648", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/83ce5543ea190f27c0122be6eb53d456", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..e3d67ec 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,83 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver returns VulnInfos that have a MaxCvssScore &gt;= over\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves returns VulnInfos excluding the given CVE IDs\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed returns VulnInfos excluding unfixed CVEs when ignoreUnfixed is true.\n+// CVEs detected by CPE are always included since fix status is unknown.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns VulnInfos excluding CVEs where all affected packages\n+// match the given regular expression patterns. Invalid patterns are logged and skipped.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T00:11:36.012594Z"}, {"uuid": "345b8802-9271-47ef-aa34-924bce8d8bbf", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/0799b4337464818f11ede78ba909a724", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..6f841e7 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -65,6 +65,11 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \tif err != nil {\n \t\treturn 0, err\n \t}\n+\tfor i := range wpVinfos {\n+\t\tfor j := range wpVinfos[i].WpPackageFixStats {\n+\t\t\twpVinfos[i].WpPackageFixStats[j].Name = models.WPCore\n+\t\t}\n+\t}\n \n \t// Themes\n \tthemes := r.WordPressPackages.Themes()\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..6736918 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -82,90 +80,6 @@ type Kernel struct {\n \tRebootRequired bool   `json:\"rebootRequired\"`\n }\n \n-// FilterByCvssOver is filter function.\n-func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnoreCves is filter function.\n-func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterUnfixed is filter function.\n-func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnorePkgs is filter function.\n-func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n // FilterInactiveWordPressLibs is filter function.\n func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult {\n \tif detectInactive {\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..0c6d8b4 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -25,6 +27,84 @@ func (v VulnInfos) Find(f func(VulnInfo) bool) VulnInfos {\n \treturn filtered\n }\n \n+// FilterByCvssOver returns vulnerabilities whose maximum CVSS score is at least over.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns vulnerabilities excluding the ignored CVE IDs.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\tignored := map[string]struct{}{}\n+\tfor _, cveID := range ignoreCveIDs {\n+\t\tignored[cveID] = struct{}{}\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t_, ok := ignored[vv.CveID]\n+\t\treturn !ok\n+\t})\n+}\n+\n+// FilterUnfixed returns vulnerabilities excluding those only affecting unfixed packages.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report CVEs detected by CPE because Vuls can't know 'fixed' or 'unfixed'.\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tif !p.NotFixedYet {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns vulnerabilities excluding those only affecting ignored package names.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t\tbreak\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // FindScoredVulns return scored vulnerabilities\n func (v VulnInfos) FindScoredVulns() VulnInfos {\n \treturn v.Find(func(vv VulnInfo) bool {\n", "creation_timestamp": "2026-06-30T00:11:36.061746Z"}, {"uuid": "9eab0adf-aa62-4e18-9820-8cca44401a5a", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/ab4a0614490d95a6b67139ca46ca194d", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..f1eebd1 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..a6f82f5 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,84 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver returns VulnInfos that have a CVSS score &gt;= over\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves returns VulnInfos that are not in the ignoreCveIDs list\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed returns VulnInfos that are fixed when ignoreUnfixed is true.\n+// CVEs detected by CPE are always included because Vuls can't determine their fix status.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tnotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tnotFixedAll = notFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !notFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns VulnInfos whose affected packages do not all match\n+// the given regular expression patterns. Invalid regex patterns are logged as\n+// warnings and skipped.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T00:11:36.106018Z"}, {"uuid": "8d5c63eb-9aeb-4382-ac76-4e7003d77676", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/9ee10c00bb8066f7a60f7e966b9be8f8", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..e4f08b1 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -82,90 +82,6 @@ type Kernel struct {\n \tRebootRequired bool   `json:\"rebootRequired\"`\n }\n \n-// FilterByCvssOver is filter function.\n-func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnoreCves is filter function.\n-func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterUnfixed is filter function.\n-func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnorePkgs is filter function.\n-func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n // FilterInactiveWordPressLibs is filter function.\n func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult {\n \tif detectInactive {\n@@ -178,6 +94,9 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..aa5742c 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -117,6 +119,81 @@ func (v VulnInfos) CountDiff() (nPlus int, nMinus int) {\n \treturn\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vInfo VulnInfo) bool {\n+\t\tif over &lt;= vInfo.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCves []string) VulnInfos {\n+\treturn v.Find(func(vInfo VulnInfo) bool {\n+\t\tfor _, c := range ignoreCves {\n+\t\t\tif vInfo.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vInfo VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vInfo.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vInfo.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vInfo VulnInfo) bool {\n+\t\tif len(vInfo.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vInfo.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // PackageFixStatuses is a list of PackageStatus\n type PackageFixStatuses []PackageFixStatus\n \n", "creation_timestamp": "2026-06-30T00:11:36.145368Z"}, {"uuid": "8173ea04-8024-4a4d-a28d-1a773d2db906", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/45f9aa1e12863dc7cfdbf3a8596e8abe", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/contrib/wordpress/fixtures/prod/wp-prod-01.toml b/contrib/wordpress/fixtures/prod/wp-prod-01.toml\nindex e4d3fc7..27a2244 100644\n--- a/contrib/wordpress/fixtures/prod/wp-prod-01.toml\n+++ b/contrib/wordpress/fixtures/prod/wp-prod-01.toml\n@@ -3,7 +3,7 @@\n [servers.wp-prod-01]\n host = \"wp-prod-01.internal.example.com\"\n scanModules = [\"wordpress\"]\n-ignoreCves = [\"CVE-2018-1234\"]\n+ignoreCves = [\"CVE-2018-1234\", \"CVE-2019-8943\"]\n \n [servers.wp-prod-01.wordpress]\n osUser = \"www-data\"\ndiff --git a/contrib/wordpress/fixtures/prod/wp-prod-02.toml b/contrib/wordpress/fixtures/prod/wp-prod-02.toml\nindex d9541af..a1ddb8a 100644\n--- a/contrib/wordpress/fixtures/prod/wp-prod-02.toml\n+++ b/contrib/wordpress/fixtures/prod/wp-prod-02.toml\n@@ -3,7 +3,7 @@\n [servers.wp-prod-02]\n host = \"wp-prod-02.internal.example.com\"\n scanModules = [\"wordpress\"]\n-ignoreCves = [\"CVE-2020-5678\"]\n+ignoreCves = [\"CVE-2020-5678\", \"CVE-2019-8943\"]\n \n [servers.wp-prod-02.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..4405b3a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -6,6 +6,7 @@ import (\n \t\"fmt\"\n \t\"io/ioutil\"\n \t\"net/http\"\n+\t\"net/http/httputil\"\n \t\"strings\"\n \t\"time\"\n \n@@ -61,7 +62,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n@@ -231,29 +232,41 @@ func httpRequest(url, token string) (string, error) {\n \tif err != nil {\n \t\treturn \"\", err\n \t}\n+\treqDump := dumpRequest(req)\n \tresp, err := client.Do(req)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s, request: %s\", err, reqDump))\n \t}\n+\tdefer resp.Body.Close()\n \tbody, err := ioutil.ReadAll(resp.Body)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s, request: %s\", err, reqDump))\n \t}\n-\tdefer resp.Body.Close()\n \tif resp.StatusCode == 200 {\n \t\treturn string(body), nil\n \t} else if resp.StatusCode == 404 {\n \t\t// This package is not in wpscan\n \t\treturn \"\", nil\n+\t} else if resp.StatusCode == 401 {\n+\t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n+\t\t\tfmt.Sprintf(\"wpscan.com authentication failed: %+v, request: %s\", resp.Status, reqDump))\n \t} else if resp.StatusCode == 429 {\n \t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n-\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v\", resp.Status))\n+\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v, request: %s\", resp.Status, reqDump))\n \t} else {\n-\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v\", resp.Status)\n-\t\treturn \"\", nil\n+\t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n+\t\t\tfmt.Sprintf(\"wpscan.com unknown status code: %+v, request: %s\", resp.Status, reqDump))\n+\t}\n+}\n+\n+func dumpRequest(req *http.Request) string {\n+\tdump, err := httputil.DumpRequestOut(req, true)\n+\tif err != nil {\n+\t\treturn fmt.Sprintf(\"failed to dump request: %s\", err)\n \t}\n+\treturn string(dump)\n }\n \n func removeInactives(pkgs models.WordPressPackages) (removed models.WordPressPackages) {\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..0989521 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \n@@ -176,6 +114,11 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\tif len(v.WpPackageFixStats) == 0 {\n \t\t\treturn true\n \t\t}\n+\t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif wp.Name == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..edf4948 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,80 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver returns CVEs whose max CVSS score or severity is over the threshold.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns CVEs excluding the specified CVE IDs.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\tignored := map[string]bool{}\n+\tfor _, cveID := range ignoreCveIDs {\n+\t\tignored[cveID] = true\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn !ignored[vv.CveID]\n+\t})\n+}\n+\n+// FilterUnfixed returns CVEs excluding entries whose affected packages are all unfixed.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report CVEs detected by CPE because Vuls can't know fixed or unfixed.\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\n+\t\tnotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tnotFixedAll = notFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !notFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns CVEs excluding entries whose affected packages all match ignored package patterns.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v.Find(func(VulnInfo) bool { return true })\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T00:11:36.386488Z"}, {"uuid": "c07a5493-2574-4f40-8127-150ebb613279", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/300576dda63fc608f914f73ddf04418c", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..6736918 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -82,90 +80,6 @@ type Kernel struct {\n \tRebootRequired bool   `json:\"rebootRequired\"`\n }\n \n-// FilterByCvssOver is filter function.\n-func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnoreCves is filter function.\n-func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterUnfixed is filter function.\n-func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnorePkgs is filter function.\n-func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n // FilterInactiveWordPressLibs is filter function.\n func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult {\n \tif detectInactive {\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..902b2bd 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,81 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCves []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCves {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T00:11:36.544024Z"}, {"uuid": "6de12e4b-90e5-4905-b12f-c61d0dc68b83", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/274b507adc8f0383b64bcd7ddd6cca29", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..ac298ab 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -6,6 +6,7 @@ import (\n \t\"fmt\"\n \t\"io/ioutil\"\n \t\"net/http\"\n+\t\"net/http/httputil\"\n \t\"strings\"\n \t\"time\"\n \n@@ -55,13 +56,14 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\treturn 0, nil\n \t}\n \t// Core\n-\tver := strings.Replace(r.WordPressPackages.CoreVersion(), \".\", \"\", -1)\n+\tcoreVersion := r.WordPressPackages.CoreVersion()\n+\tver := strings.Replace(coreVersion, \".\", \"\", -1)\n \tif ver == \"\" {\n \t\treturn 0, errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n@@ -231,15 +233,21 @@ func httpRequest(url, token string) (string, error) {\n \tif err != nil {\n \t\treturn \"\", err\n \t}\n+\n+\tdump, dumpErr := httputil.DumpRequestOut(req, true)\n+\tif dumpErr != nil {\n+\t\tlogging.Log.Warnf(\"Failed to dump request: %s\", dumpErr)\n+\t}\n+\n \tresp, err := client.Do(req)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s, request: %s\", err, string(dump)))\n \t}\n \tbody, err := ioutil.ReadAll(resp.Body)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s, request: %s\", err, string(dump)))\n \t}\n \tdefer resp.Body.Close()\n \tif resp.StatusCode == 200 {\n@@ -249,9 +257,9 @@ func httpRequest(url, token string) (string, error) {\n \t\treturn \"\", nil\n \t} else if resp.StatusCode == 429 {\n \t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n-\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v\", resp.Status))\n+\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v, request: %s\", resp.Status, string(dump)))\n \t} else {\n-\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v\", resp.Status)\n+\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v, request: %s\", resp.Status, string(dump))\n \t\treturn \"\", nil\n \t}\n }\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..2702e6e 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -179,6 +179,10 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\n+\t\t\t\t// Never filter out core component CVEs\n+\t\t\t\tif p.Type == WPCore {\n+\t\t\t\t\treturn true\n+\t\t\t\t}\n \t\t\t\tif p.Status != Inactive {\n \t\t\t\t\treturn true\n \t\t\t\t}\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..d21d5e9 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -117,6 +119,85 @@ func (v VulnInfos) CountDiff() (nPlus int, nMinus int) {\n \treturn\n }\n \n+// FilterByCvssOver returns VulnInfos that have CVSS score &gt;= over\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves returns VulnInfos excluding the given CVE IDs\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed returns VulnInfos. If ignoreUnfixed is true, it excludes\n+// CVEs where all affected packages are not-fixed-yet. CVEs detected by CPE\n+// are always included.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns VulnInfos excluding CVEs where all affected\n+// packages match the given regexp patterns. Invalid regexps are logged\n+// as warnings and skipped.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // PackageFixStatuses is a list of PackageStatus\n type PackageFixStatuses []PackageFixStatus\n \n", "creation_timestamp": "2026-06-30T00:11:36.585010Z"}, {"uuid": "63a26d03-bc89-453b-bcaf-30ddb807e0f3", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/beb79997bfa22b369d99e0e94c125dab", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..063ca90 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \n@@ -176,6 +114,11 @@ func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult\n \t\tif len(v.WpPackageFixStats) == 0 {\n \t\t\treturn true\n \t\t}\n+\t\tfor _, wp := range v.WpPackageFixStats {\n+\t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok &amp;&amp; p.Type == WPCore {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n \t\t// Ignore if all libs in this vulnInfo inactive\n \t\tfor _, wp := range v.WpPackageFixStats {\n \t\t\tif p, ok := r.WordPressPackages.Find(wp.Name); ok {\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..52a3f40 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,83 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver returns vulnerabilities whose max CVSS score or severity is over the threshold.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns vulnerabilities not listed in ignoreCveIDs.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\tignored := map[string]struct{}{}\n+\tfor _, cveID := range ignoreCveIDs {\n+\t\tignored[cveID] = struct{}{}\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t_, ok := ignored[vv.CveID]\n+\t\treturn !ok\n+\t})\n+}\n+\n+// FilterUnfixed returns vulnerabilities after applying the ignore-unfixed setting.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report CVEs detected by CPE because Vuls cannot know fixed or unfixed status.\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\n+\t\tnotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tnotFixedAll = notFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !notFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns vulnerabilities whose affected packages are not all ignored by package regexps.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T00:11:36.630854Z"}, {"uuid": "7e2cec7c-c975-42d6-8782-8446f9e278ab", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/65635d5f509248c4abfda042460c1580", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..3217d2b 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -82,89 +80,6 @@ type Kernel struct {\n \tRebootRequired bool   `json:\"rebootRequired\"`\n }\n \n-// FilterByCvssOver is filter function.\n-func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnoreCves is filter function.\n-func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterUnfixed is filter function.\n-func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnorePkgs is filter function.\n-func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n \n // FilterInactiveWordPressLibs is filter function.\n func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult {\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..426d070 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -25,6 +27,78 @@ func (v VulnInfos) Find(f func(VulnInfo) bool) VulnInfos {\n \treturn filtered\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(v VulnInfo) bool {\n+\t\treturn over &lt;= v.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCves []string) VulnInfos {\n+\treturn v.Find(func(v VulnInfo) bool {\n+\t\tfor _, c := range ignoreCves {\n+\t\t\tif v.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(v VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(v.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range v.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(v VulnInfo) bool {\n+\t\tif len(v.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range v.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // FindScoredVulns return scored vulnerabilities\n func (v VulnInfos) FindScoredVulns() VulnInfos {\n \treturn v.Find(func(vv VulnInfo) bool {\n", "creation_timestamp": "2026-06-30T01:08:53.509733Z"}, {"uuid": "c309dce2-b84c-41fc-9d41-270190a0b707", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/fef96bd7fb030d12bb1bd689d80304c3", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..4d96a43 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -6,6 +6,7 @@ import (\n \t\"fmt\"\n \t\"io/ioutil\"\n \t\"net/http\"\n+\t\"net/http/httputil\"\n \t\"strings\"\n \t\"time\"\n \n@@ -61,7 +62,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n@@ -231,15 +232,21 @@ func httpRequest(url, token string) (string, error) {\n \tif err != nil {\n \t\treturn \"\", err\n \t}\n+\n+\trequestDump, dumpErr := httputil.DumpRequestOut(req, true)\n+\tif dumpErr != nil {\n+\t\tlogging.Log.Warnf(\"Failed to dump WPScan request: %s\", dumpErr)\n+\t}\n+\n \tresp, err := client.Do(req)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. request:\\n%s\\nerr: %s\", string(requestDump), err))\n \t}\n \tbody, err := ioutil.ReadAll(resp.Body)\n \tif err != nil {\n \t\treturn \"\", errof.New(errof.ErrFailedToAccessWpScan,\n-\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. err: %s\", err))\n+\t\t\tfmt.Sprintf(\"Failed to access to wpscan.com. request:\\n%s\\nerr: %s\", string(requestDump), err))\n \t}\n \tdefer resp.Body.Close()\n \tif resp.StatusCode == 200 {\n@@ -249,9 +256,9 @@ func httpRequest(url, token string) (string, error) {\n \t\treturn \"\", nil\n \t} else if resp.StatusCode == 429 {\n \t\treturn \"\", errof.New(errof.ErrWpScanAPILimitExceeded,\n-\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v\", resp.Status))\n+\t\t\tfmt.Sprintf(\"wpscan.com API limit exceeded: %+v, request:\\n%s\", resp.Status, string(requestDump)))\n \t} else {\n-\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v\", resp.Status)\n+\t\tlogging.Log.Warnf(\"wpscan.com unknown status code: %+v, request:\\n%s\", resp.Status, string(requestDump))\n \t\treturn \"\", nil\n \t}\n }\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..f1eebd1 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -84,85 +82,25 @@ type Kernel struct {\n \n // FilterByCvssOver is filter function.\n func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(over)\n \treturn r\n }\n \n // FilterIgnoreCves is filter function.\n func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \treturn r\n }\n \n // FilterUnfixed is filter function.\n func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterUnfixed(ignoreUnfixed)\n \treturn r\n }\n \n // FilterIgnorePkgs is filter function.\n func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n+\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \treturn r\n }\n \ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..aa7a07c 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -25,6 +27,81 @@ func (v VulnInfos) Find(f func(VulnInfo) bool) VulnInfos {\n \treturn filtered\n }\n \n+// FilterByCvssOver returns VulnInfos that have a CVSS score &gt;= over\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns VulnInfos excluding any CVE whose ID is in ignoreCveIDs\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed returns VulnInfos excluding CVEs where all affected packages are NotFixedYet.\n+// CVEs detected by CPE are always kept because Vuls cannot determine their fix status.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns VulnInfos excluding CVEs where all affected package names\n+// match at least one of the provided regexps. Invalid regexps are logged as warnings\n+// and skipped.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // FindScoredVulns return scored vulnerabilities\n func (v VulnInfos) FindScoredVulns() VulnInfos {\n \treturn v.Find(func(vv VulnInfo) bool {\n", "creation_timestamp": "2026-06-30T01:08:53.564896Z"}, {"uuid": "4b66a017-d2ae-4184-ac7a-b0aa3ceb7ac4", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/800da3b3d19594fd2b16e71ff40d76c3", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..6736918 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -82,90 +80,6 @@ type Kernel struct {\n \tRebootRequired bool   `json:\"rebootRequired\"`\n }\n \n-// FilterByCvssOver is filter function.\n-func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnoreCves is filter function.\n-func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterUnfixed is filter function.\n-func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnorePkgs is filter function.\n-func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n // FilterInactiveWordPressLibs is filter function.\n func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult {\n \tif detectInactive {\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..67e6170 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -36,6 +38,83 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {\n \t})\n }\n \n+// FilterByCvssOver returns CVEs whose maximum CVSS score or severity is at least over.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\treturn over &lt;= vv.MaxCvssScore().Value.Score\n+\t})\n+}\n+\n+// FilterIgnoreCves returns CVEs excluding IDs in ignoreCveIDs.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\tignored := map[string]struct{}{}\n+\tfor _, cveID := range ignoreCveIDs {\n+\t\tignored[cveID] = struct{}{}\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t_, ok := ignored[vv.CveID]\n+\t\treturn !ok\n+\t})\n+}\n+\n+// FilterUnfixed returns CVEs excluding ones whose affected packages are all not fixed yet.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report CVEs detected by CPE because Vuls can't know fixed or unfixed.\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\n+\t\tnotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tnotFixedAll = notFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !notFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs returns CVEs excluding ones whose affected packages all match ignored package patterns.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tregexps = append(regexps, re)\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID\n func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {\n \tfor k := range v {\n", "creation_timestamp": "2026-06-30T01:08:53.617150Z"}, {"uuid": "3de45e73-ee78-41dc-ad7f-9900298571c3", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/8b4418a8b60c89d4f50f665c46aa278c", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/detector.go b/detector/detector.go\nindex 0da7994..f7331dc 100644\n--- a/detector/detector.go\n+++ b/detector/detector.go\n@@ -134,8 +134,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t}\n \n \tfor i, r := range rs {\n-\t\tr = r.FilterByCvssOver(c.Conf.CvssScoreOver)\n-\t\tr = r.FilterUnfixed(c.Conf.IgnoreUnfixed)\n+\t\tr.ScannedCves = r.ScannedCves.FilterByCvssOver(c.Conf.CvssScoreOver)\n+\t\tr.ScannedCves = r.ScannedCves.FilterUnfixed(c.Conf.IgnoreUnfixed)\n \t\tr = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)\n \n \t\t// IgnoreCves\n@@ -145,7 +145,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if con, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignoreCves = con.IgnoreCves\n \t\t}\n-\t\tr = r.FilterIgnoreCves(ignoreCves)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)\n \n \t\t// ignorePkgs\n \t\tignorePkgsRegexps := []string{}\n@@ -154,7 +154,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca\n \t\t} else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {\n \t\t\tignorePkgsRegexps = s.IgnorePkgsRegexp\n \t\t}\n-\t\tr = r.FilterIgnorePkgs(ignorePkgsRegexps)\n+\t\tr.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)\n \n \t\t// IgnoreUnscored\n \t\tif c.Conf.IgnoreUnscoredCves {\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..b1da77a 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -61,7 +61,7 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\twpVinfos, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\ndiff --git a/models/scanresults.go b/models/scanresults.go\nindex f22c1bb..6736918 100644\n--- a/models/scanresults.go\n+++ b/models/scanresults.go\n@@ -4,14 +4,12 @@ import (\n \t\"bytes\"\n \t\"fmt\"\n \t\"reflect\"\n-\t\"regexp\"\n \t\"strings\"\n \t\"time\"\n \n \t\"github.com/future-architect/vuls/config\"\n \t\"github.com/future-architect/vuls/constant\"\n \t\"github.com/future-architect/vuls/cwe\"\n-\t\"github.com/future-architect/vuls/logging\"\n )\n \n // ScanResults is a slide of ScanResult\n@@ -82,90 +80,6 @@ type Kernel struct {\n \tRebootRequired bool   `json:\"rebootRequired\"`\n }\n \n-// FilterByCvssOver is filter function.\n-func (r ScanResult) FilterByCvssOver(over float64) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif over &lt;= v.MaxCvssScore().Value.Score {\n-\t\t\treturn true\n-\t\t}\n-\t\treturn false\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnoreCves is filter function.\n-func (r ScanResult) FilterIgnoreCves(ignoreCves []string) ScanResult {\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tfor _, c := range ignoreCves {\n-\t\t\tif v.CveID == c {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t}\n-\t\treturn true\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterUnfixed is filter function.\n-func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {\n-\tif !ignoreUnfixed {\n-\t\treturn r\n-\t}\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n-\t\tif len(v.CpeURIs) != 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tNotFixedAll := true\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n-\t\t}\n-\t\treturn !NotFixedAll\n-\t})\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n-// FilterIgnorePkgs is filter function.\n-func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult {\n-\tregexps := []*regexp.Regexp{}\n-\tfor _, pkgRegexp := range ignorePkgsRegexps {\n-\t\tre, err := regexp.Compile(pkgRegexp)\n-\t\tif err != nil {\n-\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n-\t\t\tcontinue\n-\t\t} else {\n-\t\t\tregexps = append(regexps, re)\n-\t\t}\n-\t}\n-\tif len(regexps) == 0 {\n-\t\treturn r\n-\t}\n-\n-\tfiltered := r.ScannedCves.Find(func(v VulnInfo) bool {\n-\t\tif len(v.AffectedPackages) == 0 {\n-\t\t\treturn true\n-\t\t}\n-\t\tfor _, p := range v.AffectedPackages {\n-\t\t\tmatch := false\n-\t\t\tfor _, re := range regexps {\n-\t\t\t\tif re.MatchString(p.Name) {\n-\t\t\t\t\tmatch = true\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif !match {\n-\t\t\t\treturn true\n-\t\t\t}\n-\t\t}\n-\t\treturn false\n-\t})\n-\n-\tr.ScannedCves = filtered\n-\treturn r\n-}\n-\n // FilterInactiveWordPressLibs is filter function.\n func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult {\n \tif detectInactive {\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..e25c0e0 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -809,3 +811,78 @@ var (\n \t// WpScanMatch is a ranking how confident the CVE-ID was detected correctly\n \tWpScanMatch = Confidence{100, WpScanMatchStr, 0}\n )\n+\n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCves []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCves {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n", "creation_timestamp": "2026-06-30T01:08:53.656172Z"}, {"uuid": "0c6f0cdb-4b12-47e8-b36e-00904930e56f", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2019-8943", "type": "seen", "source": "https://gist.github.com/tu-trinh-scale/f6c68cd5553c8eaa2c41787db0368c2b", "content": "diff --git a/contrib/wordpress/fixtures/dev/wp-staging.toml b/contrib/wordpress/fixtures/dev/wp-staging.toml\nindex 59d0b4b..9f7917a 100644\n--- a/contrib/wordpress/fixtures/dev/wp-staging.toml\n+++ b/contrib/wordpress/fixtures/dev/wp-staging.toml\n@@ -1,7 +1,7 @@\n [servers.wp-staging]\n host = \"10.0.1.50\"\n scanModules = [\"wordpress\"]\n-ignoreCves = []\n+ignoreCves = [\"CVE-2019-8943\"]\n \n [servers.wp-staging.wordpress]\n osUser = \"www-data\"\ndiff --git a/detector/wordpress.go b/detector/wordpress.go\nindex 0aabcdb..7944f8d 100644\n--- a/detector/wordpress.go\n+++ b/detector/wordpress.go\n@@ -55,16 +55,23 @@ func detectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {\n \t\treturn 0, nil\n \t}\n \t// Core\n-\tver := strings.Replace(r.WordPressPackages.CoreVersion(), \".\", \"\", -1)\n+\tcoreVersion := r.WordPressPackages.CoreVersion()\n+\tver := strings.Replace(coreVersion, \".\", \"\", -1)\n \tif ver == \"\" {\n \t\treturn 0, errof.New(errof.ErrFailedToAccessWpScan,\n \t\t\tfmt.Sprintf(\"Failed to get WordPress core version.\"))\n \t}\n \turl := fmt.Sprintf(\"https://wpscan.com/api/v3/wordpresses/%s\", ver)\n-\twpVinfos, err := wpscan(url, ver, cnf.Token)\n+\tcoreCandidates, err := wpscan(url, models.WPCore, cnf.Token)\n \tif err != nil {\n \t\treturn 0, err\n \t}\n+\tcoreWpPkg := models.WpPackage{\n+\t\tName:    models.WPCore,\n+\t\tVersion: coreVersion,\n+\t\tType:    models.WPCore,\n+\t}\n+\twpVinfos := detect(coreWpPkg, coreCandidates)\n \n \t// Themes\n \tthemes := r.WordPressPackages.Themes()\ndiff --git a/models/vulninfos.go b/models/vulninfos.go\nindex 8ea0567..1fef94a 100644\n--- a/models/vulninfos.go\n+++ b/models/vulninfos.go\n@@ -3,10 +3,12 @@ package models\n import (\n \t\"bytes\"\n \t\"fmt\"\n+\t\"regexp\"\n \t\"sort\"\n \t\"strings\"\n \t\"time\"\n \n+\t\"github.com/future-architect/vuls/logging\"\n \texploitmodels \"github.com/vulsio/go-exploitdb/models\"\n )\n \n@@ -25,6 +27,81 @@ func (v VulnInfos) Find(f func(VulnInfo) bool) VulnInfos {\n \treturn filtered\n }\n \n+// FilterByCvssOver is filter function.\n+func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif over &lt;= vv.MaxCvssScore().Value.Score {\n+\t\t\treturn true\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n+// FilterIgnoreCves is filter function.\n+func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tfor _, c := range ignoreCveIDs {\n+\t\t\tif vv.CveID == c {\n+\t\t\t\treturn false\n+\t\t\t}\n+\t\t}\n+\t\treturn true\n+\t})\n+}\n+\n+// FilterUnfixed is filter function.\n+func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {\n+\tif !ignoreUnfixed {\n+\t\treturn v\n+\t}\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\t// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'\n+\t\tif len(vv.CpeURIs) != 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tNotFixedAll := true\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tNotFixedAll = NotFixedAll &amp;&amp; p.NotFixedYet\n+\t\t}\n+\t\treturn !NotFixedAll\n+\t})\n+}\n+\n+// FilterIgnorePkgs is filter function.\n+func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {\n+\tregexps := []*regexp.Regexp{}\n+\tfor _, pkgRegexp := range ignorePkgsRegexps {\n+\t\tre, err := regexp.Compile(pkgRegexp)\n+\t\tif err != nil {\n+\t\t\tlogging.Log.Warnf(\"Failed to parse %s. err: %+v\", pkgRegexp, err)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tregexps = append(regexps, re)\n+\t\t}\n+\t}\n+\tif len(regexps) == 0 {\n+\t\treturn v\n+\t}\n+\n+\treturn v.Find(func(vv VulnInfo) bool {\n+\t\tif len(vv.AffectedPackages) == 0 {\n+\t\t\treturn true\n+\t\t}\n+\t\tfor _, p := range vv.AffectedPackages {\n+\t\t\tmatch := false\n+\t\t\tfor _, re := range regexps {\n+\t\t\t\tif re.MatchString(p.Name) {\n+\t\t\t\t\tmatch = true\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif !match {\n+\t\t\t\treturn true\n+\t\t\t}\n+\t\t}\n+\t\treturn false\n+\t})\n+}\n+\n // FindScoredVulns return scored vulnerabilities\n func (v VulnInfos) FindScoredVulns() VulnInfos {\n \treturn v.Find(func(vv VulnInfo) bool {\n", "creation_timestamp": "2026-06-30T01:08:56.431120Z"}]}