patchnow v0.1 · MIT · open source

Exploited-vulnerability response, automated.

Vulnerabilities are disclosed faster than teams can read the advisories, and exploitation now often starts before a fix exists. PATCH matches OSV.dev, CISA KEV and EPSS against the exact versions you run, then executes the response you approved in advance: a pinned-version pull request, safe mode, credential revocation and notifications. Every decision is written to an audit log.

CVEs published · last 24h
—
per hour, −24h → now
Rate
—/h
last hour —
30-day average
—/day
NVD
CISA KEV catalog
—
—
Added to KEV · 30 days
—
—
Newest CVE
—
—

Sources: NVD CVE API 2.0, CISA KEV. Server-cached, refreshed every 15 minutes.

01

The exposure window is closing

More vulnerabilities are published every year, and attackers use them sooner. A response that waits for a human to read an advisory now starts too late.

CVE records published to NVD per yearloading…

Rejected records excluded. Current year shown year-to-date with a linear projection.

Average time-to-exploit (Mandiant)days from patch release to exploitation
PeriodTTE
2018–201963 days
2020 – early 202144 days
2021–202232 days
20235 days
2025 (estimate)−7 days

A negative value means exploitation began, on average, before a patch was available. Sources: Mandiant, 2023 Time-to-Exploit Trends (2018–2023); M-Trends 2026 (2025 estimate). The 2023 average excludes 15 statistical outliers; with them it is 47 days.

What that means for response. When a fix exists, PATCH opens the pull request that pins it, in minutes rather than at the next triage meeting. When exploitation comes before the fix, patching cannot help, so the pre-approved containment steps do the work: safe mode, credential revocation, paging.

02

Recent advisories

Four ecosystems in one week, October 17–21, 2026. Each entry links to the vendor's advisory.

  1. Critical

    PHP2Shell: unauthenticated RCE in PHP core

    CVE-2026-109618 · CVE-2026-109619 · CVSS 4.0 9.2

    Two remote code execution flaws affecting PHP installations that serve web requests (FPM, mod_php, CGI, FrankenPHP, LiteSpeed). CISA advises taking PHP systems offline if they cannot be patched immediately.

    Fixed
    8.5.12 · 8.4.27 · 8.3.36 · 8.2.35
  2. Critical

    GitLab: unauthenticated RCE via regex compiler integer overflow

    CVE-2026-110264 · CVSS 3.1 10.0

    Affects self-managed GitLab back to 7.0. Fixed releases cover seven release lines, back to 18.11.

    Fixed
    19.5.1 · 19.4.3 · 19.3.6 · 19.2.9 · 19.1.9 · 19.0.10 · 18.11.13
  3. High

    Node.js security release: 10 CVEs, including a Brotli decoder RCE

    CVE-2026-111497 and 9 others

    An out-of-bounds write in the bundled Brotli decoder affects any process that decodes attacker-controlled Brotli data, including fetch() responses. Vercel deployed WAF rules the same day and notes that only the runtime update covers fetched responses. End-of-life release lines receive no fix.

    Fixed
    26.12.1 · 24.22.1 · 22.23.4
  4. Patch update

    Oracle Critical Patch Update, October 2026

    1,295 security patches across Oracle product families.

  5. Trust

    eMudhra intermediate CA certificates distrusted

    8 intermediates · emSign ECC Root CA - G3

    Eight intermediate CA keys were generated with insufficient randomness. Chrome, Firefox, Apple and Microsoft blocked them; Chrome is removing the root. Go released 1.27.3 and 1.26.10 on October 19 with a crypto/x509 security fix.

    Update
    browsers · Go toolchain · anything with an embedded CA store

As of KEV catalog 2026.10.21, none of these CVEs is listed as known exploited. The live tables below update automatically.

03

Known exploited and critical, live

By default PATCH acts on two signals: evidence of exploitation in the wild (CISA KEV) and critical severity in a version you actually run. These are the current feeds.

CISA KEV · latest additionsloading…
AddedCVEVendor · productVulnerabilityDueRansomware
Loading…
NVD · critical CVEs, last 7 daysloading…
PublishedCVECVSSKEVSummary
Loading…

04

Check a lockfile

This uses the same parser and matcher as the CLI, running in your browser. The file is parsed in this tab; only name and version pairs are sent to api.osv.dev. Results are cross-checked against CISA KEV.

Drop a file or click to choose

package-lock.json · package.json · yarn.lock (v1) · composer.lock · requirements.txt · poetry.lock · go.mod · Cargo.lock

Nothing is stored or logged.
Runtime checkFixed versions from the advisories above

A lockfile does not record your runtime. Enter the output of node -v, php -v, go version or the GitLab admin page. The CLI detects node, php and go automatically.

05

How it works

A single CLI, patchnow, runs on a schedule in CI or as a daemon. Policy lives in your repository as patch.yml. Nothing destructive happens until you set armed: true.

