Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog,
and this project adheres to Semantic Versioning.
1.0.0 - 2026-04-24
First public release. CVE monitoring for Magento / Adobe Commerce / Mage-OS stores: polls KEV, NVD, GHSA, and Packagist (with OSV available as an optional fifth feed), deduplicates across them, scores by CVSS + EPSS + KEV, and alerts to Slack on P0 and P1 only.
Added
CLI surface
bin/aseshebang-PHP CLI.composer.jsonbinentry installsaseoncomposer global require infinri/ase.--dry-runflag: scan and report findings without calling Slack, saving state, or writing the heartbeat.--format=<human|json>flag. JSON form emits one object to stdout with keysrun_id,magento,findings,summary,exit_code; logs stream on stderr.--since <YYYY-MM-DD>flag: backfill from a specific date (first run only).--test-slackand--test-alertflags for verifying webhook wiring without waiting for a real CVE.- Severity-based exit codes:
0= no P0/P1 in alertable set,1= P1 present,2= P0 present or fatal config error. Applies under--dry-runas well.
Feeds and matching
- Five-feed support: CISA KEV, NVD v2.0, GitHub Security Advisories, Packagist, and OSV (opt-in).
ENABLED_FEEDSenv var with defaultkev,nvd,ghsa,packagist. Addosvto enable OSV.- OSV implementation issues a single
POST https://api.osv.dev/v1/querybatchpopulated from the installed packages, then hydrates each returned advisory viaGET /v1/vulns/{id}. - NVD CPE-prefix filtering uses
virtualMatchStringso prefix forms (cpe:2.3:a:adobe:commerce,cpe:2.3:a:magento:magento) match correctly. - EPSS enrichment after dedup, batches of 100 CVEs per request.
- Magento edition detection from
composer.lock(magento/product-community-edition,magento/product-enterprise-edition,mage-os/product-community-edition). Edition + version surface in logs and--format=jsonoutput. - Auto-detection of ecosystem filters from
composer.lock:ComposerLockAnalyzer::detectVendors(),detectEcosystems(),detectCpePrefix(),getInstalledPackages(). Env values are additive forECOSYSTEMS/VENDOR_FILTERand override-when-set forNVD_CPE_PREFIX. COMPOSER_LOCK_PATHis optional. When set, enables Magento-aware filtering. When unset, ASE runs in project-agnostic mode (feeds still poll; composer-ecosystem filtering disabled with a one-line WARN at run start).
Scoring and notification
- Two-tier priority system, P0 + P1 only. Anything below P1 is dropped before notification or persistence.
- Two-webhook model:
SLACK_WEBHOOK_URL(P0; required for normal runs) +SLACK_WEBHOOK_P1(P1; optional, silently skipped with one warning per run when unset). - 1.5s throttle between Slack messages so backfills don't drown the channel.
- Silent first-run import: every existing vulnerability is marked notified at its current priority on the first run; no Slack pings until subsequent runs detect new findings or escalations.
- Slack alerts include a Packagist remediation button linking to
https://packagist.org/packages/{vendor}/{name}for composer-ecosystem findings.
State and ops
- Atomic JSON state persistence via
StateManager(temp file + rename). State is the only reason ASE doesn't re-alert on the same CVE every run. StateManager::load()silently prunes legacy state entries with priorities outside{P0, P1}and logs the count.- Heartbeat file written on every successful run.
bin/heartbeat.shalerts via syslog if the last success was >24h ago. - Per-feed health tracking with consecutive-failure counts; 3+ failures logs ERROR.
LOG_FILE_LEVELenv var (defaultINFO) controls the rotating file log's minimum level independently of stderr. Set toDEBUGfor troubleshooting captures.Ase::pollFeeds()emits one INFO"Feed poll complete"line per feed carryingduration_ms.
Observability and security
SecretRedactor+ monolog processor that masks Slack webhook URLs, GitHub tokens (ghp_/gho_/ghu_/ghs_/ghr_/github_pat_), Bearer tokens, URL basic-auth credentials, and registered exact-match secrets (NVD API key, Slack webhook, GitHub token) in all log output.CorrelationId::generate()produces a UUIDv4 per run;CorrelationIdProcessorinjectsrun_idinto every log record and populatesRunResult->runId.- stderr handler uses Monolog's
JsonFormatter(one JSON object per line). The rotating file handler keeps the human-readableLineFormatter. #[\SensitiveParameter]attribute onCurlClient::{get,post,request,execute}$headersparams so API keys cannot leak into stack traces.
Types and tests
RunResultDTO returned fromAse::run(bool $dryRun = false)carrying exit code, alertable findings, escalations, detected Magento edition, dry-run flag, and run id.MagentoEditionDTO for detected edition info.VulnerabilityandAffectedPackagevalue objects (immutable, serializable).Priorityenum (P0, P1).~238unit tests covering feeds, dedup, priority scoring, state, redaction, correlation-id wiring, P0/P1 webhook routing, OSV querybatch shape, NVD URL shape,Config::logFileLevel(),ComposerLockAnalyzer::getInstalledPackages(), and Packagist-readiness (tests/Unit/DistributionTest).
Packaging
- MIT
LICENSE,SECURITY.md,CHANGELOG.md. composer.jsondeclaresext-curl,ext-json,ext-mbstring,ext-opensslinrequiresocomposer installfails fast on machines lacking them.
Fixed
- NVD feed returned HTTP 404 against
cpe:2.3:a:adobe:commerce/cpe:2.3:a:magento:magentobecausecpeNamerequires an exact NVD-dictionary entry; prefix matching now usesvirtualMatchString. Verified live across six query-shape variants. - OSV feed returned HTTP 400 "Invalid query." because
POST /v1/querywith{ecosystem: "Packagist"}is malformed; the endpoint requirespackageorcommit. Now uses/v1/querybatchwith one query per installed package. bin/ase --test-alertSlack card was missing CVSS for CVE-2024-34102 because the inline extraction only acceptedtype=Primary; the CVE has only aSecondarymetric (sourcepsirt@adobe.com, score 9.8). Now falls back to the first available metric when no Primary entry exists.composer.lockwalk-up discovery silently scanned ASE's own lockfile (36 packages) whenbin/asewas invoked from the project directory, even withCOMPOSER_LOCK_PATHset explicitly to the real Magento lockfile (828 packages). Walk-up removed; env value is now authoritative.- NVD 404 caused by whitespace-corrupted API keys -- handled by env-trim in
Config::getOptional(). - NVD 404 error message broadened to mention both
NVD_API_KEYandNVD_CPE_PREFIXas likely causes (was attributing 404s to API key alone).