A scan, then a pull request
Scandar does not write the default branch. The fix stays on scandar/fix-… until you merge it.
What a scan does
- Sign in with the GitHub App. Only the repositories chosen at install are visible.
- Find projects: a
package.jsonnext topackage-lock.json,pnpm-lock.yaml, oryarn.lock. Nested manifests without their own lockfile count as workspace members. - Parse the lockfile and query OSV.dev. Duplicate advisory IDs are merged.
- Build a fix plan. Direct dependencies move to
^fixed. Transitive ones are pinned with overrides,pnpm.overridesorpnpm-workspace.yaml, or Yarnresolutions. - Regenerate the lockfile in a temporary directory, with package scripts disabled, then open the branch and the pull request.
You can check individual packages. Major bumps start unchecked. Several pull requests can be open on one project, and the same package is not patched twice.
Safer fix pull requests
A fix does not propose a release published fewer than your version delay. The default is 5 days. Set it under Settings → Pull requests, or override it on one project. 0 disables the delay. The maximum is 90 days.
Scandar reads each npm version's publish time and checks the version that actually lands in the lockfile. A range that would float onto a younger release is pinned to the admissible version. If nothing old enough exists yet, the fix is postponed and the page shows when it becomes eligible. A critical advisory, a known exploited vulnerability, or a malicious package is still proposed, with a warning that the version is recent.
When package.json already accepts the fixed version, only the lockfile changes. npm uses npm update --min-release-age and pnpm uses minimumReleaseAge. Yarn 1 has no equivalent, so the resolved version is checked afterwards and pinned if it is too new. Python, Go, Rust, PHP and Ruby use the delay when their registries return publish dates. Otherwise the pull request says the cooldown was not applied.
The pull request includes a "Why this version" section: the OSV fix, the version chosen, its publish date, the delay, any exception, and newer releases that were skipped. A major upgrade shows a break risk of low, medium, high, or unknown, from public release notes, Node engines and peer dependencies. Major upgrades stay unchecked. Auto-merge is off until you turn it on. It squash-merges only a patch or minor fix, never a transitive override, only after every check is green and you can still push.
Ecosystems
| Ecosystem | Files | Automatic fix |
|---|---|---|
| npm | package-lock.json, pnpm-lock.yaml, yarn.lock | Yes, except Yarn Berry |
| Python | poetry.lock, uv.lock, Pipfile.lock, requirements.txt pinned with == | Listed, not applied |
| Go | go.mod | Listed, not applied |
| Rust | Cargo.lock | Listed, not applied |
| PHP | composer.lock | Listed, not applied |
| Ruby | Gemfile.lock | Listed, not applied |
GitHub App permissions
| Permission | Used for |
|---|---|
| Contents | Read files, create the branch and the commit. |
| Pull requests | Open, squash-merge, and close. |
| Metadata | Read. Granted by default. |
| Checks | Read CI before a merge, and write the Scandar check. |
| Commit statuses | Read, for the same merge decision. |
Local OAuth callback: http://localhost:3010/api/auth/callback/github. The app listens on port 3010. npm, pnpm, and yarn need to be on PATH for the lockfiles they regenerate.
Limits
- 10 projects per repository, 60 workspace members. The rest are dropped.
- A truncated Git tree falls back to the root package.json.
- Severity comes from
database_specific.severity, then from the CVSS v3 score. With neither, the advisory is Unknown. - Package health and transitive licenses cover npm only.
- Lockfile regeneration times out after 3 minutes.
- One Node process: SQLite and the in-memory event bus are not shared across instances.
Around the scan
An ignored advisory needs a reason, a note, and a duration. It leaves totals, fixes, notifications, and pull request checks until it expires. History keeps open vulnerabilities for 90 days. Exports are CycloneDX 1.5, SPDX 2.3, CSV, and a printable report. A push to the default branch can rescan through the GitHub App webhook, and Slack or Discord can receive alerts above a severity you set.
CI, CLI, and editors
The same check runs from GitHub Actions, the terminal, or an editor agent. Each client calls POST /api/v1/check with an API key. The plan needs the api feature. Nothing here is on npm or the GitHub Marketplace yet.
Public package and advisory pages
/package/<name> (including @scope/name) and /cve/<id> (a CVE or a GHSA id) are public. The name is checked before anything is requested. A name that does not match, or a package or advisory OSV and the npm registry do not know, is a 404.
The page shows severity, affected and fixed versions, and KEV or EPSS only from data already stored here. Plain-language wording appears only when it is already in the explanation cache. These pages do not call the model. The OSV advisory stays linked, because a cached explanation can be wrong.
Repository reports under /scan/… and the printable /report page are noindex. /dashboard, /admin, and /api are disallowed in robots.txt.