Security
If you are an agency, the person who has to approve this is your client’s administrator, and they will want the answers on one page. This is that page. It describes what the product actually does, including the parts that are less convenient for us.
What we ask for, and what that really grants
The GitHub App requests two repository permissions: Contents: read and Metadata: read. It requests no organisation permissions at all, which is deliberate: it means a repository administrator can install it without escalating to your organisation owner.
We will not pretend this is narrower than it is. GitHub has no permission that grants manifest files alone, so Contents: read grants read access to all file contents in the repositories you select. The honest statement is not “we can only see your manifests”. It is that we are able to read more, and we fetch only the paths listed below, log every one of them, and show you that log.
Install with “only select repositories” if you want to narrow it further. That is the default in our onboarding flow.
Exactly which files we fetch
We never clone a repository. We list the file tree once, then request these paths individually, and nothing else:
- package.json
- package-lock.json
- npm-shrinkwrap.json
- yarn.lock
- pnpm-lock.yaml
- bun.lock
- pnpm-workspace.yaml
- .npmrc
- .yarnrc.yml
- bunfig.toml
- .nvmrc
- .node-version
- Dockerfile
- Dockerfile.*
Plus one pattern, because workflow files have arbitrary names and cannot be listed the way everything above can:
- .github/workflows/*.yml
Nothing else under .github: not your issue templates, not your Dependabot configuration, not your CODEOWNERS.
Both lists are read directly from the code that does the fetching, so the page cannot drift away from the behaviour. Every request is recorded against your organisation with the path and the file hash, and is visible to you in the app.
The Dockerfile and workflow files are read for one reason: the base image you build on and the actions your CI runs are dependencies too, and they appear in no lockfile. We take the FROM lines and the uses: values, and nothing else from those files. A repository can carry many workflow files; we read at most eight per scan and say so when that cap applies, rather than presenting a partial inventory as complete.
We store the parsed dependency inventory: package names, versions, and how they relate. We do not store your source code, and manifest file contents are discarded once parsed.
What leaves the system
To tell you a package is out of date we have to ask a registry about it. That means public package names are sent to the npm registry, Google’s deps.dev and OSV.dev.
Private package names never leave. A dependency is treated as private, and excluded from every outbound request, if it resolves through a workspace, link, file, git or patch protocol; if its scope maps to a non-public registry in your .npmrc; if its lockfile entry resolves to any host we do not recognise as the public npm registry; or if it is a package defined inside your own repository.
That rule fails closed. An unfamiliar registry host is treated as private rather than assumed public, which means a proxy such as Artifactory is also withheld. We would rather show you fewer version comparisons than disclose one internal package name.
This is not only a privacy position. A dependency inventory is exactly the reconnaissance list a dependency-confusion attacker wants, and those campaigns against corporate npm scopes are active.
Credentials we may encounter
Registry configuration files often contain auth tokens that were committed by accident. We parse those files for one thing only: which scope maps to which registry host. Any line holding a token or password is discarded before the result is assembled, and the raw file is never stored or logged.
If we see one, we will tell you so that you can rotate it. We will not show you its value, because we no longer have it.
Where the data lives
The database and application run in the United States, in AWS us-west-2 and Vercel’s Washington region. Transfers from the EU and the UK are covered by the standard contractual clauses in our data processing agreement and in those of our processors.
We chose US hosting because every registry the sync loop talks to is US-hosted, so co-locating removes a round trip from each request. There is very little personal data to localise: the only personal data we hold is the GitHub login and identifier of whoever installed the app, and the email address on the account. Package names and versions are not personal data.
If a client contract requires EU residency, that is available on the Enterprise plan.
Deletion
When the app is uninstalled we mark the installation’s data for deletion immediately and erase it permanently within seven days. The delay exists so that an accidental uninstall does not destroy your history; it is well inside the thirty days GitHub’s Marketplace agreement allows.
Removing a single repository from the installation deletes that repository’s data on the same schedule. An owner can delete an organisation and everything in it from the settings screen, without contacting us; it takes effect immediately and becomes irreversible after the same seven days. Administrators cannot, deliberately, because the action cannot be undone once the window closes. Every deletion is recorded, and we can produce that record if your client asks for evidence.
What our malware detection actually catches
We back-tested the rules against every npm malware record OSV holds: 221,440 of them, run through the same normaliser and the same priority rules that run in production. Every live record is surfaced, and none of the 331 withdrawn records fires.
6% page you immediately. That number is low on purpose. Nearly nine in ten of these records condemn a whole package rather than naming versions, which is what a typosquat looks like — someone publishes lodahs, a scanner catches it, no version range is filed. If you have not installed it, it is not your emergency. A page requires the record to name the exact version you have and to be corroborated by a human review or two independent feeds.
Withdrawals are the part worth checking in any tool that claims malware detection. OSV retracted 157 automated reports in a single batch in May 2026, including one against FastAPI; a tool that treated every record as an emergency would have paged their users for three days. Ours fires on none of them.
Two things this does not measure, because a recall figure without them is misleading: whether OSV knows about a given piece of malware, which is a property of the feeds rather than of us, and how long it takes a record to appear after a malicious publish. The full method, the year-by-year breakdown and the script that reproduces it are in docs/malware-recall.md.
How the connection is protected
Webhook deliveries are verified with an HMAC signature over the raw request body, compared in constant time. Installation tokens live for one hour and are held in memory only, never written to the database. The application’s private key and webhook secret are held in a secrets manager.
Every tenant table is protected by database row-level security keyed on your organisation, and no table grants write access to a browser session at all. We test cross-tenant isolation on every change, by asserting that a member of one organisation reading another’s data gets nothing back.
Data is encrypted in transit and at rest by our infrastructure providers.
If something goes wrong
We will notify affected customers within 48 hours of confirming a security incident, and GitHub within 24 hours where their agreement requires it. To report a vulnerability in Libyears, email security@libyears.com. We will acknowledge within one business day.
What we do not have yet
We are a new product and it would be dishonest to imply otherwise. We do not hold a SOC 2 report today. We will begin a Type I audit when a customer needs one, and we would rather tell you that now than during procurement.
What exists today is this page, a data processing agreement, a published list of our subprocessors, the deletion guarantees above, and an audit log of every file we have read from your repositories.