GAdvisory privacy notice
What a GAdvisory instance stores, why, and for how long. Written from the database schema rather than from a template.
Who is responsible
For gadvisory.org and for hosted GAdvisory instances, the controller is Gelhaus Solutions, Eichenwald 3, 49624 Löningen, Germany. Contact: contact@gplatform.org.
For an instance you run yourself, you are the controller and we process nothing. Nothing in this notice applies to your installation except as a description of what the software is capable of storing, which you may find useful when writing your own.
What is stored, precisely
This is taken from the database schema rather than described in general terms, because a privacy notice that says "we may collect certain information" tells you nothing.
Your account. Email address, handle, display name, locale, timezone, country code, an optional avatar and biography, optional Git username and email for record signing, when your email was verified, and when you last signed in. Sign-in is handled by an identity service we run ourselves, Hexclave, our fork of the open-source Stack Auth, on our own servers. It holds your password hash, your second factors and passkeys, your linked accounts and your sessions, and GAdvisory trusts what it vouches for. Where you choose a social sign-in (GitHub, Google or GitLab), that provider receives the request to sign you in. Accounts that came across from before the identity service existed also keep an older password hash in GAdvisory itself.
Disclosure requests. When somebody reports a vulnerability: the subject and body, the answers to whatever form was used, any file attachments, and either a linked account or a submitter name and email address. Where a report arrives by email, the message headers are kept with it (sender, recipients, any addresses in copy, and the message identifiers that thread a conversation) because a disclosure is a correspondence and the thread is the record.
The raw inbound payload is kept alongside the parsed version until 12 months after the report was triaged. That is deliberate: a report that was parsed wrongly is a report that has to be re-read as it was sent. Then an email's full header set, the IP address a web form was sent from and a webhook's body are deleted; the parsed report, its sender and recipients and its correspondence stay as part of the record. The original email is deleted from our intake mailbox 12 months after it arrived.
Participants in a request. Email address and display name for everyone on a thread, whether or not they hold an account.
Credits. Where a researcher is credited on an advisory, the name and contact they asked to be credited with. This is published, permanently, and that is the point of it.
Subscriptions. An email address, and nothing else. Subscriptions are confirmed by double opt-in and carry an unsubscribe token, so an address is only on a list because somebody clicked a link to put it there.
Browser push. Where enabled: the push endpoint your browser issues, its two keys, and the user agent string.
The audit log. Who did what, when, with the values before and after, plus IP address and user agent. After 180 days the IP address and user agent are replaced by a keyed hash, which can still show that two entries came from the same place but cannot be turned back into them. Each row carries a hash of the one before it, so the log can be shown not to have been edited after the fact. That is a security property, so a single entry is not deleted on request. Instead the log is shortened as a whole: entries go after 24 months, oldest first, and before each deletion we record the hash the remaining log starts from, so that what is left can still be shown to be complete.
Share links. Where a link is created for someone outside the instance: the invited email address, and a hash of any PIN. Each use records a hashed IP address and the user agent: hashed, not stored, because the question a share link needs to answer is "was this used from more than one place", not "where is this person".
Attachments. Filename, content type, size, a SHA-256 digest, and the result of a malware scan. Files are held in object storage.
Credentials. API tokens, OAuth client secrets and application secrets are stored only as hashes. Integration secrets are envelope-encrypted, and an instance can be configured to keep them in HashiCorp Vault instead.
Other details about people that the product keeps. If you link a GitHub account (which private fixes in GitHub mode need before they can invite you): your GitHub login, name and avatar address. For a person invited to a private fix by GitHub login who has no account here: that login and the state of the invitation. For a comment synced in from GitHub: the commenter's GitHub login. For an installation of our GitHub App: the login of the account that installed it. For a guest who opens a share link: a guest session with a hashed IP address and the user agent. For somebody who starts a report form and does not finish it: the draft, with the contact email they typed and their IP address. For every mail we send: a log entry with its sender and recipient addresses, kept for 24 months. For notification channels you set up: the target, an email address or a webhook address. For Git sync, if you configure it: the committer name and email you chose. For bot accounts you create: their name and handle. For your acceptance of our terms: the version and the time, and the mails that announce a change (see "What you accepted" below).
Artificial intelligence
The AI features are off unless somebody turns them on, are configured per scope, and run against an API key the operator supplies. GAdvisory ships no model provider of its own and sends nothing anywhere by default.
When they are on, they can draft and review advisories and triage incoming requests, which means the content of a disclosure report, including whatever personal information the reporter put in it, can be sent to whichever provider that key belongs to. Each stored credential records whether that provider trains on the data submitted to it, and the interface shows it.
The prompts and responses of each run are kept for 12 months so a proposal can be audited, then deleted; the record that the run took place, which tools it called and how many tokens it used stays.
On gadvisory.org and the hosted service these features are enabled. They are restricted, but not in the way the word usually implies: the restriction is on who may run them (the Gelhaus Solutions team) and not on what they may read.
Within the scopes Gelhaus Solutions and Postiz own, that reaches disclosure reports, the request queues and disputes; for an administrator it is effectively the whole instance.
So: if you send a disclosure report to a Gelhaus Solutions or Postiz scope, its content can be sent to the model provider when somebody on the team runs a task over it. The provider is OpenRouter (OpenRouter, Inc., United States), which routes to Google Gemini. Scopes belonging to other organisations are configured by those organisations, not by us. The transfer to OpenRouter rests on the European Commission's standard contractual clauses in its data processing agreement; Google LLC, to which it routes, is certified under the EU-U.S. Data Privacy Framework.
This is worth knowing before you write a report, which is why it is here rather than in a settings screen.
AI assistants you connect
GAdvisory can be connected to an AI assistant (Claude, ChatGPT, Claude Code, Cursor and others) through the Model Context Protocol, at /mcp. Nothing is connected unless you connect it. The assistant sends you to a consent screen on GAdvisory that names it and lists what it asks to do, in groups, with an access level for each: none, read, or read and write. What is ticked to start with is read-only unless the assistant asked for more, and you can change every line before you agree.
What we store. The assistant's registered name and redirect addresses (an assistant registers itself, and a registration that nobody has agreed to or used for 30 days is removed), your consent and the scopes you gave, the access and refresh tokens as hashes, and audit entries for the grant, each refresh and each revocation. The access token lasts an hour. The refresh token lasts 90 days unused, is replaced each time it is used, and if a replaced one is used again the whole connection is ended. The access appears in your account settings as an API token named "OAuth:" followed by the assistant's name, where you can revoke it; the assistant can end it too.
What the assistant can do. It acts as you and no further than you may: each call is checked against your own permissions in the scope concerned as well as against the scopes you gave. Tools that publish or change records are marked as such, so that the assistant asks you before it uses them. We cannot make an assistant ask.
What happens to what it reads. Whatever the assistant reads leaves GAdvisory and goes to the provider that runs it, under your own agreement with that provider. That is not our processing, and we cannot take it back. It includes reports with personal data in them and material under embargo: reading an embargoed advisory into an assistant can be the disclosure the embargo forbids. Connect an assistant only to what you may share with its provider.
Why. Your consent (Art. 6(1)(a) GDPR), which you withdraw at any time by revoking the token or ending the connection, without affecting what was done before. Keeping the record of the grant and of what was done under it is accountability (Art. 6(1)(f) GDPR). A connection stays until you revoke it or delete your account, and ends by itself once its refresh token has gone 90 days unused.
Private fix repositories
For an advisory that is not yet public, a person with the right can open a private repository for the fix, one per upstream project (Advisory Patch). It runs in one of two modes, chosen when it is created. In the native mode we host the repository ourselves, on our own server, and serve it on an address that begins with patch., with a small forge: browsing, history, branches, pull requests with reviews and in-browser editing. In the GitHub mode a private copy is made in a GitHub organisation, ours unless your organisation has us use one of its own, and people are invited there, which needs a GitHub account linked to yours.
What is stored. The upstream branch with its full history, the fix, pull requests, reviews and comments, and which files a reviewer has marked as viewed. Who has access: your account, or for an external collaborator the GitHub login they were invited by, with the state of the invitation. The credentials for landing the fix upstream, which you or the owner of a scope save: an HTTPS token, an SSH deploy key or an installation of our GitHub App on the upstream owner. A secret is encrypted, never shown again and used for nothing else; only who set it and when is shown. To work with a repository from your machine you sign git in with an API token, or through the browser or a device code; those sign-ins are stored as hashed tokens, end after 90 days unused, and are listed under Authorised devices, where you end any of them.
Who sees it. Only the people on the patch and, in the GitHub mode, GitHub: GitHub, Inc. (United States, certified under the EU-U.S. Data Privacy Framework) stores the private copy and its invitations as our sub-processor for this mode only. In a GitHub organisation of your organisation's own, GitHub holds the copy under your organisation's terms with GitHub, not as our sub-processor. We never open an upstream pull request on our own; the fix reaches upstream only when a person with the right to publish lands it.
If you were invited by your GitHub login and have no account here, this section is our information to you under Art. 14 GDPR: the source is the person who invited you, and the data is your GitHub login and the state of the invitation. We use it so that you can reach the fix, and pass it to nobody else but GitHub in the GitHub mode.
How long. When the advisory is published, the collaborators are removed from the patch and the repository is deleted 30 days later, a period your organisation can change. If an advisory is deleted, the person deleting it chooses to delete the repositories at once, to archive them and delete them after that period, or to keep them. A withdrawn advisory freezes its patches for everyone until it is restored.
Why. Coordinating a fix before disclosure is what you asked the service to do (Art. 6(1)(b) GDPR). For the people invited, it is our legitimate interest, and yours, in getting the fix made privately (Art. 6(1)(f) GDPR).
Why, and on what basis
Operating the service, authenticating you and keeping your account is performance of a contract, Art. 6(1)(b) GDPR.
Receiving, triaging and coordinating vulnerability reports is a legitimate interest under Art. 6(1)(f): the interest is in vulnerabilities reaching the people who can fix them. Where you send us a report, it is also Art. 6(1)(b), because you asked us to act on it.
The audit log, the abuse controls and the security of the service are Art. 6(1)(f).
Crediting a researcher by name is consent, Art. 6(1)(a), asked for at the time and withdrawable, although see the next section about what withdrawal can and cannot undo.
Subscriptions are consent, Art. 6(1)(a), and the double opt-in is the record of it.
Publication is permanent, and that is a limit on erasure
A published advisory is a public record. It is mirrored, indexed, aggregated into other vulnerability databases, and cited by systems we have no relationship with. We can remove a credit from our copy, and we will on request; we cannot remove it from everyone else's.
That is not a refusal of Art. 17. It is the honest scope of what erasure here can achieve, and it is worth understanding before asking to be credited by name.
How long
Account data is kept until the account is deleted. Deactivating an account marks it rather than erasing it; ask, and it is erased.
Disclosure requests and their correspondence are kept for as long as the coordination is open and afterwards as part of the record of how it was handled.
Audit entries are deleted after 24 months, with the chain's starting point recorded at each deletion; their IP address and user agent are replaced by a keyed hash after 180 days.
Subscription addresses are removed on unsubscribe.
AI assistant connections and git sign-ins end when you revoke them, or 90 days after they were last used. Private fix repositories go 30 days after the advisory is published, unless set otherwise. The mail log goes after 24 months.
Published advisories, and any credit in them, are permanent.
Who else touches it
Hosting is on infrastructure operated by Gelhaus Solutions, on servers rented from IONOS SE (Germany) and on our own hardware in Germany. Mail runs on our own servers at IONOS, and file storage is our own MinIO on our own hardware. The rule we work to is that anything which can reasonably be self-hosted is, and almost all of this is.
Error and performance reporting goes to Sentry (Functional Software, Inc.), on its EU data region, so what it holds is stored in the EU. What reaches it is diagnostic: the exception and its stack trace, the request that failed, and the identifier and handle of the signed-in user where there was one. IP addresses and request bodies are not sent. That rests on our legitimate interest in a service that works and is secure (Art. 6(1)(f) GDPR), and you may object at any time (Art. 21 GDPR). Besides it, the sub-processors here that are more than a place the servers stand are OpenRouter for the AI features and GitHub for private fixes in GitHub mode, each described in its own section. Functional Software, Inc. is in the United States and certified under the EU-U.S. Data Privacy Framework.
A recording of your visit is made only if you say yes. The default is no recording. A bar at the foot of the first page asks, with two equal buttons; a "Session recording" link in the footer opens the question again, and while you are signed in a switch under Settings, Account does the same. If you say yes, Sentry receives a replay of the visit from the first page to the last: what was on screen, the clicks and what changed. It is not masked: it shows the page as it was on screen, including draft advisory text and what a reporter typed, because a masked replay cannot show what went wrong. We never record on the pages of a private fix repository, because a replay there would record the fix's code. To join the pages of one visit, the Sentry script keeps a random identifier in your browser's session storage, which is gone when you close the tab, and your answer is kept in your browser's local storage under gadv.replay-consent so that the question is not asked again on every page. The recording rests on your consent (Section 25(1) TDDDG, Art. 6(1)(a) GDPR), which you can withdraw at any time with the same link or switch, without affecting what was recorded before.
Browser push, where you switch it on, is delivered by the push service your own browser nominates: Google for Chrome, Mozilla for Firefox, Apple for Safari. Those are outside the EU, and there is no way to deliver a web push without one. The service receives the endpoint and the timing; the payload is encrypted to your browser's own keys, so it does not receive the content. Not enabling push means none of this happens to you.
Where an instance has AI features enabled, the provider whose key is configured receives whatever those features send it. That provider is chosen by the operator, not by us.
AI assistants you connect receive what they read, as described above: that is your choice and your agreement with their provider, not processing on our behalf.
Publishing sends an advisory outward, on purpose. Publishing to GitHub Security Advisories sends the advisory and any credit in it to GitHub, Inc. in the United States, per advisory, and with the consent for it recorded against that advisory. Publishing through the CVE Program sends it to the CVE Program, also in the United States. So does syncing records into a Git repository you have configured. GitHub is certified under the EU-U.S. Data Privacy Framework.
Those are recipients rather than sub-processors: they receive a published document because publishing it was the whole point, and they then act for themselves rather than on our instructions. This is the machinery behind the section above about publication being permanent, and it is worth reading before asking to be credited by name.
No analytics service, no advertising network, and no third-party fonts or scripts are used.
The account menu and the list of our products
The pages carry a shared account menu and a list of our products, drawn by GPlatform Identity, our own service under the same controller. So that the list is right on your first day, this product tells GPlatform Identity that an address it has verified uses it: a keyed hash of the address, not the address, and the time of the last report. GPlatform Identity keeps it for 180 days after the last report and uses it for nothing else. The GPlatform Identity privacy notice describes it, including your rights over it.
Why. An account menu that shows the products you already use (Art. 6(1)(f) GDPR).
Precautions against an attack on our systems
If our systems may have been compromised, Gelhaus Solutions can put GAdvisory into a lockdown through a security service of its own, GLockdown. A lockdown has stages. First, no new accounts and no new OAuth or MCP clients. Then only members of an organisation, group or project can sign in or use an API token, and share-link guests, apps and bots are refused. Then only instance administrators can sign in, through the browser alone, and intake by webhook and anonymous request drafts are refused. At the last stage nobody can sign in. Pages that need no sign-in carry on at every stage.
We also keep decoys that no real person uses: an administrator account and an API key. If somebody signs in as the decoy account or sends the decoy key, the attempt is refused like any invalid credential and reported to GLockdown with the time and the address and browser it came from, so that a lockdown can be raised.
Why. Defending the service and the people who use it against an attack (Art. 6(1)(f) GDPR).
What you accepted, and the notices we send
When you accept our terms, GPlatform Legal, another service of ours under the same controller, records it: the address of your account, the identifier the product knows you by, which versions you accepted, when, through which product, and your IP address and browser at that moment. It also keeps the mails with which we announce a change before it binds (to your address, with whether they arrived and any bounce) and anything you object to; they come from legal@gplatform.org. The entries are chained by hashes so that nobody can change them afterwards. Proof of acceptance is a record in its own right and is kept longer than your account data, because we have to be able to show what you agreed to: at the end of the third calendar year after the year your account closed (the sixth if you ever paid for something), your address is removed, the identifier becomes a keyed hash, your IP address and browser details are erased from each entry, and what stays is the version, time, source and hash. The GPlatform Legal privacy notice describes that service in full.
Why. Proving the consent you gave and the terms you agreed to, and informing you of changes as the general terms require (Art. 6(1)(b), (c) and (f) GDPR; Art. 7(1) GDPR; Art. 17(3)(e) GDPR).
Your rights
Access (Art. 15), rectification (Art. 16), erasure (Art. 17), restriction (Art. 18), portability (Art. 20), and objection to processing based on legitimate interests (Art. 21). Consent, where it is the basis, can be withdrawn at any time without affecting what was lawful before. You can download everything held about your account as a JSON file yourself, with "Download my data" in your account settings.
An informal email to the address at the top is enough.
You may also complain to a supervisory authority. The competent one here is Die Landesbeauftragte für den Datenschutz Niedersachsen, Prinzenstraße 5, 30159 Hannover.