PATCH architecture OSV.dev, CISA KEV and NVD/EPSS feed a matcher that reads lockfiles and runtimes. Findings go through the patch.yml policy, which triggers actions (pull request, safe mode, revoke, notify). Every step is written to an audit log. SOURCES OSV.devadvisories, fixed ranges CISA KEVknown exploited FIRST EPSSexploit probability MATCHER patchnow scan npm · pnpm · yarncomposer · pip · poetrygo.mod · Cargo.lockruntimes: node · php · go→ findings: severity, fixed-in, KEV, EPSS POLICY patch.yml triggersignore + expiryallow / excludededupe statearmed: false→ dry run ACTIONS pin_patch → PR safe_mode revoke notify RECORD audit.jsonlevery decisionevery actionappend-onlySARIF →code scanning Runs locally or in GitHub Actions. Sends package names + versions to OSV, CVE IDs to EPSS. No source code leaves your machine.

1 · Match

Lockfiles are parsed for exact versions and queried in batches against OSV.dev. Each finding carries its advisory severity, the smallest fixed version, its KEV status and its EPSS score.

2 · Decide

Triggers in patch.yml are evaluated: any entry can fire, and every key within an entry must match. Ignores need a reason and can expire. Findings that already fired are deduplicated.

3 · Act

Actions run in order: a pinned-version pull request, safe mode on Render, Vercel or a webhook, credential revocation, then notifications that include the PR link.

4 · Record

Every run, decision and action is appended to .patchnow/audit.jsonl. SARIF output feeds GitHub code scanning.

06

Documentation

Reference for v0.1. Everything below matches the code in the release tarball.

Quick start

$ npm install -g https://github.com/patchprojectx/patch/releases/download/v0.1.0/patchnow-0.1.0.tgz
$ patchnow init            # writes patch.yml (dry run until armed: true), adds .patchnow/ to .gitignore
$ patchnow scan --fail-on kev
$ patchnow run             # scan → policy → actions (dry run)

Requires Node.js 20 or newer. The only runtime dependency is yaml.

CLI

CommandFlagsPurpose
init--dir <path> · --forceWrite a commented patch.yml and add .patchnow/ to .gitignore.
scan--dir · --format text|json|sarif · --output <file> · --include-dev · --no-runtimes · --no-epss · --fail-on kev|critical|high|any|noneReport only; never changes anything. --fail-on makes it a CI gate.
run--dir · --config <file> · --dry-run · --sarif <file> · --jsonScan, evaluate policy, execute actions. Dry run unless armed: true; --dry-run forces one. No flag can arm the policy.
watch--dir · --config · --interval 15m · --dry-runRepeat run on an interval (minimum 1m).
version · help

Exit codes: 0 ok · 1 --fail-on threshold met · 2 usage or config error · 3 an action failed

patch.yml

Unknown keys are rejected, so a typo cannot silently weaken the policy. Secrets are never stored in the file: any key ending in _env names an environment variable.

version: 1
armed: false                # nothing destructive happens until true

scan:
  paths: ["."]
  include_dev: false
  runtimes: auto            # auto | off
  epss: true
  max_depth: 4

packages: { only: [], exclude: [] }

ignore:
  - id: CVE-2020-28500       # OSV id, GHSA id or CVE
    reason: "never called with user input"   # required
    expires: 2026-12-31      # fires again after this date
    packages: [lodash]

triggers:                   # ANY entry fires; keys inside an entry are ANDed
  - kev: true
  - severity: critical       # minimum: low | moderate | high | critical
  - epss: ">0.5"

actions:                    # run in order on the findings that fired
  - pin_patch: { base: main }
  - safe_mode:
      when: { kev: true }
      provider: render_deploy_hook
      url_env: RENDER_MAINTENANCE_DEPLOY_HOOK
  - notify:
      slack: { url_env: SLACK_WEBHOOK_URL }

state: { path: .patchnow/state.json, refire_after_days: 0 }
audit: { path: .patchnow/audit.jsonl }
Trigger keyTypeMatches when
kevboolThe finding's CVE is in the CISA KEV catalog.
severitylow|moderate|high|criticalAdvisory severity is at least this level (medium is an alias for moderate).
cvss">=9.0"The CVSS v3 base score satisfies the comparison (> >= < <= ==).
epss">0.5"The highest EPSS probability among the finding's CVEs satisfies the comparison.
ecosystems[npm, PyPI, …]The finding's ecosystem is listed (case-insensitive).
packages[name, …]The package name is listed.
include_devboolfalse excludes dev dependencies.
runtimeboolRuntime findings (node, php, go) only, or never.
has_fixboolA fixed version is, or is not, published.

Any action can carry when: with the same keys to narrow it further. Dedupe key: ecosystem|package|version|advisory. After an armed run acts on a key, that key does not fire again unless refire_after_days is above 0. Dry runs record no state.

Actions

