Repository navigation
v2.0.0
Version 2.0.0 changes things that integrations can see, so read the upgrade notes first. Each project has its own update schedule, a change to a project or to techs.yaml is judged against the stored advisories at once with older history fetched as needed, CVSS is read from every version the sources carry, and projects are kept apart by vendor. Environments are free and optional, you can add your own technologies, the monitor reports GREEN, YELLOW or RED, the TUI is switched by letters, and independent black-box validation led to many correctness fixes.
Upgrading from 1.x
- Health levels are
green,yellowandred;ok,warn,failandunknownare gone. Update scripts that readlevelfromcvewatch status -json(report, daemon, each feed and channel) or from MCPget_status. A monitor that has not read a feed yet is yellow, notunknown.cvewatch statusstill exits non-zero only on red, and no longer printswarning:orOverall:lines. - The TUI screens are switched by the letters
OFPHS, not1to5, and the Status screen is now Health.F(fetch) is nowu, and a few other keys moved; the old and new keys are in the table under Screen keys. - Search terms that name a project, vendor, environment, status, owner and the like must hold on the same environment row, and an exclusion such as
-owner:annkeeps the rows that do not match, so some queries return fewer issues. The text oflistandsearchfor an issue open in several projects now has one version verdict per project; scripts should read-json. - An entry in
sources/with the id of a shipped feed now overrides only the fields it gives and keeps the rest; before, it replaced the whole feed. If you relied on a left-out field being empty, set it explicitly (for examplematch_structured: false). - The shipped
ghsasource sendsGITHUB_TOKEN, when that variable is set, as a bearer token to api.github.com. To keep it unauthenticated, addsources: [{id: ghsa, auth_env: ""}]to a file insources/. cvewatch updateandrunexit 1 when every source failed. One failed source among several still exits 0, and-jsonis unchanged. Check CI and cron wrappers that treated exit 0 as fresh data.- Regional production names such as
prod-euandeu-prodcount as production for "open in prod", the ordering and the development-only package rule (non-prodandpre-proddo not). Development-only packages now count by default inlocal,dev,int,developmentandtest, not only indevandint. - A project file with
environments:still loads with the same meaning, and a file withoutenvsstill meansdev,int,stagingandprod.cvewatch project NAME -migrate-envs -saverewrites the old block aswhen@<env>blocks, and any edit of the differences does it too. cvewatch rescanis nowcvewatch revalidate, and the old name still works. The first cycle after upgrading judges every stored advisory again, which can add findings, and fetches history back to the earliestsincedate or alert horizon of your projects, which can take minutes at NVD's request rate; an interrupted run continues where it stopped.- A
sincedate now also closes the open findings of advisories published before it, as not affected with a note. Moving the date earlier or removing it reopens them, and a status you set yourself is never changed. - Exports and state only gain fields. The JSON export keeps
schema_version1 and its required fields; targets gainvendor, issues gaincvss_version,cvss_vectorandcvss_source, andenvmay be any environment name instead of one of four. CSV has avendorcolumn at the end. The state and the audit log gain optional fields. enrich.cvssis on by default: tracked CVEs that no source rated are looked up at NVD, by CVE id only. Setenrich.cvss: falseto turn it off.
Added
Project files and environments
- Environments have free names (lowercase letters, digits,
-and_, starting with a letter, up to 32 characters);local,dev,int,stagingandprodare suggestions,productioncounts as prod, and a new project starts withlocal. - A
when@<env>:block in a project file holds only what differs there:techs(another version, or a technology that runs only there),exclude(generic technologies that do not run there) andimage. A technology can carryenvs: [...]to run only in some environments. - Environment edits
add_env,remove_envandrename_env:-env-add,-env-removeand-env-rename OLD=NEWon the CLI,+,-andrin the TUI, and the same kinds in MCPedit_project. A rename moves the environment's findings and says how many; a removal also drops its differences. - Edits for the start date, lockfiles, images, versions per environment and technology scope:
-since,-lock TYPE:PATH[:ENV][:dev],-unlock,-lock-dev,-lock-nodev,-image,-env-set,-env-unset,-env-exclude,-env-includeand-tech-envs TECH=ENV,ENVon the CLI, with matching kinds and alockfileobject in MCP. migrate_envs(-migrate-envson the CLI,mon the TUI's differences list) rewrites the oldenvironments:block aswhen@<env>blocks in one previewed step.- Project lifecycle: rename, duplicate, delete, disable and enable in the TUI (
R,D,X,Z, andNfor a new project), on the CLI (cvewatch project rename|duplicate|delete|disable|enable, which shows the consequences until-yes) and in MCP (manage_project, untilconfirm). Delete moves the project file to the backups, and-close-findingsmarks its open findings ignored. - Projects from one Dockerfile, compose or Kubernetes file:
cvewatch discover FILE,cvewatch setup FILEanddiscover_stack. Base images, compose services, Kubernetes images and packages installed in a Dockerfile are marked as infrastructure, with their category. - Discovery and setup skip what
.gitignoreand.git/info/excludeignore.-allreads them anyway, a directly given file that is ignored is refused without it, and the TUI folder box hides ignored entries. - Hints: advice about a project that is not an error, such as an unknown technology with its suggestions, a missing version, a lockfile problem, no prod environment or no start date. They show in the setup review,
cvewatch project,check_projectsandpreview_project_change, and in the TUI underw. check_projectsMCP tool: a read-only report of problems in project files, with the fixes it knows. Validation warns when a lockfile'senvis not in the project'senvs, since such a lockfile is never read.
Technologies and catalog
- Technologies the catalog lacks can be kept as your own keyword:
+termin setup,ctrl+oandKin the TUI, orcvewatch tech add|edit|remove|list. The entry goes toconfig/techs.yamlafter a preview, and a new project is written together with it. - MCP
suggest_tech(the closest names for a typed term),preview_tech_changeandedit_tech(with-allow-write) for your own technologies. The Settings screen's Tech catalog section lists yours, witha,eandx. - The Linux kernel entry takes the names people write (
ubuntu kernel,debian kernel,linux-image,linux image), and the words of an unknown technology are matched one by one.
Updating, history and scheduling
- Per-project schedule:
update: {auto: true, every: 1h}in a project file (everyat least 5m, default theinterval;auto: falseleaves the project out of scheduled runs),update.autoinconfig.yamlas the main switch,-update-everyand-update-autooncvewatch project,set_updatein MCP, and an Updates field in the TUI. - The daemon wakes when the first project is due, at the latest after
interval. A scheduled cycle fetches the feeds once, then judges, reports and alerts only the projects that are due;cvewatch update,cvewatch runanduin the TUI still cover every project. - Last update and next due time per project in
cvewatch statusand on the TUI Health screen; the Projects screen showsevery 1hwithdue now,next 14:05,pausedormanual. cvewatch doctorand validation: aneveryunder 5m is an error, one over 30 days is a warning, and a project withauto: falseis listed.- Revalidation: when a project, its technologies, versions, environments, lockfiles or
sincedate changes, or atechs.yamlentry or the alert horizon does, every stored advisory is judged again, including the ones that matched nothing before. New matches become findings and nothing stored is removed. It runs at the start of every cycle, on the TUI's next read, and in the daemon within about 15 seconds of a file change. cvewatch revalidate [-apply] [-fetch] [-json]previews or applies the same re-judging, and-fetchalso fetches the older advisories the change needs.rescanis the old name and still works.- Back-fill: when a change starts earlier than what the sources have covered, NVD is asked in 119-day windows with paging, GitHub advisories are followed page by page and KEV is read in full. Vendor records, RSS and Hacker News cannot go back, and the cycle notes say so.
sincecloses the open findings of advisories published before it, as not affected with a note saying why. Moving the date earlier, or removing it, reopens the findings cvewatch closed.- Alert horizon:
horizon:inconfig.yaml(unlimited,hour,day,week,month,yearorcustomwithfromandto). A vulnerability published outside it is not judged, alerted or put in a digest, and existing findings stay.cvewatch checkwarns when the window reaches further back thanlookback. published:search field (published:week,published:7d,published:2026-01-01..2026-03-01) and-published VALUEonlist,update,searchandexport.cvewatch updateand the daemon log each finished chunk or page of a long fetch. Stopping or a failure part way keeps the NVD windows that finished and the next run continues from there.
Ratings (CVSS)
- CVSS scores are read for every version the sources carry (2.0, 3.0, 3.1 and 4.0), from NVD, CVE records, GitHub advisories, CSAF advisories and articles. An issue keeps its issuer's score first, then the newer version, and
showand the exports carry the version, vector and source (cvss_version,cvss_vector,cvss_source). enrich: {cvss: true}, on by default: tracked CVEs that no source rated get a score from NVD's public API, at most 5 per cycle and once a day per CVE. Only the CVE id is sent.
Vendors, projects and access
- Projects can belong to a vendor:
vendor: acmein the project file (lowercase letters, digits,-and_, at most 63 characters), set withcvewatch project NAME -vendor acme, MCPset_vendoror by hand.project list,list_projectsand the project view show it, and projects without one are selected with-. - Every target of an issue carries
vendor: additive inexport-v1, avendorcolumn at the end of the CSV, and vendor in the SARIF properties and the markdown export. -vendor Vonlist,update,search,exportandcalendar,vendorin the MCP toolslist_findings,search_findings,get_calendar,get_vulnerability,explainandget_evidence, andvendor:acmein a search keep only the projects of that vendor.cvewatch show,whyandevidencetake-vendorand-project, andget_vulnerability,explainandget_evidencetakeprojecttoo; the targets, history and audit records of the other projects are left out.accessgrants acceptvendor:acmeinprojects: every project of that vendor, resolved on each request, so a project added to the vendor later is covered.- TUI context: the interface always works in one context, a project (
shop, oracme ▸ shop), the projects of one vendor, or all projects, shown ascontext: ...on the breadcrumb line. Rows of other projects are not shown, and the same issue in two projects is two rows.Cchooses the context from every screen, and with one project it is set by itself.
Health and status
- The health of the monitor is GREEN, YELLOW or RED, as for an Elasticsearch cluster, in
cvewatch status, the dashboard, MCPget_statusand the TUI header (GREEN · last check 12:13 (4m ago),YELLOW · 2 problems, with the glyphs ● ▲ ✖). - A list of problems (
problemsinstatus -jsonandget_status), each with a stablekey,level,title,detail,hintandsince, red before yellow, then oldest first. The causes are a failing or stale feed, a failing channel, an overdue daemon, no cycle yet, no enabled source, a project file or lockfile that cannot be used, and a broken audit chain. A problem stays until its cause is gone and cannot be dismissed; the state records when a failure streak began. - When the monitor is not green, the TUI Overview starts with its open problems and Health with the same list; Enter opens a problem with its detail and hint.
cvewatch statusprints the problems with their hints and has a Projects section.
Terminal UI
- Settings screen (
S) andcvewatch settings list|get|set|unset|add|diff|schema: every setting ofconfig.yaml,techs.yamlandsources/*.yamlwith its type and help. Changes are validated as the loader validates them, previewed, saved atomically with a backup, keep comments, and never show secrets; the audit log records the paths that changed, never the values. tuisection inconfig.yaml:refresh(how often the TUI re-reads the state, 30s by default),fetch(a fixed fetch period;0sby default) andauto(without a running daemon the TUI updates the due projects on the project schedule; true by default). All are on the Settings screen.- The TUI fetches in the background:
uupdates now, the header shows the run asfetch 3/12, and a click on it lists the sources that failed. A store busy with a daemon cycle is retried later without an error. - Overview lists every open issue, not only the policy violations;
/andssearch and filter it with the Findings syntax, andvshows the violations and warnings. - Navigation: a breadcrumb under the tabs (Left, Esc and Backspace go back one level), a jump box (
:or Ctrl+G) to an issue by ID or a project by name, rows that link to their targets with Esc returning, and mouse support (wheel, click to select, clickable tabs and breadcrumb). - Triage:
]and[for the next and previous issue, Space and Ctrl+A to mark issues, and one status change for all marked issues. - One issue page for the TUI,
cvewatch showand the reports, with References, Evidence, History, installed versions and affected ranges. Keys:landLselect a link, Enter opens it,ccopies it,vshows the evidence pack,Rthe report and+adds evidence. - Time filter:
tcycles the publication date (any time, past hour, day, week, month, year) on Overview and Findings, shown as a chip on the breadcrumb line, and0clears it. Overview and Health show the alert horizon when it is not unlimited. - Projects screen: a problems column and the problems of the selected project;
xpreviews a fix (every fix of a problem, chosen with[and]), andEopens the project file in the editor at the problem's line (vim, nano, emacs, VS Code, Sublime Text and more). A project file that cannot be read is shown as broken instead of stopping the TUI. - Project field editor (
c): environments, technologies, lockfiles with env and dev, differences per environment (versions, technologies that run only there, exclusions and images), since, updates and vendor. Each change is previewed as a diff before it is saved;+adds an item,-removes one after a question, andeon a technology chooses the environments it runs in. A VENDOR column shows on Projects when a project has a vendor. - Adding projects:
+adds one from a folder, from a Dockerfile, compose or Kubernetes file, or empty, and-removes the selected project after its name is typed. In the guided form,eon the review changes one step and returns to the review. The folder box completes with Tab, goes up with Shift+Tab, picks with Up and Down, and marks folders with lockfiles and manifests.+adds a lockfile by picking its file, and the type comes from the file name. Vrevalidates after a preview. The header showsrevalidatingandback-fillwhile it runs, and the Projects list marks with*the projects whose changes are not judged yet.tui.editorchooses the editorEopens files in, with its options (for examplecode --wait). Without it the TUI uses$VISUAL, then$EDITOR, then the first usual editor on the machine, and says which one it used.
MCP, CLI and exports
- MCP tools
get_settingsandpreview_settings_change(read-only), andedit_settingsandmanage_project(with-allow-write). The CLI flags and the MCP schema for project edits are built from one table, so they cannot drift apart. cvewatch showand report files include Installed, Affected and History sections.
Feeds and HTTP
- Source field
auth_env: the name of an environment variable whose value is sent asAuthorization: Bearer <value>. An unset or empty variable sends no header and is no error. The shippedghsasource usesauth_env: GITHUB_TOKEN, which raises GitHub's limit from 60 to 5000 requests an hour and needs no scopes for public advisories.cvewatch doctorsays whether the variable is set.
Environment files
cvewatchandcvewatch-tuiread.envand then.env.localfrom the current folder and from-rootat start, and-env-file FILE(repeatable) names the files yourself. The real environment wins over files, a later file wins over an earlier one, errors name the file and line but never a value, and a file other users can read gets a warning. See Environment files.cvewatch-tui -versionprints the version.
Changed
- A project file without
envsstill meansdev,int,stagingandprod, and the review says so with a hint.environments:is still read, but new files and edits writewhen@<env>blocks. - A
when@<env>block for an environment the project does not have is an error with a fix; a lockfile or technology that names one is a warning. - The daemon no longer refreshes every project on every
interval: a project is refreshed when its own period is up, which is theintervalwhen it has noupdate:block.tui.fetchkeeps its meaning, andtui.autois the default way for the TUI to keep data fresh. - Setup asks once whether an environment differs from the rest, only when there is more than one environment, instead of a version per technology and environment.
- The hint for a project without
sincesays what a start date does, including closing the findings of older advisories. - A search holds the terms that name a row on the same target and lists only those rows, a plain word included, so
project:crm env:prodno longer matches because another project has a prod row. - When an issue is open in prod in several projects, the reason reads
open in prod: blog, shop. - The text list of an issue open in several projects shows one version verdict per project,
shop (acme): prod,dev [affected]; blog: prod [not affected], and the vendor shows next to the project in the lists, the issue report and the plan. - Setting a project's vendor needs write access to every project.
- The health levels
ok,warn,failandunknownare replaced bygreen,yellowandredeverywhere (see Upgrading). - TUI screens are switched by their highlighted letter:
O,F,P,HandSfor Overview, Findings, Projects, Health and Settings. The Status screen is now called Health.0clears the time filter only, and the project scope is the context, chosen withC. The footer and the help are written from the same table as the keys. - TUI keys moved:
F(fetch) isu;FINO(status for every environment) is Ctrl+P in the note prompt offino;H(hints) isw;P(previous problem) is[;u(restore a setting's default) isd. - TUI: Enter on a project opens it, with its problems and fixes, and
eedits it.aadds a project (nworks),xpreviews a fix (fworks), andEopens the editor (oworks on Projects). - TUI: Esc cancels a fix preview, and
nno longer does.qquits only from the root of a screen; inside a level or a popup it goes back. - TUI lists name environments only where an issue differs from what the project monitors, and the Findings column is
PROJECTS (ONLY IN). Overview'sby environmentline readsall N environments alike (K open each)when the counts are equal.
Fixed
Project files, environments and technologies
- A missing or unreadable lockfile or SBOM was taken as proof that its packages were gone: the findings became
not_affectedwithno longer installed, lost their matches and did not come back with the file. Such findings now stay as they were, and a finding damaged that way is judged again once the package is back; status, owner and notes are kept. - Removing an environment left its open findings as current open targets. They are now set to
ignoredwith the noteenvironment removed from project, with their history kept; declaring the environment again reopens them, and a status a person set is not touched. - Editing a project's technologies or
sincedate did not judge advisories that were already stored, so a technology added later or an earliersincemissed older advisories. - A project whose file name differs from the
name:it declares could not be deleted, disabled, renamed or edited. Projects are found by their declared name now, and the mismatch is a warning. cvewatch initsaved lockfile paths as absolute paths with the default-root .; they stay relative now.cvewatch init -forceedits an existing project file in place, keeping its comments and backing up the old file.edit_projectandpreview_project_changeaccept alockfileobject, so fixes fromcheck_projectscan be passed on as they are.list_projectsshows a lockfile'sdeclared_pathnext to its resolvedpath, andremove_lockfileandset_lockfile_devaccept either; two spellings of the same file are an error that names both, unlessenvtells them apart.- An unknown technology such as
ubuntu kernelgets a fix that renames it to the catalog name, andDid you meanoffers only close names (rabbitMWfindsrabbitmq,algoliafinds nothing). - Kernel version suffixes such as
6.12.86-genericwere read as pre-releases, so they ranked before a fix at6.12.86. A build suffix no longer orders a version. - The
user-techs.yamlexample saidkeywords; the field isaliases.
Health, updating and feeds
- A new monitor reported
okbefore any cycle had run. It is now YELLOW with "no cycle has run yet" until a cycle has read at least one feed, and YELLOW with "no enabled sources: nothing will be fetched" when every feed is switched off. cvewatch update(andrun) exited 0 although every source failed. It now prints the open findings as before, then exits 1 with "all N sources failed; findings shown are from earlier runs".- The
ghsasource got HTTP 403 once GitHub's 60 requests an hour without a token were used. A 403 or 429 withX-RateLimit-Remaining: 0or aRetry-Afteris now a rate limit: a wait up tohttp.cooldown_429is waited out, and a longer one fails at once withrate limited by api.github.com until 14:05; set auth_env on the source for a higher limit. - A file in
sources/with only- {id: cve-records, disabled: true}was rejected ("needs a unique id, a type and a url"). An entry with the id of a built-in feed now overrides only the fields it gives; a new id still needs a type and a url, and a misspelled key is still an error. $EDITOR is not setstopped the TUI from opening a project or settings file. The editor is looked up now.- Hints and notes told you to press
Fto update; the key isu.
Audit, evidence and access
- The audit log missed findings created by a revalidation or a catch-up and the changes cvewatch makes by itself. Every new finding now writes
detectedwith its project and environment, and every automatic close or reopen writes astatusrecord with the actorcvewatch. Automatic changes show ascvewatch (automatic)in the markdown and the issue page. - The evidence pack and the issue history of a renamed project lost what was recorded under its old name. A rename now records the new name in the audit event (
to, additive; older logs are read from the note) and former names are followed, soArenamed toBrenamed toCshows all of it. The audit log is never rewritten. - The evidence pack of an actor limited to some projects reported
audit_intact: falsewhen none of the audit records was visible to them. It now lists the records of their projects and those of no project, saysno audit records visible to youand keepsaudit_intact: truewhile the chain verifies; a broken chain still givesfalse.
Terminal UI
- After the context was changed, the issue page of the old project stayed open under the new chip, and
aand the status keys acted on the old project's environment. A change of context now closes the issue page and its prompts, and an action on a finding outside the context is refused withthat issue belongs to <project>; choose its project with C. - In a project context, an issue opened from Overview or Findings started on another project's environment row, so assign and the status keys acted on the wrong project. The issue page now holds the rows of the context's project only, and the prompts name project and environment.
- Prompts keep what was typed when a write is refused, and show the reason; a second submit of a change that is still being saved is refused.
- The Projects cursor stays on its project when the list changes, and an open issue reloads after a status, assign, bulk or editor change.
Security
- Advisory links are listed only when they are plain http or https addresses, and long link titles are cut at 200 characters.
- On Windows, links open with
rundll32, not throughcmd, so&and^in an address are not read as shell syntax. - For
auth_env, only the variable's name is ever shown or logged, and a value that is not a variable name is refused without being echoed.