The product
GAdvisory is a self-hosted vulnerability advisory database and CNA workflow. It holds the drafting, review, identifier assignment and publication of security advisories in one place, on infrastructure you control, with no coupling to a source repository and no dependency on a network you do not own.
One record, from report to publication
An advisory in GAdvisory starts as a draft in a project, gains affected products and version ranges, severity, weaknesses, references and credits, goes through review, is assigned identifiers, and is published to every channel the operator has configured. The same record carries the whole history: who wrote what, which identifier came from which registry, what was sent upstream and when.
Nothing about that workflow is unusual, and it is not meant to be. What is different is where the record lives and what it is coupled to. It is not attached to a repository, it is not served from anybody else's hostname, and every step of it works with the network switched off.
Groups, organizations, projects
Advisories belong to a project. Projects belong to an organization, organizations to a group, and a group is the top of a tenant's own world. That is three levels rather than one because access, publication policy, identifier prefixes, custom domains and numbering-authority remits are all decided at different heights: a company holds the group, a product line holds the organization, a shipped component holds the project.
Every level carries a visibility. Public is listed and indexable, private requires membership, and unlisted sits between them: reachable by anyone holding the URL and absent from every listing, feed and sitemap. Permissions are per-level memberships that cascade downward, so granting somebody a role on an organization grants it on every project beneath it, and a role set explicitly on a project wins over what it inherits.
The practical effect is that one instance serves several teams without their advisories, members, or published pages ever meeting.
The advisory editor
The editor is seven tabs, each a real URL: details, impact, additional context, sources, CNA, distribution and activity. It is split that way because the fields answer unrelated questions. Impact is severity and affected products; context is everything known around the vulnerability; sources is references and credits; CNA is where identifiers are requested and records are pushed upstream; distribution reports where the advisory is actually reachable in public and what is blocking it where it is not.
Several people can hold the same advisory open. Edits broadcast per field and reconcile last-write-wins on that field's version, so two people working on different sections never collide, and two people working on the same field resolve rather than fork. Unsaved work is tracked per panel and guards navigation away from it.
An advisory moves through draft, in review, published, withdrawn and rejected. Publication is a state change on the local record; sending it to an upstream registry is a separate, explicitly authorised act, because one is reversible and the other is not.
What each state means
| State | What it means |
|---|---|
| Draft | Being written. Visible to members only, whatever the project's visibility says. |
| In review | Content complete and awaiting a second pair of eyes. Still not public. |
| Published | Live on every channel its visibility and embargo permit. |
| Withdrawn | Was published and no longer stands. The record and its identifiers are kept, because an identifier that was cited cannot be un-cited. |
| Rejected | Judged not to be a vulnerability. Terminal, and never auto-synced upstream again. |
Embargo is a date, not a workflow to remember
An advisory can be published while still inside an embargo window. The record is complete, the identifier can be reserved, and every public read path withholds it until the date passes. When it does, the embargo lifts on its own and the advisory appears everywhere at once, including in feeds and in the search index.
That is what coordinated disclosure needs: the work is finished ahead of time and the release is a clock rather than a person remembering to press something at the agreed hour.
Four kinds of identifier, one record
Every advisory has an internal id from the moment it is created, drawn from a per-scope template, and a public id when it is published. On top of that it can carry identifiers from outside: a CVE assigned through MITRE, CVE Services or GitHub; a GHSA if the advisory is mirrored to GitHub; a GCVE if the scope operates as a numbering authority; and a GAVR if it participates in the GAVR network.
They coexist deliberately. One vulnerability legitimately holds several identifiers, and discarding the duplicates destroys exactly the duplicate-resolution information a reader needs. One of them is marked as the one to cite; the rest are retained and shown as what they are.
Assignment of a permanent identifier is gated. Because a CVE cannot be un-minted, an operator has to approve the request before anything reaches a registry, and the approval is bound to the exact document that was reviewed.
Where a published advisory appears
Six channels, and they do not share preconditions. The four this instance serves inherit the advisory's visibility and embargo; the two upstream ones do not, because a record published to a registry stays readable there whatever the local copy later becomes.
| Channel | What it is |
|---|---|
| Public page | The advisory's own URL on this instance, with structured data for crawlers and a shareable link card. |
| Custom domain | The same advisory served under a verified domain of your own, with your branding rather than the instance's. |
| Atom feed | A subscribable feed per scope, for readers and for machines that poll rather than receive. |
| GCVE feed | The publication feed a GCVE numbering authority serves, in the format the aggregators collect. |
| CVE record | The record on cve.org, when the advisory has been published through a CNA configuration. |
| GitHub advisory | The mirrored GHSA on github.com, when a repository is linked and publication was consented to. |
The distribution tab reports each of the six for the advisory in front of you, and where one is not live it names the reason in terms of something you can act on rather than as a blank.
How reports arrive
Reporters reach a project through a public intake form, which the operator builds themselves: fields, branching, and a routing decision at the end. Four kinds of thing arrive through it, and they are kept apart because they need different handling: vulnerability reports, disputes about a CVE record, suggested changes to a published advisory, and appeals against a decision.
Mail works too. An intake mailbox is polled, threaded correctly through reply headers, and answered from inside the request rather than from somebody's client, so the whole exchange stays on the record. Replies from anyone who is not a participant on that thread are refused, because possessing a forwarded copy of an e-mail is not authorisation to write to a coordinated-disclosure thread.
Triage assigns, states, links a request to an advisory, and keeps internal notes that the reporter never sees.
Running it
Everything that changes is written to an append-only audit log with a hash chain over its own rows. Advisories, requests, comments and that log can be mirrored continuously into git repositories you control, as canonical JSON, so the record survives the application entirely.
Notifications go to an in-app inbox, e-mail, Slack, Discord, Microsoft Teams and outbound webhooks. Search is full-text across everything the reader is allowed to see. There is a REST API and an MCP endpoint for AI clients, both scoped by API tokens that are closed by default. Sign-in is your own identity provider over OIDC or SAML.
Secrets are encrypted at rest under a key you hold, or kept in your own Vault and never written to the database at all.
Keep reading
This page covers what the product does. The rest of the documentation covers the decisions around adopting it.