ActionOptionsBehaviour
pin_patchbranch_prefix · base · remote · push · open_pr · draft · labels · token_env · repo · allow_dirty · author_name · author_emailRaises each package to the smallest version that clears every fired advisory. For npm: npm install pkg@X --package-lock-only --ignore-scripts for direct dependencies, and overrides for transitive ones. Also edits requirements.txt pins and uses pnpm, go, cargo or composer when installed. Verifies by re-parsing the lockfile (npm: also npm ls), then commits on patchnow/<date>-<hash>, pushes, and opens a pull request through the GitHub REST API. Refuses to run on a dirty working tree.
safe_modeprovider · url_env · secret_env · method · token_env · project_id · deployment_id · team_idrender_deploy_hook POSTs a Render deploy hook. vercel_promote calls POST /v10/projects/{id}/promote/{deployment}. webhook sends JSON with an optional HMAC-SHA256 X-Patchnow-Signature.
revokegithub_tokens_env · npm_token_ids · confirm · npm_binGitHub tokens go to POST /credentials/revoke (unauthenticated by design). npm tokens are revoked with npm token revoke <id>. Executes only when the policy is armed and confirm: true. Token values are never printed or logged.
notifywebhook · slack · telegram · ntfy · email · send_in_dry_runThe message includes the results of earlier actions, such as the PR link. Email uses a built-in SMTP client (implicit TLS or STARTTLS) and will not send credentials without TLS.

GitHub Action

patchprojectx/patch is a composite action (action.yml at the repository root). It runs patchnow run --sarif, keeps .patchnow/ between runs with actions/cache, and uploads SARIF to code scanning. Pin @v0.1 for the latest v0.1.x, or @v0.1.0 for an exact release.

on:
  schedule: [{ cron: "*/15 * * * *" }]
  workflow_dispatch:
permissions: { contents: write, pull-requests: write, security-events: write }
jobs:
  patchnow:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: patchprojectx/patch@v0.1
        with: { config: patch.yml }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

Inputs: config · working-directory · dry-run · sarif · upload-sarif · github-token · persist-state

Supported files

FileEcosystemNotes
package-lock.json v1–3, npm-shrinkwrap.jsonnpmExact versions; dev respected.
pnpm-lock.yaml v5, v6, v9npmCLI only.
yarn.locknpmClassic v1 and Berry (Berry: CLI only).
package.jsonnpmUsed only without a lockfile. Takes the lowest version each range allows, so results are approximate.
composer.lockPackagistdev-* branches skipped.
requirements.txt · poetry.lockPyPIrequirements.txt: exact == pins only.
go.mod (go.sum fallback)GoGo toolchain matched live as stdlib.
Cargo.lockcrates.ioRegistry crates only.

Security model: what leaves your machine

  • To api.osv.dev: package names, versions and ecosystems.
  • To api.first.org: CVE identifiers, for EPSS scores. Disable with scan.epss: false or --no-epss.
  • From cisa.gov: the public KEV catalog, cached locally for 6 hours.
  • Never sent: source code, file contents beyond name and version, environment variables. Secrets are referenced only by environment-variable name and redacted from error URLs.
  • Least surprise: dry run by default. Revocation needs armed: true and confirm: true. Lockfile updates run with --ignore-scripts. PATCH never merges anything; a human reviews the pull request.
  • This website: the checker sends only name and version pairs to OSV. No cookies, no analytics.

Limitations (v0.1)

  • Coverage is OSV's coverage. Matching is by package and version only; there is no reachability analysis.
  • A package.json without a lockfile, or a go.sum-only project, can over-report. Ranges in requirements.txt are skipped.
  • The minimum fixed version can still be a breaking change. Run your tests on the pull request.
  • The end-to-end test covers the npm update path. The pnpm, Go, Cargo and Composer editors call the native tools but are not covered by it. yarn.lock and poetry.lock are reported for manual update.
  • Pull requests opened with the default GITHUB_TOKEN do not trigger other workflows. Use a GitHub App or a fine-grained PAT if CI must run on them.
  • Node.js and PHP runtime checks use a hand-curated advisory table, not a live feed. Go is matched live through OSV.
  • Windows and SBOM inputs (CycloneDX, SPDX) are not supported yet.

07

Install

v0.1 Not on npm yet. Install from the GitHub release tarball, or use the GitHub Action.

Release tarballpatchnow-0.1.0.tgz
$ curl -LO https://github.com/patchprojectx/patch/releases/download/v0.1.0/patchnow-0.1.0.tgz
$ sha256sum patchnow-0.1.0.tgz
  2f6c32753ad14f482fcb3f78fa3dac0a270e31a66ae2b29b3c14845ec73a1b5a  patchnow-0.1.0.tgz
$ npm install -g ./patchnow-0.1.0.tgz
$ patchnow init && patchnow run

Download tarballRelease notes

Statusv0.1
CLI: scan, run, watch, init
working
pin_patch: npm
tested end-to-end
pin_patch: requirements.txt
unit-tested
pin_patch: pnpm, Go, Cargo, Composer
implemented, not end-to-end tested
safe_mode, revoke, notify
tested against local mock servers
GitHub Action
dry run verified in CI
npm registry
not published yet