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.
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.
Rejected records excluded. Current year shown year-to-date with a linear projection.
| Period | TTE | |
|---|---|---|
| 2018–2019 | 63 days | |
| 2020 – early 2021 | 44 days | |
| 2021–2022 | 32 days | |
| 2023 | 5 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.
-
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
-
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
-
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
-
Patch update
Oracle Critical Patch Update, October 2026
1,295 security patches across Oracle product families.
-
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.
| Added | CVE | Vendor · product | Vulnerability | Due | Ransomware |
|---|---|---|---|---|---|
| Loading… | |||||
| Published | CVE | CVSS | KEV | Summary |
|---|---|---|---|---|
| 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
| Severity | Package | Version | Advisories | KEV | Upgrade to |
|---|
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.
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
| Command | Flags | Purpose |
|---|---|---|
| init | --dir <path> · --force | Write 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|none | Report only; never changes anything. --fail-on makes it a CI gate. |
| run | --dir · --config <file> · --dry-run · --sarif <file> · --json | Scan, 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-run | Repeat 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 key | Type | Matches when |
|---|---|---|
| kev | bool | The finding's CVE is in the CISA KEV catalog. |
| severity | low|moderate|high|critical | Advisory 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_dev | bool | false excludes dev dependencies. |
| runtime | bool | Runtime findings (node, php, go) only, or never. |
| has_fix | bool | A 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
| Action | Options | Behaviour |
|---|---|---|
| pin_patch | branch_prefix · base · remote · push · open_pr · draft · labels · token_env · repo · allow_dirty · author_name · author_email | Raises 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_mode | provider · url_env · secret_env · method · token_env · project_id · deployment_id · team_id | render_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. |
| revoke | github_tokens_env · npm_token_ids · confirm · npm_bin | GitHub 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. |
| notify | webhook · slack · telegram · ntfy · email · send_in_dry_run | The 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
| File | Ecosystem | Notes |
|---|---|---|
| package-lock.json v1–3, npm-shrinkwrap.json | npm | Exact versions; dev respected. |
| pnpm-lock.yaml v5, v6, v9 | npm | CLI only. |
| yarn.lock | npm | Classic v1 and Berry (Berry: CLI only). |
| package.json | npm | Used only without a lockfile. Takes the lowest version each range allows, so results are approximate. |
| composer.lock | Packagist | dev-* branches skipped. |
| requirements.txt · poetry.lock | PyPI | requirements.txt: exact == pins only. |
| go.mod (go.sum fallback) | Go | Go toolchain matched live as stdlib. |
| Cargo.lock | crates.io | Registry 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: falseor--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: trueandconfirm: 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.jsonwithout a lockfile, or ago.sum-only project, can over-report. Ranges inrequirements.txtare 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.lockandpoetry.lockare reported for manual update. - Pull requests opened with the default
GITHUB_TOKENdo 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.
$ 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
- 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
