Repository navigation
CVEngine v1.1
Changed
- The old reNgine scan engine is retired. Its scan and subscan tasks, the
/api/action/initiate/subtask/endpoint, its extra queues, and about 4,000 lines of code that nothing in the current pipeline called are removed, along with the Go tools only it used (httpx, subfinder, chaos, gospider, hakrawler, katana, gau, waybackurls, ffuf, tlsx, gf, unfurl, dalfox, crlfuzz, s3scanner) and the Python tools it cloned at every start (Sublist3r, OneForAll, EyeWitness, CMSeeK, ctfr, GooFuzz, h8mail). The worker image now builds only nuclei and naabu, next to nmap and bbot, so it builds and starts faster. - Every CVE match is validated automatically. Before, only fire and smoke matches were queued for AI validation and the rest waited for someone to press Validate now. Now a match of any confidence or score is queued by itself, hottest first (fire, smoke, then ice at the lowest priority, using the capacity the hot ones leave), except one the AI ruled out or the distribution patched. Ice stops at five active jobs per project so it cannot crowd out hot findings, and the daily validation caps still apply.
CVENGINE_AUTO_VALIDATE_ALL_MATCHES=0restores fire and smoke only. - More nuclei templates run. Installed templates that follow redirects on the same host (
host-redirects, at most three hops) now pass the read-only policy, about 1,250 more (6,531 of 13,903 in the current community set, up from 5,280), among them the technology detection template, so hosts get fingerprinted again. A template that merely recognizes an interactsh server by its header is no longer taken for an out-of-band check. Redirects to other hosts stay refused, and AI-written templates still follow none. - naabu now runs by default. A full port sweep ahead of nmap used to be opt-in; nmap's own top-1,000 guess misses real services often enough (8443, 9200, 27017, and the like) that full coverage up front is worth the extra time for most installs.
CVENGINE_NAABU=0restores the old top-1,000-only behavior for installs scanning many targets on a tight schedule.
Added
-
Database metadata and two more exposure checks. nmap now reads MySQL, Microsoft SQL Server, MongoDB, Redis, Memcached, and CouchDB's own pre-authentication greetings for version, role, and, for MySQL and Microsoft SQL Server, the Windows identity their NTLM negotiation discloses, filling in a version or product nmap's own probe missed. Shown on the host page next to each port. Separately, the credential-less exposure check that already covers Redis, Memcached, PostgreSQL, Elasticsearch, and CouchDB now also tries MySQL (
root, no password) and MongoDB (listDatabaseswith no prior authentication): a server that lets either through with nothing at all is a critical finding. -
node2shell (CVE-2026-111497). Checks hosts fingerprinted as Node.js or Express with Assetnote's own read-only detector, no credentials sent and no command executed. Off by default, because its footprint (about 23 MB uploaded per host) is much larger than every other check here;
CVENGINE_NODE2SHELL=1turns it on. -
RDP login-screen screenshots. When nmap shows a server accepts a connection without Network Level Authentication, cvENGINE captures its pre-authentication screen with no credentials sent, stores it, and asks the configured AI model whether an account is already shown signed in and what it is called. A server that requires NLA is never attempted.
-
JavaScript libraries and technology columns. The web route check reads jQuery, Bootstrap, AngularJS, React, Vue.js, Lodash, Moment.js, and Underscore.js versions from script names and script banners, and Angular from the page, so old libraries reach CVE matching. Technologies now have
versionandcategorycolumns. The host page shows an overview, a technology table, per-service script output, and what the web archive remembers. -
Deeper service fingerprinting. nmap runs at version intensity 7 with the banner, SSH host key and algorithms, TLS certificate, HTTP header and title, anonymous FTP, RDP NTLM, SMB OS discovery, and NetBIOS scripts, and keeps the output per port. Search reaches it with
banner:. Windows build, computer name, and domain from RDP and SMB fill an empty OS guess, and an FTP server that allows anonymous sign-in is a finding with its listing as evidence. -
WPScan for WordPress sites. A host fingerprinted as WordPress is scanned at most once a day (
CVENGINE_TTL_WPSCAN=168for weekly) for its version, plugins, themes, config backups, database exports, and author names, and for known vulnerabilities when a wpscan.com API token is set under Settings, API keys. Findings and versions flow into Findings and CVE matching. -
Archived URLs as passive evidence. The Internet Archive's saved URLs show what a host ran in the past, such as PHP or WordPress. Search finds it and labels it as seen in the web archive.
-
Local checks for CVE matches nothing external can settle. When validation finds no read-only check exists for a match, such as a CVE in a specific vendor add-on no banner or template can see, cvENGINE asks the AI once for up to three short, read-only commands a person with shell access could run themselves, with what the output would mean. Shown under Confirm it yourself as a suggestion, never as evidence; the model is told never to suggest a command that changes anything or needs a credential, and to say so when it is not confident of the exact way to detect a product rather than invent one.
-
Remediation status on scanner and hygiene findings, and a bulk status route. CVE matches already had
open/in_progress/fixed/accepted_riskwith a note; scanner and hygiene findings now carry the same fields, set the same way:PATCH projects/{slug}/findings/{match,vulnerability,hygiene}/{id}(update_finding_status) for one finding,POST projects/{slug}/findings/status(bulk_update_finding_status) for up to 200 at once, answering{updated, failed: [{kind, id, error}]}so one bad id never blocks the rest. Marking one of these two statuses drops the finding out of the actionable Findings view immediately, whether or not a later scan still finds it. -
A new install starts loading CVEs by itself. As soon as its workers are up, a once-only
bootstrap_first_runtask pulls the CVE feed and threat intelligence and backfills recent entries (which in turn correlate and auto-fire), instead of waiting for the first scheduled run, up to 30 minutes for the feed and an hour for threat intelligence. It only acts when the CVE table is empty, so an update or a restart never repeats it, a lock keeps several workers from queuing it twice, and a first try that found no network is retried at the next worker start. A global scan pause does not hold it back. -
The setup wizard has a last, skippable step for search-engine keys. After the first target is added (discovery has already started by then), one page offers Shodan, VirusTotal and SecurityTrails keys next to a live line showing the discovery's progress (queued, running with hosts and IPs found so far, finished), so the first dashboard visit has findings in it. Keys are stored per project, never shown again, and apply from the next scan on. Adding a target twice, or while the scanner is still starting (a clear "try again in a few seconds" instead of an error page), starts discovery without creating a second scan.
-
A guide to hosting it online. docs/HOSTING-ONLINE.md covers a public name with a browser-trusted certificate: DNS and firewall, a Let's Encrypt certificate on the bundled proxy (it must be RSA, because the proxy's cipher list is RSA-only) with a renewal hook, running behind Cloudflare with Full (strict), using your own reverse proxy, checks, and a troubleshooting table.
-
One command installs it:
sudo ./install.sh. It asks nothing and no longer needs.envedited. It checks the machine (root, memory, disk, free ports 443 and 8082, Docker's registry reachable), installs what is missing on Debian and Ubuntu, generates the passwords, detects this machine's address forDOMAIN_NAME(or takes--domain), builds the HTTPS certificate, starts everything, waits until the site answers instead of guessing with a sleep, creates the admin account, and ends with one summary: address, username, generated password, and the certificate note. A failed step prints the log lines of the service that failed. Running it again is safe. The certificate now also covers an IP address asDOMAIN_NAME(before, an IP never matched), pluslocalhostand127.0.0.1, andCERT_EXTRA_SANSfor more names. -
A new install tells its owner how to sign in. Nothing used to generate or print an admin password: the installer left the owner to invent one at a prompt (or set
DJANGO_SUPERUSER_PASSWORD, which the plain prompt then ignored). Now./scripts/init-env.sh(run byinstall.shand bymakeon first use) creates.envwith the database and certificate passwords already generated, andmake admin(also the last step ofinstall.sh) creates the admin account, generates a password, and prints it once with the address and username; the owner chooses their own at first sign-in.make admin-passwordgenerates a new one for a lost password, and the sign-in page says where to look. A password set inDJANGO_SUPERUSER_PASSWORDis still used (and validated), and nothing is replaced on an install that is already running. -
Scanning pauses for an update's own restart, and Settings, Updates shows live progress.
scripts/apply-update.shnow requests a drain pause (new scan dispatch stops; whatever is already running is left to finish, never stopped) before it waits for active scans, and releases it once the run reaches a stable state, whichever commit that ends up being.GET /cve/api/settings/updatesreports the currentphase(idle,draining,applying,done,failed), a short detail, how many scans it is waiting on, and whether scanning is paused for this update, so the page no longer looks idle during a long build or migration. -
Status timestamps on findings. Every match, scanner, and hygiene finding response (detail and
findingsrows alike) now carriesstatus_changed_atandstatus_changed_by({id, username, name}), andfindingsrows also carryfirst_seenalongside the existingdetected, so aging, SLA-overdue, and time-to-fix can be shown without guessing from scan dates. -
SOC mode and live scan highlighting on the asset graph. The domains and hosts a scan is working on right now pulse on
/cve/graph/, fed by a newGET /cve/api/graph-live(running scans, the step each is in, the hosts they are working on, queued count; never cached, tenancy-scoped like the graph). SOC mode (a button, or?soc=1for a wall display) puts the graph over the whole window with a status bar (scanning, queued, fire, smoke, nodes, clock) and a Scanning now list, dims everything not being scanned while a scan runs, and has its own Full screen button; Escape leaves it. -
Bug bounty engagements get their own project in a Bug Bounty organization. Working a program (
POST /cve/api/bounty/engagements) now creates, on first use, a Bug Bounty organization and one project per program inside it (bb-<platform>-<handle>), puts the engagement there, and answers with itsproject,project_name, andorg, so imported scope targets are never mixed into a client's project. The page follows to that project.GET .../engagementswith noprojectlists every engagement in the Bug Bounty org the caller can see. The creator becomes the project's admin; a second authorized user working the same program gets a409naming the project rather than silent access to someone else's drafts. The audit role cannot create one. Existing engagements are not moved. -
Per-project SLA days.
GET/PUT projects/{slug}/settings(get_project_settings,set_project_settings) keep how many days a finding of each severity has to be fixed (critical, high, medium, low; defaults 7, 30, 90, 180) in one place per project, so "overdue" is the same for every user instead of a default baked into each screen.PUTis a partial update;nullrestores a severity's default. -
Screenshot thumbnails.
/cve/<project>/hosts/<id>/screenshot/?size=thumbserves a 320 px-wide JPEG, made on first request and kept beside the original (remade when the screenshot changes), so a gallery of hundreds of hosts does not download hundreds of full-size captures. Every screenshot response now carries anETagand a day of private caching, so a revisit is a 304. The same size, pixel, and decompression-bomb limits as screenshot comparison apply; a file Pillow cannot read is served at full size instead.sizeother thanfullorthumbis a 400. -
Assignee, comments, and an audit trail on findings. Matches, scanner findings, and hygiene findings can be assigned to a project member (
PATCH .../findings/{kind}/{id}withassignee, a user id ornull), commented on (GET/POST .../findings/{kind}/{id}/comments), and carry an audit trail of every status change, assignee change, and comment with who, when, and before/after (GET .../findings/{kind}/{id}/audit, bulk status changes included).GET projects/{slug}/membersfeeds an assignee picker. Rows and detail showassigneeandcomment_count.statusis no longer required on that PATCH whenassigneeis sent. Validation runs are not part of the trail yet. -
Finding detail shows status for scanner and hygiene findings.
GET .../findings/{kind}/{id}only reportedremediation.statusandnotefor CVE matches; scanner and hygiene findings now do too. -
Daily stats history for trend charts. A new beat task stores one point-in-time snapshot per project per day (hosts, exposed hosts, open findings by severity, CVE matches by heat, fixed count, mean days to fix).
GET projects/{slug}/stats/history?days=90(stats_history) answers the series oldest first, so exposure-over-time and time-to-fix charts have a past to plot instead of only today. -
Shodan-style comma-OR, a
country:filter, and general facets on search. Any field filter's value now takes a comma-separated list for OR within that filter (port:80,443), unless quoted. A newcountry:filter matches a host IP's geolocated country (ISO code or name).?facets=port,product,tech,os,countryadds the same whole-match, heat-chip-style countingfacets.heatalready did, asfacets.<name>: [{value, count}], up to?facet_size=values (default 10, max 50).org:/asn:/hosting:were also asked for, but CVEngine does not look up an IP's ASN or hosting provider today (only its country), so those are not implemented here. -
Heat facet counts and a server-side heat filter on search.
GET projects/{slug}/searchacceptsheat=fire|smoke|ice|clean|unscannedto narrow the page to that value, and always returnsfacets.heatwith every value's real count over the whole match ofq, ignoringheatitself, so the heat chips show accurate totals instead of only counting the rows already loaded on a big inventory. -
Search guide. docs/SEARCH.md documents every search filter with examples and the closest Shodan equivalents, for the Hosts page, the Ctrl+K palette, the REST API, and MCP.
Fixed
- The attack-surface map's hover card names the host's project. With "All projects" selected, the dashboard spans every project the viewer can see, and the card had no way to say which one a host belonged to.
- CI runs the whole test suite, not a short list of modules, and the image build no longer waits for it.
- Search. A bare word and
tech:find a host wherever its software was seen (web server andX-Powered-Byheaders, cookie names, banners, NSE output, route fingerprints, port product and version), not only in the technology list, andbanner:searches service banners.phpnow finds every host running PHP. - Findings counted wrongly.
save_vulnerabilityreturned the created flag of its last tag, CVE or reference lookup instead of the finding's own, so new-finding counts were off. - Test suite.
tests.test_hard_lockoutcalls the current lockout helpers, and the placeholdertests.test_nmapis gone with the code it was meant to test. - Unreviewed NSE scripts showing up in service output. nmap's
-sVsilently runs its whole "version" script category (rpcinfo,hnap-info,vmware-version, and more) on top of whatever--scriptasked for, and writes their output to the XML cvENGINE parses, win or error. None of those scripts have been reviewed for the read-only guarantee the rest of this list has, so they are now dropped before anything is stored, searched, or shown. A one-time migration scrubs any already stored on an upgrade, instead of leaving it there until that host's next scan. - The dashboard's live-discovery counts undercounted the graph above them. Hosts, IPs and open ports were totaled from only the scan being followed, so a rescan that added one host to an already-populated project read as "1 host" under a graph showing everything found to date. They now total the same live inventory the graph draws.
PATCH .../matches/{id}erased a match's remediation note whenever a caller leftnoteout of the body. Every status change had to resend the existing note just to keep it.noteis now a true partial-update field: omitting it leaves the stored note alone, and an explicit""still clears it. Applies to the new scanner/hygiene status routes too.- An AI activity row left "running" forever by a killed worker never closed. A nuclei or validation step whose worker was restarted mid-task (an OOM kill, a lost broker message) had no code path left to mark it done or failed, so it sat "running" in the feed indefinitely even after the scan it described had long since finished. The existing stuck-job reaper (
cveFeed.reaper, every 15 minutes) now coversAgentActivitythe same way it already does host assessments and validation jobs, closing any row still "running" after 11 hours.