Servidor MCP

NPMScan

io.github.salemalem/npmscan
Herramientas para desarrolladores Seguridad Público y accesible MCP 2025-11-25

Qué hace este MCP

Scans npm packages and dependency trees for vulnerabilities, malicious install behavior, license issues, maintainer risks, provenance concerns, and remediation priorities.

analyze_install_script
Analyze an npm package install script
Statically scans a package's preinstall/install/postinstall/prepare lifecycle scripts AND the file(s) they reference — fetched directly from the published tarball, not just the command string in package.json — against npmscan's documented red-flags rubric (/docs/red-flags): child_process use, network calls, access to sensitive paths/env (.ssh, .aws, .npmrc, *TOKEN/*KEY), obfuscation, remote binaries hosted off trusted CDNs, writes to HOME, Discord/Telegram/Pastebin exfil endpoints, eval on decoded strings, chmod+exec of downloaded binaries, and CI-metadata telemetry — plus a possibleTyposquatOf name check. Returns a weighted totalScore and riskTier ('none'/'low'/'moderate'/'high'/'critical'). This is a heuristic static scan, not proof of malice or a guarantee of safety: it doesn't execute any code, can't see behavior gated on runtime conditions, and does NOT check maintainer/ownership history (a separate red-flags signal this tool doesn't cover). Use get_package/get_package_version first for the raw script listing; use this when you need to know what an install script actually does, not just that one exists.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['name'], 'properties': {'name': {'type': 'string', 'maxLength': 214, 'minLength': 1, 'description': 'Exact npm package name, e.g. "lodash" or "@scope/name"'}, 'version': {'type': 'string', 'maxLength': 128, 'minLength': 1, 'description': 'Exact version to analyze; omit to use the latest published version'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['name', 'version', 'npmscanUrl', 'hasLifecycleScripts', 'lifecycleScripts', 'filesScanned', 'scanNote', 'possibleTyposquatOf', 'findings', 'totalScore', 'riskTier'], 'properties': {'name': {'type': 'string'}, 'version': {'type': 'string'}, 'findings': {'type': 'array', 'items': {'type': 'object', 'required': ['rule', 'text', 'points', 'note', 'locations'], 'properties': {'note': {'type': 'string'}, 'rule': {'type': 'string'}, 'text': {'type': 'string'}, 'points': {'type': 'number'}, 'locations': {'type': 'array', 'items': {'type': 'object', 'required': ['file', 'snippet'], 'properties': {'file': {'type': 'string'}, 'snippet': {'type': 'string'}}, 'additionalProperties': False}}}, 'additionalProperties': False}}, 'riskTier': {'enum': ['none', 'low', 'moderate', 'high', 'critical'], 'type': 'string'}, 'scanNote': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'totalScore': {'type': 'number'}, 'filesScanned': {'type': 'array', 'items': {'type': 'string'}}, 'lifecycleScripts': {'type': 'object', 'additionalProperties': {'type': 'string'}}, 'hasLifecycleScripts': {'type': 'boolean'}, 'possibleTyposquatOf': {'anyOf': [{'type': 'object', 'required': ['name', 'rank'], 'properties': {'name': {'type': 'string'}, 'rank': {'type': 'number'}}, 'additionalProperties': False}, {'type': 'null'}]}}, 'additionalProperties': False}
analyze_transitive_dependencies
Analyze transitive dependencies for vulnerabilities
Recursively resolves one or more direct/root packages' dependency graphs — e.g. the "dependencies" section of a package.json — up to maxDepth levels deep (default 2, max 3) and batch-checks every resolved package@version against OSV.dev, so vulnerabilities buried several levels down (which would never show up from checking direct dependencies alone) still surface. `summary` is a one-sentence, deterministic recap (packages scanned, unresolved count, vulnerable count and which roots pulled them in) — read it first. The `vulnerablePaths` field directly answers "which of my dependencies pulled this in" by naming the root package(s) responsible for each vulnerable transitive package; `nodes` has the full resolved graph (depth, parents, resolutionError) for deeper inspection. An npm alias (e.g. `"totally-safe": "npm:minimist@0.0.8"`) is followed to its real target — `actualName` names the real package that vulnerability data attaches to (`name` stays the declared/alias key) — this is NOT silently skipped, since doing so would mean a vulnerable package hides behind whatever name a project calls it. A node with `resolutionError` set (unsatisfiable range, 404, or a git/file/workspace/URL specifier — those still aren't followed, only npm: aliases are) has `isVulnerable: null`, not `false` — it was never actually scanned, so "not vulnerable" would be a fabricated clean bill of health; only trust `isVulnerable: true`/`false` once a real version was resolved and checked. Scope/limits worth knowing before trusting a "clean" result: only the "dependencies" field is followed (not devDependencies/peerDependencies/optionalDependencies); each range is resolved independently per branch via semver max-satisfying against published versions — this does NOT emulate npm/yarn's actual node_modules hoisting/dedup, so read results as "which vulnerable versions are reachable in the graph," not the exact installed layout; and the whole traversal is capped at a total node budget — check `truncated`/`truncationNote` rather than assuming a large graph was scanned exhaustively. Prefer batch_query_vulnerabilities instead when you only need to check exact packages you already have a flat list for (faster, no graph walk).
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['packages'], 'properties': {'maxDepth': {'type': 'integer', 'maximum': 3, 'minimum': 0, 'description': 'How many levels of transitive dependencies to expand beyond the given root packages (0 = only check the roots themselves). Default 2, capped at 3 to bound registry calls and stay within the request timeout.'}, 'packages': {'type': 'array', 'items': {'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string', 'maxLength': 214, 'minLength': 1}, 'version': {'type': 'string', 'maxLength': 128}}, 'additionalProperties': False}, 'maxItems': 15, 'minItems': 1, 'description': '1-15 direct/root packages to expand from, e.g. a package.json\'s "dependencies". version accepts an exact version or a semver range like "^4.17.21"; omitted = latest.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['summary', 'roots', 'maxDepth', 'nodes', 'vulnerablePaths', 'totalPackagesScanned', 'unresolvedCount', 'vulnerablePackageCount', 'totalVulnerabilities', 'truncated', 'truncationNote', 'enrichmentNote'], 'properties': {'nodes': {'type': 'array', 'items': {'type': 'object', 'required': ['name', 'actualName', 'version', 'depth', 'isRoot', 'rootPackages', 'parents', 'npmscanUrl', 'resolutionError', 'isVulnerable', 'highestSeverity', 'vulnerabilities'], 'properties': {'name': {'type': 'string'}, 'depth': {'type': 'number'}, 'isRoot': {'type': 'boolean'}, 'parents': {'type': 'array', 'items': {'type': 'string'}}, 'version': {'type': ['string', 'null']}, 'actualName': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'isVulnerable': {'type': ['boolean', 'null']}, 'rootPackages': {'type': 'array', 'items': {'type': 'string'}}, 'highestSeverity': {'type': ['string', 'null']}, 'resolutionError': {'type': ['string', 'null']}, 'vulnerabilities': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'summary', 'severity', 'aliases', 'publishedAt', 'fixedVersion', 'npmscanUrl'], 'properties': {'id': {'type': 'string'}, 'aliases': {'type': 'array', 'items': {'type': 'string'}}, 'summary': {'type': ['string', 'null']}, 'severity': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'publishedAt': {'type': ['string', 'null']}, 'fixedVersion': {'type': ['string', 'null']}}, 'additionalProperties': False}}}, 'additionalProperties': False}}, 'roots': {'type': 'array', 'items': {'type': 'object', 'required': ['name', 'requestedVersion'], 'properties': {'name': {'type': 'string'}, 'requestedVersion': {'type': ['string', 'null']}}, 'additionalProperties': False}}, 'summary': {'type': 'string'}, 'maxDepth': {'type': 'number'}, 'truncated': {'type': 'boolean'}, 'enrichmentNote': {'type': ['string', 'null']}, 'truncationNote': {'type': ['string', 'null']}, 'unresolvedCount': {'type': 'number'}, 'vulnerablePaths': {'type': 'array', 'items': {'type': 'object', 'required': ['name', 'version', 'highestSeverity', 'vulnerabilityCount', 'pulledInBy', 'npmscanUrl'], 'properties': {'name': {'type': 'string'}, 'version': {'type': 'string'}, 'npmscanUrl': {'type': 'string'}, 'pulledInBy': {'type': 'array', 'items': {'type': 'string'}}, 'highestSeverity': {'type': ['string', 'null']}, 'vulnerabilityCount': {'type': 'number'}}, 'additionalProperties': False}}, 'totalPackagesScanned': {'type': 'number'}, 'totalVulnerabilities': {'type': 'number'}, 'vulnerablePackageCount': {'type': 'number'}}, 'additionalProperties': False}
audit_github_repository
Audit a GitHub repository's npm dependencies
Given a GitHub repository URL, fetches its package.json (and, if present, a pnpm-lock.yaml/package-lock.json/yarn.lock — first one found wins, in that priority order) straight from the repo's default branch and runs the same vulnerability, license-compliance, install-script, and ownership-risk pipelines batch_query_vulnerabilities/check_license_compliance/analyze_install_script/check_maintainer_changes/check_package_provenance expose individually, in one call — no copy-pasting file contents required. A monorepo (package.json#workspaces, Yarn's {packages:[...]} form, or pnpm-workspace.yaml) is detected automatically: pnpm-lock.yaml and yarn.lock already record every workspace member's dependencies directly, and for package.json-only or package-lock.json repos this additionally lists the repo's file tree, resolves the declared glob patterns to member directories, and merges each member's dependencies into the audit (capped at 50 member packages) — see isMonorepo/workspacePatterns/workspacePackageCount/workspaceNote in the result. Every direct dependency (up to 100 per call, across the root and any merged workspace members) gets: an OSV.dev vulnerability check, a license-compliance verdict against the given policy (same default as check_license_compliance: only copyleft/network-copyleft/proprietary are violations unless you pass one), and a tarball-free install-script risk signal (installScriptScanScope: 'lifecycle-scripts-only'). Up to 10 of the packages that actually declare a lifecycle script — prioritized by already-vulnerable, then possible-typosquat, then whatever's left — additionally get the full tarball-fetching deep scan analyze_install_script itself runs (installScriptScanScope: 'deep-tarball-scan', with a populated installScriptFindings array); any remaining flagged packages past that cap keep the lighter signal only, noted in deepScanNote. Any package that comes back vulnerable at high/critical severity, a possible typosquat, or deprecated (ownershipRiskEligible) additionally gets check_maintainer_changes and check_package_provenance run against it — up to 5 such packages per call (ownershipRiskChecked), prioritized the same way as the deep install-script scan, populating maintainerRiskTier/maintainerFindings and provenanceRiskTier/provenanceFindings; remaining eligible packages past that cap are named in ownershipCheckNote. This is the most expensive tool in the suite (a repo lookup, a handful of file fetches, up to 100 registry doc fetches, one OSV batch call, up to 10 tarball fetches, up to 5 packages each getting a maintainer-history check plus a provenance check — the latter alone can fan out to ~8 more registry fetches on its own — and, for a monorepo needing enumeration, one file-tree listing plus up to 50 more manifest fetches) — don't call it in a loop across many repos. `peerDependencies` (root and, for a monorepo, each workspace member's own manifest) are excluded from the audit by default, same as batch_query_vulnerabilities — pass `includePeerDependencies: true` to also check them; see `warnings` for which peers were excluded.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['url'], 'properties': {'ref': {'type': 'string', 'maxLength': 250, 'minLength': 1, 'description': "Branch, tag, or commit SHA to audit. Omit to use the repository's default branch."}, 'url': {'type': 'string', 'maxLength': 500, 'minLength': 1, 'description': 'GitHub repository URL, e.g. "https://github.com/owner/repo".'}, 'policy': {'type': 'object', 'properties': {'deny': {'type': 'array', 'items': {'type': 'string', 'maxLength': 100, 'minLength': 1}, 'maxItems': 50, 'description': 'SPDX ids, family prefixes, or category names. Always takes precedence over allow.'}, 'allow': {'type': 'array', 'items': {'type': 'string', 'maxLength': 100, 'minLength': 1}, 'maxItems': 50, 'description': 'SPDX ids, family prefixes (e.g. "GPL"), or category names. Anything not matching is a violation.'}}, 'description': 'License allow/deny policy, same shape as check_license_compliance. Omit for the default policy (only copyleft/network-copyleft/proprietary are violations).', 'additionalProperties': False}, 'includeDevDependencies': {'type': 'boolean', 'description': 'Include package.json devDependencies in the audit. Default false. Ignored when a lockfile is used instead (its own format decides direct-dependency scope), and yarn.lock can never distinguish dev from production dependencies regardless of this flag.'}, 'includePeerDependencies': {'type': 'boolean', 'description': 'Include package.json peerDependencies (root and, for a monorepo, each workspace member) in the audit. Default false â\x80\x94 a peer is often intentionally left unresolved by the consumer. See warnings for which peers were excluded.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['summary', 'owner', 'repoName', 'ref', 'defaultBranchUsed', 'manifestPath', 'lockfilePath', 'inputFormat', 'isMonorepo', 'workspacePatterns', 'workspacePackageCount', 'workspaceNote', 'policy', 'findings', 'overflowPackages', 'totalPackages', 'vulnerablePackageCount', 'licenseViolationCount', 'installScriptFlaggedCount', 'deepScannedCount', 'ownershipCheckedCount', 'ownershipRiskFlaggedCount', 'warnings', 'truncationNote', 'deepScanNote', 'ownershipCheckNote'], 'properties': {'ref': {'type': 'string'}, 'owner': {'type': 'string'}, 'policy': {'type': 'object', 'required': ['mode', 'allow', 'deny'], 'properties': {'deny': {'type': 'array', 'items': {'type': 'string'}}, 'mode': {'enum': ['default', 'allow', 'deny', 'allow+deny'], 'type': 'string'}, 'allow': {'type': 'array', 'items': {'type': 'string'}}}, 'additionalProperties': False}, 'summary': {'type': 'string'}, 'findings': {'type': 'array', 'items': {'type': 'object', 'required': ['name', 'requestedVersion', 'resolvedVersion', 'npmscanUrl', 'deprecated', 'possibleTyposquatOf', 'isVulnerable', 'highestSeverity', 'vulnerabilities', 'rawLicense', 'licenseCategory', 'isLicenseCompliant', 'licenseNeedsReview', 'licenseViolation', 'hasLifecycleScripts', 'installScriptRiskTier', 'installScriptScore', 'installScriptScanScope', 'installScriptFindings', 'resolutionError', 'ownershipRiskEligible', 'ownershipRiskReason', 'ownershipRiskChecked', 'maintainerRiskTier', 'maintainerFindings', 'provenanceRiskTier', 'provenanceFindings'], 'properties': {'name': {'type': 'string'}, 'deprecated': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'rawLicense': {'type': ['string', 'null']}, 'isVulnerable': {'type': ['boolean', 'null']}, 'highestSeverity': {'type': ['string', 'null']}, 'licenseCategory': {'enum': ['permissive', 'weak-copyleft', 'copyleft', 'network-copyleft', 'proprietary', 'public-domain', 'unknown', 'mixed'], 'type': 'string'}, 'resolutionError': {'type': ['string', 'null']}, 'resolvedVersion': {'type': ['string', 'null']}, 'vulnerabilities': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'summary', 'severity', 'aliases', 'publishedAt', 'fixedVersion', 'npmscanUrl'], 'properties': {'id': {'type': 'string'}, 'aliases': {'type': 'array', 'items': {'type': 'string'}}, 'summary': {'type': ['string', 'null']}, 'severity': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'publishedAt': {'type': ['string', 'null']}, 'fixedVersion': {'type': ['string', 'null']}}, 'additionalProperties': False}}, 'licenseViolation': {'anyOf': [{'type': 'object', 'required': ['rule', 'text', 'note'], 'properties': {'note': {'type': 'string'}, 'rule': {'type': 'string'}, 'text': {'type': 'string'}}, 'additionalProperties': False}, {'type': 'null'}]}, 'requestedVersion': {'type': ['string', 'null']}, 'installScriptScore': {'type': ['number', 'null']}, 'isLicenseCompliant': {'type': ['boolean', 'null']}, 'licenseNeedsReview': {'type': 'boolean'}, 'maintainerFindings': {'anyOf': [{'type': 'array', 'items': {'$ref': '#/properties/findings/items/properties/installScriptFindings/anyOf/0/items'}}, {'type': 'null'}]}, 'maintainerRiskTier': {'anyOf': [{'$ref': '#/properties/findings/items/properties/installScriptRiskTier/anyOf/0'}, {'type': 'null'}]}, 'provenanceFindings': {'anyOf': [{'type': 'array', 'items': {'$ref': '#/properties/findings/items/properties/installScriptFindings/anyOf/0/items'}}, {'type': 'null'}]}, 'provenanceRiskTier': {'anyOf': [{'$ref': '#/properties/findings/items/properties/installScriptRiskTier/anyOf/0'}, {'type': 'null'}]}, 'hasLifecycleScripts': {'type': 'boolean'}, 'ownershipRiskReason': {'anyOf': [{'enum': ['critical-or-high-severity-vulnerability', 'possible-typosquat', 'deprecated'], 'type': 'string'}, {'type': 'null'}]}, 'possibleTyposquatOf': {'anyOf': [{'type': 'object', 'required': ['name', 'rank'], 'properties': {'name': {'type': 'string'}, 'rank': {'type': 'number'}}, 'additionalProperties': False}, {'type': 'null'}]}, 'ownershipRiskChecked': {'type': 'boolean'}, 'installScriptFindings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['rule', 'text', 'points', 'note', 'locations'], 'properties': {'note': {'type': 'string'}, 'rule': {'type': 'string'}, 'text': {'type': 'string'}, 'points': {'type': 'number'}, 'locations': {'type': 'array', 'items': {'type': 'object', 'required': ['file', 'snippet'], 'properties': {'file': {'type': 'string'}, 'snippet': {'type': 'string'}}, 'additionalProperties': False}}}, 'additionalProperties': False}}, {'type': 'null'}]}, 'installScriptRiskTier': {'anyOf': [{'enum': ['none', 'low', 'moderate', 'high', 'critical'], 'type': 'string'}, {'type': 'null'}]}, 'ownershipRiskEligible': {'type': 'boolean'}, 'installScriptScanScope': {'anyOf': [{'enum': ['lifecycle-scripts-only', 'deep-tarball-scan'], 'type': 'string'}, {'type': 'null'}]}}, 'additionalProperties': False}}, 'repoName': {'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'string'}}, 'isMonorepo': {'type': 'boolean'}, 'inputFormat': {'enum': ['package.json', 'npm-lock', 'yarn-lock', 'pnpm-lock'], 'type': 'string'}, 'deepScanNote': {'type': ['string', 'null']}, 'lockfilePath': {'type': ['string', 'null']}, 'manifestPath': {'type': 'string'}, 'totalPackages': {'type': 'number'}, 'workspaceNote': {'type': ['string', 'null']}, 'truncationNote': {'type': ['string', 'null']}, 'deepScannedCount': {'type': 'number'}, 'overflowPackages': {'type': 'array', 'items': {'type': 'object', 'required': ['name', 'requestedVersion'], 'properties': {'name': {'type': 'string'}, 'requestedVersion': {'type': ['string', 'null']}}, 'additionalProperties': False}}, 'defaultBranchUsed': {'type': 'boolean'}, 'workspacePatterns': {'type': 'array', 'items': {'type': 'string'}}, 'ownershipCheckNote': {'type': ['string', 'null']}, 'licenseViolationCount': {'type': 'number'}, 'ownershipCheckedCount': {'type': 'number'}, 'workspacePackageCount': {'type': 'number'}, 'vulnerablePackageCount': {'type': 'number'}, 'installScriptFlaggedCount': {'type': 'number'}, 'ownershipRiskFlaggedCount': {'type': 'number'}}, 'additionalProperties': False}
batch_query_vulnerabilities
Batch query known vulnerabilities
Query OSV.dev for known vulnerabilities across a whole npm dependency inventory at once: either pass a flat {packages:[...]} list, or paste raw package.json / lockfile / CycloneDX JSON / SPDX JSON content via `content`. The tool normalizes npm dependencies first, then chunk-queries OSV behind the scenes so large SBOMs don't stop at the upstream 100-package batch limit. Each finding includes severity, a summary, CVE aliases, and the fixed version — not just a bare advisory ID — so a dependency audit answer doesn't need a follow-up call per flagged package. For an explicit `packages` list or raw `package.json` content — names that were never actually resolved against a registry, unlike a real lockfile/SBOM — package names are also cross-checked against the npm registry (capped at 200 unique names): a name that doesn't exist there would otherwise show a silent, indistinguishable `vulnerabilityCount: 0` — see `unresolvedPackages`/`existenceCheckNote` and do not read those entries as a clean bill of health. A `packages[].version` that doesn't currently appear on the registry (a typo'd/fabricated version, OR a real version that was published and later removed, e.g. unpublished for containing malware) is cross-checked the same way — see `nonexistentVersions`; don't assume it never existed, and don't assume `vulnerabilityCount:0` for it means clean, since OSV can still carry findings for a version the registry no longer lists. A `packages[]` entry given with NO version at all (e.g. `{name:"react"}`) is intentionally queried unversioned against OSV — this returns advisories affecting ANY historical published version of that package, not just the latest or whatever a project actually has installed; see the corresponding `warnings` entry naming which packages this applied to, and don't report "package X is vulnerable" from an unversioned result without separately confirming against the specific version in use (get_package/get_package_version). Each result also carries `signals` (deprecated, hasInstallScripts for the specific requested/resolved version, popularityTier/maintenanceTier, and possibleTyposquatOf — same deterministic rule-based labels as get_package/search_packages, capped at the same 200 unique names): a clean `vulnerabilityCount:0` does NOT mean safe to use if `signals` flags a likely typosquat, an abandoned/stale package, or a deprecation notice — surface those explicitly rather than reporting only the vulnerability count. `signals` is `null` for a `scanStatus: "not-scanned"` entry, deliberately — a git/file/workspace/URL dependency can be declared under a name that collides with a real npm package (e.g. a git dependency literally named "lodash"), and that unrelated public package's popularity/maintenance signals must not be attached to it just because the name happens to resolve on the registry. A lockfile-resolved result also carries `source` (resolvedUrl/integrity straight from that lockfile entry, plus `nonRegistryHost`): `nonRegistryHost: true` means the tarball URL points somewhere other than the expected npm/yarn registry host — e.g. a compromised mirror or a hand-edited lockfile — which a name+version match against OSV cannot detect on its own, since a malicious tarball can share the same name/version as the real package and carry zero OSV findings. `source` is `null` when the input format doesn't record this (package.json content, an explicit `packages` entry, or pnpm-lock, which never records a resolvedUrl). `nonRegistryHost: false` alone is NOT proof the tarball is correct — `source.identityMismatch: true` catches a SAME-HOST swap that host-checking cannot: a lockfile entry can declare e.g. "lodash@4.18.1" while resolvedUrl actually points at the real registry.npmjs.org's own tarball for a completely different package/version, and `vulnerabilityCount` above was still computed for the DECLARED name/version, not whatever that resolved tarball actually is — treat `identityMismatch: true` as a lockfile-tamper finding, not a cosmetic mismatch, and see `source.resolvedName`/`resolvedVersion` for what the tarball actually names. `vulnerabilityCount`/`advisoryCount` are raw OSV/GHSA advisory counts and can over-count: OSV sometimes publishes more than one advisory record for the same underlying CVE — use `uniqueVulnerabilityCount` (deduped by shared CVE alias) when reporting 'how many distinct issues' rather than a raw advisory tally. When `content` is itself a package.json (not a lockfile/SBOM), `projectLifecycleScripts` surfaces that SCANNED PROJECT's own preinstall/install/postinstall/prepare scripts, if any — these run arbitrary code the moment someone runs `npm install` on the project itself, separate from anything a dependency does, and 'scan my package.json' should not silently skip the one script that actually executes for the project being scanned. An npm alias (e.g. `"totally-safe": "npm:minimist@0.0.8"`) is followed to its real target in every input format — `results[i].package.actualName` names the real package that vulnerability/signal data attaches to (`.name` stays the declared/alias key); this is NOT silently skipped, since doing so would let a vulnerable package hide behind whatever name a project calls it. A dependency whose spec points somewhere other than the registry (git/file/workspace/URL) or that never resolved to a version is excluded from vulnerability querying entirely rather than queried by name alone — `vulnerabilityCount: 0` for one of these would otherwise misleadingly attach an unrelated public npm package's entire vulnerability history to it. When `content` is a package.json, `peerDependencies` are excluded from scanning by default (a peer is often intentionally left unresolved by the consumer) — see `ignoredPeerDependencyNames`, and pass `includePeerDependencies: true` to also check them, since a vulnerable/malicious peerDependency is otherwise invisible to this scan. `results[i].package.declaredSpec` is set whenever `.version` was RESOLVED from a package.json semver range/tag (e.g. `"^18.2.0"` -> `"18.2.0"`) rather than being an already-exact pin or a lockfile-derived version — a range can silently pick up a new, possibly-compromised release the next time this project is installed, while an exact pin can't, so don't treat a range-resolved `isVulnerable:false` as equally durable to a pinned one just because they look identical today.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'properties': {'content': {'type': 'string', 'minLength': 1, 'description': 'Raw dependency inventory content: package.json, package-lock.json, yarn.lock, pnpm-lock.yaml, CycloneDX JSON, or SPDX JSON. Use this OR `packages`, not both.'}, 'packages': {'type': 'array', 'items': {'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string', 'maxLength': 214, 'minLength': 1}, 'version': {'type': 'string', 'maxLength': 128, 'description': 'One exact published version, e.g. "18.2.0" (not a range/tag like "^18.2.0" or "latest" â\x80\x94 those are resolved against the registry first, at the cost of an extra lookup, rather than rejected)'}}, 'additionalProperties': False}, 'maxItems': 1000, 'minItems': 1, 'description': 'Explicit package list (1-1000 items). Use this OR `content`, not both.'}, 'includeDevDependencies': {'type': 'boolean', 'description': 'Ignored when using `packages`; only applies when `content` is a manifest/lockfile format that distinguishes dev dependencies.'}, 'includePeerDependencies': {'type': 'boolean', 'description': 'Ignored when using `packages`; only applies when `content` is a package.json. peerDependencies are excluded from scanning by default (see ignoredPeerDependencyNames) since a peer is often intentionally left unresolved by the consumer â\x80\x94 set this to also check them.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['results', 'totalVulnerabilities', 'totalUniqueVulnerabilities', 'packagesWithVulnerabilities'], 'properties': {'results': {'type': 'array', 'items': {'type': 'object', 'required': ['package', 'npmscanUrl', 'scanStatus', 'vulnerabilityCount', 'advisoryCount', 'uniqueVulnerabilityCount', 'vulnerabilities', 'signals', 'source'], 'properties': {'source': {'anyOf': [{'type': 'object', 'required': ['resolvedUrl', 'integrity', 'nonRegistryHost', 'identityMismatch', 'resolvedName', 'resolvedVersion'], 'properties': {'integrity': {'type': ['string', 'null']}, 'resolvedUrl': {'type': ['string', 'null']}, 'resolvedName': {'type': ['string', 'null']}, 'nonRegistryHost': {'type': ['boolean', 'null']}, 'resolvedVersion': {'type': ['string', 'null']}, 'identityMismatch': {'type': ['boolean', 'null']}}, 'additionalProperties': False}, {'type': 'null'}]}, 'package': {'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string'}, 'version': {'type': 'string'}, 'actualName': {'type': 'string'}, 'declaredSpec': {'type': 'string'}}, 'additionalProperties': False}, 'signals': {'anyOf': [{'type': 'object', 'required': ['deprecated', 'hasInstallScripts', 'popularityTier', 'maintenanceTier', 'possibleTyposquatOf'], 'properties': {'deprecated': {'type': ['string', 'null']}, 'popularityTier': {'enum': ['very-high', 'high', 'moderate', 'low', 'very-low', 'unknown'], 'type': 'string'}, 'maintenanceTier': {'enum': ['active', 'aging', 'stale', 'unknown'], 'type': 'string'}, 'hasInstallScripts': {'type': ['boolean', 'null']}, 'possibleTyposquatOf': {'anyOf': [{'type': 'object', 'required': ['name', 'rank'], 'properties': {'name': {'type': 'string'}, 'rank': {'type': 'number'}}, 'additionalProperties': False}, {'type': 'null'}]}}, 'additionalProperties': False}, {'type': 'null'}]}, 'npmscanUrl': {'type': 'string'}, 'scanStatus': {'enum': ['scanned', 'not-scanned'], 'type': 'string'}, 'advisoryCount': {'type': 'number'}, 'vulnerabilities': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'summary', 'severity', 'aliases', 'publishedAt', 'fixedVersion', 'npmscanUrl'], 'properties': {'id': {'type': 'string'}, 'aliases': {'type': 'array', 'items': {'type': 'string'}}, 'summary': {'type': ['string', 'null']}, 'severity': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'publishedAt': {'type': ['string', 'null']}, 'fixedVersion': {'type': ['string', 'null']}}, 'additionalProperties': False}}, 'vulnerabilityCount': {'type': 'number'}, 'uniqueVulnerabilityCount': {'type': 'number'}}, 'additionalProperties': False}}, 'warnings': {'type': 'array', 'items': {'type': 'string'}}, 'inputFormat': {'type': 'string'}, 'ignoredCount': {'type': 'number'}, 'enrichmentNote': {'type': 'string'}, 'queryFailureCount': {'type': 'number'}, 'existenceCheckNote': {'type': 'string'}, 'parsedPackageCount': {'type': 'number'}, 'unresolvedPackages': {'type': 'array', 'items': {'type': 'string'}}, 'nonexistentVersions': {'type': 'array', 'items': {'type': 'string'}}, 'totalVulnerabilities': {'type': 'number'}, 'projectLifecycleScripts': {'anyOf': [{'type': 'object', 'additionalProperties': {'type': 'string'}}, {'type': 'null'}]}, 'ignoredPeerDependencyNames': {'type': 'array', 'items': {'type': 'string'}}, 'projectLifecycleScriptRisk': {'type': 'object', 'required': ['hasLifecycleScripts', 'riskTier', 'totalScore'], 'properties': {'riskTier': {'enum': ['none', 'low', 'moderate', 'high', 'critical'], 'type': 'string'}, 'totalScore': {'type': 'number'}, 'hasLifecycleScripts': {'type': 'boolean'}}, 'additionalProperties': False}, 'totalUniqueVulnerabilities': {'type': 'number'}, 'packagesWithVulnerabilities': {'type': 'number'}}, 'additionalProperties': False}
check_license_compliance
Check a dependency list against a license policy
Given a list of packages (name + optional exact version or semver range — e.g. straight from a package.json "dependencies" object) and an optional allow/deny license policy, resolves each package's declared SPDX license and reports a compliance verdict per package. Classifies every license into one of permissive/weak-copyleft/copyleft/network-copyleft/proprietary/public-domain/unknown, and understands simple SPDX expressions: "(MIT OR GPL-3.0)" is compliant if EITHER side is permitted (a consumer may legally pick the clean alternative), "MIT AND Apache-2.0" requires both sides to pass, and "X WITH exception" is judged on X. A mixed/nested expression like "(MIT OR ISC) AND Apache-2.0" is reported as needsReview rather than guessed at. `policy.deny` entries always win over `policy.allow` (so a name can appear in both without a silent contradiction); with `policy.allow` set, anything not matching it is a violation (unproven is treated as non-compliant); with neither given, the default policy flags only copyleft/network-copyleft/proprietary (e.g. GPL/AGPL/UNLICENSED) — weak-copyleft (LGPL/MPL/EPL) and unrecognized license strings are surfaced but not auto-flagged. Policy entries accept an exact SPDX id, a family prefix ("GPL" catches GPL-2.0/GPL-3.0-only/etc.), or a category name. This reads only the registry-declared `license` field — it does not fetch or parse LICENSE file contents from the source repository.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['packages'], 'properties': {'policy': {'type': 'object', 'properties': {'deny': {'type': 'array', 'items': {'type': 'string', 'maxLength': 100, 'minLength': 1}, 'maxItems': 50, 'description': 'SPDX ids, family prefixes, or category names. Always takes precedence over allow.'}, 'allow': {'type': 'array', 'items': {'type': 'string', 'maxLength': 100, 'minLength': 1}, 'maxItems': 50, 'description': 'SPDX ids, family prefixes (e.g. "GPL"), or category names. Anything not matching is a violation.'}}, 'description': 'Omit entirely to use the default policy: only copyleft/network-copyleft/proprietary are violations.', 'additionalProperties': False}, 'packages': {'type': 'array', 'items': {'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string', 'maxLength': 214, 'minLength': 1}, 'version': {'type': 'string', 'maxLength': 128}}, 'additionalProperties': False}, 'maxItems': 100, 'minItems': 1, 'description': '1-100 packages to check. version accepts an exact version or a semver range like "^4.17.21"; omitted = latest.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['policy', 'summary', 'results', 'totalPackages', 'compliantCount', 'violationCount', 'needsReviewCount', 'unresolvedCount'], 'properties': {'policy': {'type': 'object', 'required': ['mode', 'allow', 'deny'], 'properties': {'deny': {'type': 'array', 'items': {'type': 'string'}}, 'mode': {'enum': ['default', 'allow', 'deny', 'allow+deny'], 'type': 'string'}, 'allow': {'type': 'array', 'items': {'type': 'string'}}}, 'additionalProperties': False}, 'results': {'type': 'array', 'items': {'type': 'object', 'required': ['package', 'npmscanUrl', 'resolvedVersion', 'rawLicense', 'category', 'isCompliant', 'needsReview', 'violation', 'resolutionError'], 'properties': {'package': {'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string'}, 'version': {'type': 'string'}}, 'additionalProperties': False}, 'category': {'enum': ['permissive', 'weak-copyleft', 'copyleft', 'network-copyleft', 'proprietary', 'public-domain', 'unknown', 'mixed'], 'type': 'string'}, 'violation': {'anyOf': [{'type': 'object', 'required': ['rule', 'text', 'note'], 'properties': {'note': {'type': 'string'}, 'rule': {'type': 'string'}, 'text': {'type': 'string'}}, 'additionalProperties': False}, {'type': 'null'}]}, 'npmscanUrl': {'type': 'string'}, 'rawLicense': {'type': ['string', 'null']}, 'isCompliant': {'type': 'boolean'}, 'needsReview': {'type': 'boolean'}, 'resolutionError': {'type': ['string', 'null']}, 'resolvedVersion': {'type': ['string', 'null']}}, 'additionalProperties': False}}, 'summary': {'type': 'string'}, 'totalPackages': {'type': 'number'}, 'compliantCount': {'type': 'number'}, 'violationCount': {'type': 'number'}, 'unresolvedCount': {'type': 'number'}, 'needsReviewCount': {'type': 'number'}}, 'additionalProperties': False}
check_maintainer_blast_radius
Check npm maintainer blast radius
Given an npm username, lists the packages npm's maintainer:<username> search index returns for that account and looks for a tight cluster of packages whose latest version was published within a short rolling window of each other — the shape of a compromised-account supply-chain attack, where a stolen credential is used on every package the account can publish to within hours (e.g. the September 2025 chalk/debug compromise, ~18 packages in ~2 hours). A large total package count is not itself a red flag; only a tight publish-time cluster is scored, weighted by its package count and combined weekly downloads/dependentsCount. Clusters mostly within one npm scope (a monorepo release) are dampened, and multiple clusters combine with diminishing returns. isCurrentMaintainer shows whether the account still maintains each package. avatarUrl is a proxied Gravatar image (null if no email is on record). Natural follow-up to check_maintainer_changes: call this with a newly added maintainer's username to see whether the same account touched other packages around the same time. Limitations: npm's search index can lag or omit packages; results are capped at 250 packages ranked by relevance, not recency (see resultsTruncated/totalPackagesFound); lastPublished reflects only each package's latest version. npmscanUrl is the account's npmscan profile; npmProfileUrl is its npmjs.com page.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['maintainerUsername'], 'properties': {'maintainerUsername': {'type': 'string', 'maxLength': 100, 'minLength': 1, 'description': 'Exact npm username, e.g. "sindresorhus" â\x80\x94 as shown at npmjs.com/~username. Not an email address, not a package name or scope.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['maintainerUsername', 'npmscanUrl', 'npmProfileUrl', 'avatarUrl', 'totalPackagesFound', 'packagesReturned', 'resultsTruncated', 'clusterWindowHours', 'packages', 'clusters', 'findings', 'totalScore', 'riskTier', 'note'], 'properties': {'note': {'type': ['string', 'null']}, 'clusters': {'type': 'array', 'items': {'type': 'object', 'required': ['windowStart', 'windowEnd', 'packageNames', 'packageCount', 'combinedWeeklyDownloads', 'combinedDependentsCount', 'stillCurrentMaintainerCount'], 'properties': {'windowEnd': {'type': 'string'}, 'windowStart': {'type': 'string'}, 'packageCount': {'type': 'number'}, 'packageNames': {'type': 'array', 'items': {'type': 'string'}}, 'combinedDependentsCount': {'type': 'number'}, 'combinedWeeklyDownloads': {'type': 'number'}, 'stillCurrentMaintainerCount': {'type': 'number'}}, 'additionalProperties': False}}, 'findings': {'type': 'array', 'items': {'type': 'object', 'required': ['rule', 'text', 'points', 'note', 'locations'], 'properties': {'note': {'type': 'string'}, 'rule': {'type': 'string'}, 'text': {'type': 'string'}, 'points': {'type': 'number'}, 'locations': {'type': 'array', 'items': {'type': 'object', 'required': ['file', 'snippet'], 'properties': {'file': {'type': 'string'}, 'snippet': {'type': 'string'}}, 'additionalProperties': False}}}, 'additionalProperties': False}}, 'packages': {'type': 'array', 'items': {'type': 'object', 'required': ['name', 'version', 'lastPublished', 'weeklyDownloads', 'dependentsCount', 'isCurrentMaintainer', 'npmscanUrl'], 'properties': {'name': {'type': 'string'}, 'version': {'type': 'string'}, 'npmscanUrl': {'type': 'string'}, 'lastPublished': {'type': ['string', 'null']}, 'dependentsCount': {'type': ['number', 'null']}, 'weeklyDownloads': {'type': ['number', 'null']}, 'isCurrentMaintainer': {'type': 'boolean'}}, 'additionalProperties': False}}, 'riskTier': {'enum': ['none', 'low', 'moderate', 'high', 'critical'], 'type': 'string'}, 'avatarUrl': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'totalScore': {'type': 'number'}, 'npmProfileUrl': {'type': 'string'}, 'packagesReturned': {'type': 'number'}, 'resultsTruncated': {'type': 'boolean'}, 'clusterWindowHours': {'type': 'number'}, 'maintainerUsername': {'type': 'string'}, 'totalPackagesFound': {'type': 'number'}}, 'additionalProperties': False}
check_maintainer_changes
Check an npm package for maintainer/ownership red flags
Reconstructs a package's maintainer-change history straight from the npm packument — every published version carries the maintainers-list SNAPSHOT as it stood at that publish plus who actually ran `npm publish` (`_npmUser`), so diffing consecutive snapshots in publish-time order recovers exactly who was added or removed and when, with no extra API calls. Flags: (1) a maintainer added recently who then published a release shortly afterward on a package with real prior history — the account-takeover/hostile-handoff shape behind incidents like ua-parser-js, event-stream, and the 2025 chalk/debug ('qix') compromise; (2) a full, sudden replacement of the entire maintainer list; (3) a long-standing maintainer quietly dropped from the list; (4) a maintainer-list change that happened on npm's site AFTER the latest release — not yet tied to any published version, which is the more urgent case since it means access changed hands but nothing has shipped with it yet. Also cross-checks the declared GitHub repository: whether it still resolves to the same owner/name (a transfer/rename), whether it's reachable at all, and whether the latest npm release landed long after any real push activity there — repository.ownerLogin/ownerAvatarUrl name and show the CURRENT owning account (the new one after a transfer, not the one originally declared in package.json), with ownerAvatarUrl a proxied GitHub avatar image, both null whenever the repo check itself didn't reach GitHub. Use get_package/check_package_provenance first for the package's general health and publish-integrity signals; use this specifically for the 'who controls this package, and did that change recently' question. If this flags a newly added or fully turned-over maintainer, follow up with check_maintainer_blast_radius on that maintainer's username — it lists every other package the same account currently touches and flags a tight publish-time cluster across them, the 'did this compromise hit just one package or a dozen' question this tool can't answer on its own.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['name'], 'properties': {'name': {'type': 'string', 'maxLength': 214, 'minLength': 1, 'description': 'Exact npm package name, e.g. "lodash" or "@scope/name"'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['name', 'npmscanUrl', 'lookbackDays', 'currentMaintainers', 'history', 'repository', 'findings', 'totalScore', 'riskTier'], 'properties': {'name': {'type': 'string'}, 'history': {'type': 'object', 'required': ['versionsConsidered', 'firstTrackedVersion', 'latestTrackedVersion', 'latestVersionPublishedViaTrustedPublisher', 'changes', 'changesTruncated', 'note'], 'properties': {'note': {'type': ['string', 'null']}, 'changes': {'type': 'array', 'items': {'type': 'object', 'required': ['version', 'publishedAt', 'added', 'removed'], 'properties': {'added': {'type': 'array', 'items': {'type': 'string'}}, 'removed': {'type': 'array', 'items': {'type': 'string'}}, 'version': {'type': ['string', 'null']}, 'publishedAt': {'type': ['string', 'null']}}, 'additionalProperties': False}}, 'changesTruncated': {'type': 'boolean'}, 'versionsConsidered': {'type': 'number'}, 'firstTrackedVersion': {'anyOf': [{'type': 'object', 'required': ['version', 'publishedAt'], 'properties': {'version': {'type': 'string'}, 'publishedAt': {'type': 'string'}}, 'additionalProperties': False}, {'type': 'null'}]}, 'latestTrackedVersion': {'anyOf': [{'type': 'object', 'required': ['version', 'publishedAt'], 'properties': {'version': {'type': 'string'}, 'publishedAt': {'type': 'string'}}, 'additionalProperties': False}, {'type': 'null'}]}, 'latestVersionPublishedViaTrustedPublisher': {'type': 'boolean'}}, 'additionalProperties': False}, 'findings': {'type': 'array', 'items': {'type': 'object', 'required': ['rule', 'text', 'points', 'note', 'locations'], 'properties': {'note': {'type': 'string'}, 'rule': {'type': 'string'}, 'text': {'type': 'string'}, 'points': {'type': 'number'}, 'locations': {'type': 'array', 'items': {'type': 'object', 'required': ['file', 'snippet'], 'properties': {'file': {'type': 'string'}, 'snippet': {'type': 'string'}}, 'additionalProperties': False}}}, 'additionalProperties': False}}, 'riskTier': {'enum': ['none', 'low', 'moderate', 'high', 'critical'], 'type': 'string'}, 'npmscanUrl': {'type': 'string'}, 'repository': {'type': 'object', 'required': ['checked', 'declaredRepository', 'currentFullName', 'transferred', 'archived', 'reachable', 'ownerLogin', 'ownerAvatarUrl', 'note'], 'properties': {'note': {'type': ['string', 'null']}, 'checked': {'type': 'boolean'}, 'archived': {'type': ['boolean', 'null']}, 'reachable': {'type': ['boolean', 'null']}, 'ownerLogin': {'type': ['string', 'null']}, 'transferred': {'type': ['boolean', 'null']}, 'ownerAvatarUrl': {'type': ['string', 'null']}, 'currentFullName': {'type': ['string', 'null']}, 'declaredRepository': {'type': ['string', 'null']}}, 'additionalProperties': False}, 'totalScore': {'type': 'number'}, 'lookbackDays': {'type': 'number'}, 'currentMaintainers': {'type': 'array', 'items': {'type': 'object', 'required': ['name', 'email'], 'properties': {'name': {'type': 'string'}, 'email': {'type': ['string', 'null']}}, 'additionalProperties': False}}}, 'additionalProperties': False}
check_package_provenance
Check an npm package version for publish-provenance red flags
Checks whether a package version was published with npm's own Sigstore-backed publish provenance (`npm publish --provenance`), and cross-checks that provenance against reality rather than just reporting its presence. Three checks: (1) parses the SLSA build attestation (declared source repo, commit, builder identity, GitHub Actions run URL) and flags a builder that isn't GitHub-hosted, or an attested source repo that doesn't match package.json's own `repository` field; (2) when this version LACKS provenance, checks whether most peer packages (same npm scope, or same maintainer for an unscoped name) DO have it — a package that's the odd one out in an org that otherwise always publishes from CI is a real anomaly, not proof of malice; (3) fetches package.json from the source repository at the exact attested commit (or a best-effort matching git tag when no provenance/commit is available) and diffs its install-lifecycle scripts (preinstall/install/postinstall/prepare) and dependency names against what's actually in the published tarball — this is the single highest-signal check here, since a script or dependency that exists on npm but was never committed is exactly the pattern of a stolen-npm-token publish that bypasses CI (the event-stream/ua-parser-js incident shape). This is a heuristic, structural check: it does NOT cryptographically re-verify the Sigstore bundle (Fulcio cert chain, Rekor inclusion proof) — it trusts that npm's registry already refused to accept a publish that failed that verification, and checks the CONTENT of what the registry reports instead. Most packages don't use --provenance yet, so its bare absence is never scored on its own — only an org-norm anomaly or an actual source mismatch is. Use get_package/get_package_version first for basic package info; use this specifically to assess publish-integrity risk.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['name'], 'properties': {'name': {'type': 'string', 'maxLength': 214, 'minLength': 1, 'description': 'Exact npm package name, e.g. "lodash" or "@scope/name"'}, 'version': {'type': 'string', 'maxLength': 128, 'minLength': 1, 'description': 'Exact version to check; omit to use the latest published version'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['name', 'version', 'npmscanUrl', 'provenance', 'peers', 'sourceDiff', 'findings', 'totalScore', 'riskTier'], 'properties': {'name': {'type': 'string'}, 'peers': {'type': 'object', 'required': ['orgKind', 'orgIdentifier', 'peersChecked', 'peersWithProvenance', 'peerProvenanceRate', 'note'], 'properties': {'note': {'type': ['string', 'null']}, 'orgKind': {'anyOf': [{'enum': ['scope', 'maintainer'], 'type': 'string'}, {'type': 'null'}]}, 'peersChecked': {'type': 'number'}, 'orgIdentifier': {'type': ['string', 'null']}, 'peerProvenanceRate': {'type': ['number', 'null']}, 'peersWithProvenance': {'type': 'number'}}, 'additionalProperties': False}, 'version': {'type': 'string'}, 'findings': {'type': 'array', 'items': {'type': 'object', 'required': ['rule', 'text', 'points', 'note', 'locations'], 'properties': {'note': {'type': 'string'}, 'rule': {'type': 'string'}, 'text': {'type': 'string'}, 'points': {'type': 'number'}, 'locations': {'type': 'array', 'items': {'type': 'object', 'required': ['file', 'snippet'], 'properties': {'file': {'type': 'string'}, 'snippet': {'type': 'string'}}, 'additionalProperties': False}}}, 'additionalProperties': False}}, 'riskTier': {'enum': ['none', 'low', 'moderate', 'high', 'critical'], 'type': 'string'}, 'npmscanUrl': {'type': 'string'}, 'provenance': {'type': 'object', 'required': ['hasProvenance', 'predicateType', 'sourceRepository', 'workflowPath', 'builderId', 'sourceCommit', 'buildRunUrl', 'declaredRepository', 'repositoryMatchesBuild', 'note'], 'properties': {'note': {'type': ['string', 'null']}, 'builderId': {'type': ['string', 'null']}, 'buildRunUrl': {'type': ['string', 'null']}, 'sourceCommit': {'type': ['string', 'null']}, 'workflowPath': {'type': ['string', 'null']}, 'hasProvenance': {'type': 'boolean'}, 'predicateType': {'type': ['string', 'null']}, 'sourceRepository': {'type': ['string', 'null']}, 'declaredRepository': {'type': ['string', 'null']}, 'repositoryMatchesBuild': {'type': ['boolean', 'null']}}, 'additionalProperties': False}, 'sourceDiff': {'type': 'object', 'required': ['checked', 'gitRef', 'refSource', 'addedInstallScripts', 'addedDependencies', 'note'], 'properties': {'note': {'type': ['string', 'null']}, 'gitRef': {'type': ['string', 'null']}, 'checked': {'type': 'boolean'}, 'refSource': {'anyOf': [{'enum': ['provenance-commit', 'guessed-tag'], 'type': 'string'}, {'type': 'null'}]}, 'addedDependencies': {'type': 'array', 'items': {'type': 'string'}}, 'addedInstallScripts': {'type': 'array', 'items': {'type': 'string'}}}, 'additionalProperties': False}, 'totalScore': {'type': 'number'}}, 'additionalProperties': False}
compare_packages
Compare npm packages side-by-side
Given 2-5 candidate packages for the same job (e.g. "axios vs got vs node-fetch"), fetches the same registry/popularity/maintenance/vulnerability enrichment get_package computes for each one in parallel and returns a structured side-by-side plus a deterministic, reasoned pick. Each candidate gets downloads + trend, popularityTier/maintenanceTier, GitHub stars, TypeScript support, license, deprecated status, latest-version vulnerability status, a lightweight installScriptRisk signal (scans lifecycle script command strings for known red flags — does NOT fetch the tarball; call analyze_install_script on a specific candidate for that deeper scan), and installSize (the candidate's own dist.unpackedSize plus a transitive rollup — summed dist.unpackedSize across its resolved dependency tree, walked up to depth 2 / 60 nodes per candidate; `installSize.transitive.truncated`/`sizeUnknownCount` flag when that sum is partial rather than pretending it's exact — call analyze_transitive_dependencies on a specific candidate for the full graph). `differentiators` names which candidates stand out on each dimension (most downloads, only ones with TS types, which are deprecated/vulnerable/flagged as a typosquat/install-script risk, smallest/largest install size). `recommendation.pick` is chosen deterministically from a weighted score (popularity, maintenance, deprecation, vulnerabilities, typosquat flag, install-script risk, TS support, GitHub stars — install size is reported but not scored) — never a deprecated or typosquat-flagged candidate — with `rationale` explaining why and `confidence` reflecting how close the top two scored. If a candidate's OSV.dev vulnerability check itself failed (network/timeout/upstream outage), `isLatestVersionVulnerable` comes back `false` only because the field has to be a boolean — `vulnerabilityCheckFailed:true` is the real signal there, and means that candidate's safe/not-safe answer is unknown, not confirmed clean. A name that can't be resolved (typo, unpublished, malformed) still appears in `candidates` with `found:false` and `resolutionError` set rather than failing the whole call; duplicate names in the input are rejected.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['packages'], 'properties': {'packages': {'type': 'array', 'items': {'type': 'string', 'maxLength': 214, 'minLength': 1}, 'maxItems': 5, 'minItems': 2, 'description': '2-5 exact npm package names to compare, e.g. ["axios", "got", "node-fetch"].'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['candidates', 'differentiators', 'recommendation'], 'properties': {'candidates': {'type': 'array', 'items': {'type': 'object', 'required': ['name', 'found', 'resolutionError', 'npmscanUrl', 'description', 'license', 'latestVersion', 'deprecated', 'weeklyDownloads', 'downloadTrend', 'githubStars', 'hasBuiltInTypes', 'daysSinceLastPublish', 'popularityTier', 'maintenanceTier', 'maintenanceSummary', 'possibleTyposquatOf', 'isLatestVersionVulnerable', 'vulnerabilityCheckFailed', 'highestSeverity', 'vulnerabilityCount', 'installScriptRisk', 'installSize', 'score'], 'properties': {'name': {'type': 'string'}, 'found': {'type': 'boolean'}, 'score': {'type': ['number', 'null']}, 'license': {'type': ['string', 'null']}, 'deprecated': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'description': {'type': ['string', 'null']}, 'githubStars': {'type': ['number', 'null']}, 'installSize': {'anyOf': [{'type': 'object', 'required': ['unpackedSize', 'transitive'], 'properties': {'transitive': {'type': 'object', 'required': ['transitiveUnpackedSize', 'transitiveDependencyCount', 'sizeUnknownCount', 'truncated'], 'properties': {'truncated': {'type': 'boolean'}, 'sizeUnknownCount': {'type': 'number'}, 'transitiveUnpackedSize': {'type': ['number', 'null']}, 'transitiveDependencyCount': {'type': 'number'}}, 'additionalProperties': False}, 'unpackedSize': {'type': ['number', 'null']}}, 'additionalProperties': False}, {'type': 'null'}]}, 'downloadTrend': {'type': 'object', 'required': ['direction', 'changePercent'], 'properties': {'direction': {'enum': ['growing', 'stable', 'declining', 'unknown'], 'type': 'string'}, 'changePercent': {'type': ['number', 'null']}}, 'additionalProperties': False}, 'latestVersion': {'type': ['string', 'null']}, 'popularityTier': {'enum': ['very-high', 'high', 'moderate', 'low', 'very-low', 'unknown'], 'type': 'string'}, 'hasBuiltInTypes': {'type': 'boolean'}, 'highestSeverity': {'type': ['string', 'null']}, 'maintenanceTier': {'enum': ['active', 'aging', 'stale', 'unknown'], 'type': 'string'}, 'resolutionError': {'type': ['string', 'null']}, 'weeklyDownloads': {'type': ['number', 'null']}, 'installScriptRisk': {'anyOf': [{'type': 'object', 'required': ['hasLifecycleScripts', 'riskTier', 'totalScore', 'scanScope'], 'properties': {'riskTier': {'enum': ['none', 'low', 'moderate', 'high', 'critical'], 'type': 'string'}, 'scanScope': {'type': 'string', 'const': 'lifecycle-scripts-only'}, 'totalScore': {'type': 'number'}, 'hasLifecycleScripts': {'type': 'boolean'}}, 'additionalProperties': False}, {'type': 'null'}]}, 'maintenanceSummary': {'type': 'string'}, 'vulnerabilityCount': {'type': 'number'}, 'possibleTyposquatOf': {'anyOf': [{'type': 'object', 'required': ['name', 'rank'], 'properties': {'name': {'type': 'string'}, 'rank': {'type': 'number'}}, 'additionalProperties': False}, {'type': 'null'}]}, 'daysSinceLastPublish': {'type': ['number', 'null']}, 'vulnerabilityCheckFailed': {'type': 'boolean'}, 'isLatestVersionVulnerable': {'type': 'boolean'}}, 'additionalProperties': False}}, 'recommendation': {'type': 'object', 'required': ['pick', 'runnerUp', 'rationale', 'confidence'], 'properties': {'pick': {'type': ['string', 'null']}, 'runnerUp': {'type': ['string', 'null']}, 'rationale': {'type': 'string'}, 'confidence': {'enum': ['high', 'medium', 'low'], 'type': 'string'}}, 'additionalProperties': False}, 'differentiators': {'type': 'object', 'required': ['mostDownloads', 'mostGithubStars', 'hasTypeScriptSupport', 'hasKnownVulnerabilities', 'deprecated', 'possibleTyposquat', 'installScriptRiskFlagged', 'smallestInstallSize', 'largestInstallSize'], 'properties': {'deprecated': {'type': 'array', 'items': {'type': 'string'}}, 'mostDownloads': {'type': ['string', 'null']}, 'mostGithubStars': {'type': ['string', 'null']}, 'possibleTyposquat': {'type': 'array', 'items': {'type': 'string'}}, 'largestInstallSize': {'type': ['string', 'null']}, 'smallestInstallSize': {'type': ['string', 'null']}, 'hasTypeScriptSupport': {'type': 'array', 'items': {'type': 'string'}}, 'hasKnownVulnerabilities': {'type': 'array', 'items': {'type': 'string'}}, 'installScriptRiskFlagged': {'type': 'array', 'items': {'type': 'string'}}}, 'additionalProperties': False}}, 'additionalProperties': False}
diff_dependencies
Diff two package.json/lockfile snapshots
Compares two raw snapshots of a package.json, package-lock.json (npm v1-v3), yarn.lock (classic v1 or Berry), or pnpm-lock.yaml — e.g. before/after a PR — and reports which packages were added, removed, or version-bumped. An npm alias (e.g. `"totally-safe": "npm:minimist@0.0.8"`) is followed to its real target in every format — `actualName` names the real package that vulnerability/install-script data attaches to (`name` stays the declared/alias key); this is NOT silently skipped, since doing so would let a vulnerable package hide behind whatever name a project calls it. For every added or bumped package (up to 100 per call), also checks whether its resolved version carries a preinstall/install/postinstall/prepare lifecycle script that the before-version did NOT have (`installScriptIntroduced`, a headline signal — a routine-looking patch bump quietly adding a postinstall is exactly the shape of a compromised-maintainer supply-chain attack) and batch-checks it against OSV.dev, reporting `vulnerabilityDelta` (introduced/fixed/still-vulnerable/still-clean) rather than just a bare isVulnerable flag. `installScriptIntroduced` is a boolean across all four lifecycle keys, so it treats a bare `"prepare": "husky"` bump the same as a newly-added network-capable `postinstall` — read `installScriptKeysIntroduced` (null when only npm-lock's boolean hint was available, not the real scripts object; otherwise the actual key(s) added) to tell those apart before treating a flag as high-severity. `sourceIntegrityChanged` catches a DIFFERENT attack shape than a version bump: a lockfile entry whose resolved tarball URL or integrity hash changed while the version string stayed IDENTICAL — e.g. a compromised registry mirror or a hand-edited lockfile pointing a legitimate-looking "lodash@4.17.21" at a different, unverified artifact — which a version-only diff would report as "no change" (`resolvedUrl`/`integrity` are null when a format doesn't record either, package.json has neither). Scope notes: package.json is diffed as its own declared dependency list only (a manifest has no transitive data at all, and this includes `peerDependencies`, unlike batch_query_vulnerabilities/generate_sbom which exclude them by default — a diff should catch a peerDependency change just like any other); every lockfile format (package-lock.json, pnpm-lock.yaml, yarn.lock) reports its FULL resolved graph — direct and transitive alike — so a transitive-only change (e.g. a nested `qs` bumped while the direct `express` version is untouched) is caught, not just direct dependency changes; check `comparisonNote` when the two snapshots are different formats/scopes. The install-script check is presence-only (read from the registry packument or lockfile metadata, not a tarball content scan) — use analyze_install_script for a deep-dive on anything flagged here. `projectLifecycleChanges` diffs the SCANNED PROJECT's own root preinstall/install/postinstall/prepare scripts (package.json only — null when neither snapshot is one) — independent of the dependency list above, since a PR that only adds a root postinstall (`"postinstall": "curl ... | sh"`) changes nothing about added/removed/changed and would otherwise be invisible to this tool entirely; `introduced`/`changed` on a preinstall/install/postinstall key is counted in `flaggedCount`. `overridesChanges` similarly diffs package.json's `overrides` (npm), `resolutions` (yarn), or `pnpm.overrides` — these force a specific version onto a transitive dependency (often to pin past a known vulnerability), so a PR that quietly removes, downgrades, or introduces one is exactly the kind of change a dependency diff should catch, and previously nothing here read this field at all; ANY change here (introduced/removed/changed) is counted in `flaggedCount`, since an override can be a security control being weakened just as easily as an attack forcing a compromised version onto an otherwise-untouched dependency. Ideal for a CI gate reviewing a dependency-changing PR.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['before', 'after'], 'properties': {'after': {'type': 'string', 'maxLength': 8388608, 'minLength': 1, 'description': 'Raw file content of the "after" snapshot â\x80\x94 a package.json, package-lock.json (npm v1-v3), yarn.lock (classic v1 or Berry), or pnpm-lock.yaml. Format is auto-detected; before/after may be different formats.'}, 'before': {'type': 'string', 'maxLength': 8388608, 'minLength': 1, 'description': 'Raw file content of the "before" snapshot â\x80\x94 a package.json, package-lock.json (npm v1-v3), yarn.lock (classic v1 or Berry), or pnpm-lock.yaml. Format is auto-detected; before/after may be different formats.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['summary', 'beforeFormat', 'afterFormat', 'comparisonNote', 'added', 'removed', 'changed', 'totalAdded', 'totalRemoved', 'totalChanged', 'flaggedCount', 'truncated', 'truncationNote', 'enrichmentNote', 'projectLifecycleChanges', 'overridesChanges'], 'properties': {'added': {'type': 'array', 'items': {'type': 'object', 'required': ['name', 'actualName', 'npmscanUrl', 'beforeVersion', 'afterVersion', 'coexistingVersions', 'changeType', 'hasInstallScript', 'installScriptIntroduced', 'installScriptKeys', 'installScriptKeysIntroduced', 'sourceIntegrityChanged', 'resolvedUrl', 'integrity', 'isVulnerable', 'highestSeverity', 'vulnerabilities', 'vulnerabilityDelta', 'resolutionNote'], 'properties': {'name': {'type': 'string'}, 'integrity': {'type': ['string', 'null']}, 'actualName': {'type': ['string', 'null']}, 'changeType': {'anyOf': [{'enum': ['upgrade', 'downgrade', 'unresolved'], 'type': 'string'}, {'type': 'null'}]}, 'npmscanUrl': {'type': 'string'}, 'resolvedUrl': {'type': ['string', 'null']}, 'afterVersion': {'type': ['string', 'null']}, 'isVulnerable': {'type': ['boolean', 'null']}, 'beforeVersion': {'type': ['string', 'null']}, 'resolutionNote': {'type': ['string', 'null']}, 'highestSeverity': {'type': ['string', 'null']}, 'vulnerabilities': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'summary', 'severity', 'aliases', 'publishedAt', 'fixedVersion', 'npmscanUrl'], 'properties': {'id': {'type': 'string'}, 'aliases': {'type': 'array', 'items': {'type': 'string'}}, 'summary': {'type': ['string', 'null']}, 'severity': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'publishedAt': {'type': ['string', 'null']}, 'fixedVersion': {'type': ['string', 'null']}}, 'additionalProperties': False}}, 'hasInstallScript': {'type': ['boolean', 'null']}, 'installScriptKeys': {'anyOf': [{'type': 'array', 'items': {'enum': ['preinstall', 'install', 'postinstall', 'prepare'], 'type': 'string'}}, {'type': 'null'}]}, 'coexistingVersions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}]}, 'vulnerabilityDelta': {'anyOf': [{'enum': ['introduced', 'fixed', 'still-vulnerable', 'still-clean', 'unknown'], 'type': 'string'}, {'type': 'null'}]}, 'sourceIntegrityChanged': {'type': ['boolean', 'null']}, 'installScriptIntroduced': {'type': ['boolean', 'null']}, 'installScriptKeysIntroduced': {'anyOf': [{'type': 'array', 'items': {'enum': ['preinstall', 'install', 'postinstall', 'prepare'], 'type': 'string'}}, {'type': 'null'}]}}, 'additionalProperties': False}}, 'changed': {'type': 'array', 'items': {'$ref': '#/properties/added/items'}}, 'removed': {'type': 'array', 'items': {'type': 'object', 'required': ['name', 'actualName', 'version', 'npmscanUrl'], 'properties': {'name': {'type': 'string'}, 'version': {'type': ['string', 'null']}, 'actualName': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}}, 'additionalProperties': False}}, 'summary': {'type': 'string'}, 'truncated': {'type': 'boolean'}, 'totalAdded': {'type': 'number'}, 'afterFormat': {'enum': ['package.json', 'npm-lock', 'yarn-lock', 'pnpm-lock'], 'type': 'string'}, 'beforeFormat': {'enum': ['package.json', 'npm-lock', 'yarn-lock', 'pnpm-lock'], 'type': 'string'}, 'flaggedCount': {'type': 'number'}, 'totalChanged': {'type': 'number'}, 'totalRemoved': {'type': 'number'}, 'comparisonNote': {'type': ['string', 'null']}, 'enrichmentNote': {'type': ['string', 'null']}, 'truncationNote': {'type': ['string', 'null']}, 'overridesChanges': {'anyOf': [{'type': 'object', 'required': ['introduced', 'removed', 'changed'], 'properties': {'changed': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['before', 'after'], 'properties': {'after': {'type': 'string'}, 'before': {'type': 'string'}}, 'additionalProperties': False}}, 'removed': {'type': 'object', 'additionalProperties': {'type': 'string'}}, 'introduced': {'type': 'object', 'additionalProperties': {'type': 'string'}}}, 'additionalProperties': False}, {'type': 'null'}]}, 'projectLifecycleChanges': {'anyOf': [{'type': 'object', 'required': ['introduced', 'removed', 'changed'], 'properties': {'changed': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['before', 'after'], 'properties': {'after': {'type': 'string'}, 'before': {'type': 'string'}}, 'additionalProperties': False}}, 'removed': {'type': 'object', 'additionalProperties': {'type': 'string'}}, 'introduced': {'type': 'object', 'additionalProperties': {'type': 'string'}}}, 'additionalProperties': False}, {'type': 'null'}]}}, 'additionalProperties': False}
enrich_npm_audit
Rank raw `npm audit --json` output by what to fix first
Given the raw output of `npm audit --json` (npm 7+'s `{vulnerabilities: {...}}` format, or legacy npm 6's `{advisories: {...}}`), parses it directly — no need to re-paste package.json/lockfile content — and runs it through the same remove-now/patch-now/patch-soon/scheduled/monitor ranking prioritize_remediation exposes for hand-built finding lists (a MAL-* advisoryId in the audit report is auto-detected as malware and forces remove-now). npm audit's JSON almost never includes a CVE id (only a GHSA advisory URL), so this resolves each GHSA to its CVE alias via OSV.dev when one exists (ghsaResolvedToCveCount reports how many) before doing the same CISA KEV + FIRST.org EPSS + severity scoring — skipping this step would silently degrade most findings to severity-only ranking despite prioritize_remediation being built around CVE-keyed KEV/EPSS data. Also carries through npm-audit-specific context prioritize_remediation itself has no field for: isDirect (direct vs. transitive dependency) and fixAvailable/fixTarget (npm's own computed fix — note fixTarget can name a different package than the vulnerable one, e.g. bumping a parent to pull in a patched transitive dependency). A package with more than one distinct advisory in the source report only has its first advisory used for ranking; a warning names the package so query_vulnerabilities can be called on it directly for the rest. `yarn audit --json` and `pnpm audit --json` use different report shapes and are not supported — use batch_query_vulnerabilities with the project's manifest/lockfile for those instead.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['content'], 'properties': {'content': {'type': 'string', 'minLength': 1, 'description': 'Raw stdout of `npm audit --json` â\x80\x94 either npm 7+ format ({"auditReportVersion": 2, "vulnerabilities": {...}}) or legacy npm 6 format ({"advisories": {...}}).'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['inputFormat', 'totalFindings', 'uniqueCveCount', 'ghsaResolvedToCveCount', 'summary', 'ranked', 'warnings', 'skippedCount'], 'properties': {'ranked': {'type': 'array', 'items': {'type': 'object', 'required': ['rank', 'packageName', 'cveId', 'advisoryId', 'currentVersion', 'fixedVersion', 'severity', 'kev', 'epss', 'score', 'tier', 'findingType', 'reason', 'npmscanUrl', 'cveNpmscanUrl', 'advisoryTitle', 'isDirect', 'fixAvailable', 'fixTarget'], 'properties': {'kev': {'anyOf': [{'type': 'object', 'required': ['dateAdded', 'dueDate', 'knownRansomwareCampaignUse', 'requiredAction'], 'properties': {'dueDate': {'type': 'string'}, 'dateAdded': {'type': 'string'}, 'requiredAction': {'type': 'string'}, 'knownRansomwareCampaignUse': {'type': 'string'}}, 'additionalProperties': False}, {'type': 'null'}]}, 'epss': {'anyOf': [{'type': 'object', 'required': ['score', 'percentile', 'date'], 'properties': {'date': {'type': 'string'}, 'score': {'type': 'number'}, 'percentile': {'type': 'number'}}, 'additionalProperties': False}, {'type': 'null'}]}, 'rank': {'type': 'number'}, 'tier': {'enum': ['remove-now', 'patch-now', 'patch-soon', 'scheduled', 'monitor'], 'type': 'string'}, 'cveId': {'type': ['string', 'null']}, 'score': {'type': 'number'}, 'reason': {'type': 'string'}, 'isDirect': {'type': ['boolean', 'null']}, 'severity': {'type': ['string', 'null']}, 'fixTarget': {'anyOf': [{'type': 'object', 'required': ['name', 'version', 'isSemVerMajor'], 'properties': {'name': {'type': 'string'}, 'version': {'type': 'string'}, 'isSemVerMajor': {'type': 'boolean'}}, 'additionalProperties': False}, {'type': 'null'}]}, 'advisoryId': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'findingType': {'enum': ['malware', 'vulnerability', 'supply-chain', 'install-script'], 'type': 'string'}, 'packageName': {'type': 'string'}, 'fixAvailable': {'type': ['boolean', 'null']}, 'fixedVersion': {'type': ['string', 'null']}, 'advisoryTitle': {'type': ['string', 'null']}, 'cveNpmscanUrl': {'type': ['string', 'null']}, 'currentVersion': {'type': ['string', 'null']}}, 'additionalProperties': False}}, 'summary': {'type': 'object', 'required': ['removeNow', 'patchNow', 'patchSoon', 'scheduled', 'monitor', 'kevListedCount'], 'properties': {'monitor': {'type': 'number'}, 'patchNow': {'type': 'number'}, 'patchSoon': {'type': 'number'}, 'removeNow': {'type': 'number'}, 'scheduled': {'type': 'number'}, 'kevListedCount': {'type': 'number'}}, 'additionalProperties': False}, 'warnings': {'type': 'array', 'items': {'type': 'string'}}, 'inputFormat': {'enum': ['npm-audit-v2', 'npm-audit-legacy'], 'type': 'string'}, 'skippedCount': {'type': 'number'}, 'totalFindings': {'type': 'number'}, 'uniqueCveCount': {'type': 'number'}, 'ghsaResolvedToCveCount': {'type': 'number'}}, 'additionalProperties': False}
generate_sbom
Generate a CycloneDX or SPDX SBOM
Given the same inputs batch_query_vulnerabilities accepts — either a flat {packages:[...]} list, or raw package.json / lockfile / CycloneDX JSON / SPDX JSON content via `content` — emits a spec-valid CycloneDX 1.6 or SPDX 2.3 JSON document (pick with `format`, default 'cyclonedx') with npmscan's own OSV.dev vulnerability findings and registry license data embedded in each spec's native fields: CycloneDX gets a top-level `vulnerabilities[]` array (VEX `analysis.state: 'in_triage'` — an unreviewed automated finding, not a claim of exploitability) and per-component `licenses[]`; SPDX (which has no vulnerabilities array in 2.3) gets one `externalRefs` SECURITY/advisory entry per finding and `licenseDeclared`/`licenseConcluded`. Only a flat package inventory is known here, so the CycloneDX `dependencies[]` transitive graph and any SPDX package hierarchy are intentionally omitted rather than fabricated. Set `includeVulnerabilities`/`includeLicenses` to false to skip either enrichment pass (faster, no registry/OSV calls for that pass); pass `policy` (same shape as check_license_compliance) to also get per-package compliance context; `componentName`/`componentVersion` name the SBOM's own root component/document if known. When `content` is a package.json, `peerDependencies` are excluded by default (a peer is often intentionally left unresolved by the consumer) — pass `includePeerDependencies: true` to include them as SBOM components too, since an SBOM meant to be complete shouldn't silently omit a whole dependency category.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'properties': {'format': {'enum': ['cyclonedx', 'spdx'], 'type': 'string', 'description': "SBOM format to emit. Default 'cyclonedx'."}, 'policy': {'type': 'object', 'properties': {'deny': {'type': 'array', 'items': {'type': 'string', 'maxLength': 100, 'minLength': 1}, 'maxItems': 50, 'description': 'SPDX ids, family prefixes, or category names. Always takes precedence over allow.'}, 'allow': {'type': 'array', 'items': {'type': 'string', 'maxLength': 100, 'minLength': 1}, 'maxItems': 50, 'description': 'SPDX ids, family prefixes (e.g. "GPL"), or category names. Anything not matching is a violation.'}}, 'description': 'License allow/deny policy, same shape as check_license_compliance. Omit for the default policy.', 'additionalProperties': False}, 'content': {'type': 'string', 'minLength': 1, 'description': 'Raw dependency inventory content: package.json, package-lock.json, yarn.lock, pnpm-lock.yaml, CycloneDX JSON, or SPDX JSON. Use this OR `packages`, not both.'}, 'packages': {'type': 'array', 'items': {'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string', 'maxLength': 214, 'minLength': 1}, 'version': {'type': 'string', 'maxLength': 128}}, 'additionalProperties': False}, 'maxItems': 1000, 'minItems': 1, 'description': 'Explicit package list (1-1000 items, capped to 100 when includeLicenses is on). Use this OR `content`, not both.'}, 'componentName': {'type': 'string', 'maxLength': 214, 'minLength': 1, 'description': "Name of the SBOM's own root component/document, if known."}, 'includeLicenses': {'type': 'boolean', 'description': 'Resolve registry license data and embed it natively. Default true.'}, 'componentVersion': {'type': 'string', 'maxLength': 128, 'minLength': 1}, 'includeDevDependencies': {'type': 'boolean', 'description': 'Ignored when using `packages`; only applies when `content` is a manifest/lockfile format that distinguishes dev dependencies.'}, 'includeVulnerabilities': {'type': 'boolean', 'description': 'Query OSV.dev and embed findings natively. Default true.'}, 'includePeerDependencies': {'type': 'boolean', 'description': 'Ignored when using `packages`; only applies when `content` is a package.json. peerDependencies are excluded by default â\x80\x94 set this to also include them as SBOM components.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['format', 'sbom', 'parsedPackageCount', 'totalVulnerabilities', 'packagesWithVulnerabilities'], 'properties': {'sbom': {'type': 'object', 'additionalProperties': {}}, 'format': {'enum': ['cyclonedx', 'spdx'], 'type': 'string'}, 'policy': {'type': 'object', 'required': ['mode', 'allow', 'deny'], 'properties': {'deny': {'type': 'array', 'items': {'type': 'string'}}, 'mode': {'enum': ['default', 'allow', 'deny', 'allow+deny'], 'type': 'string'}, 'allow': {'type': 'array', 'items': {'type': 'string'}}}, 'additionalProperties': False}, 'warnings': {'type': 'array', 'items': {'type': 'string'}}, 'inputFormat': {'type': 'string'}, 'ignoredCount': {'type': 'number'}, 'enrichmentNote': {'type': 'string'}, 'parsedPackageCount': {'type': 'number'}, 'totalVulnerabilities': {'type': 'number'}, 'licenseViolationCount': {'type': 'number'}, 'packagesWithVulnerabilities': {'type': 'number'}}, 'additionalProperties': False}
get_cve
Look up a CVE in the NIST NVD
Look up authoritative NIST NVD data for one exact CVE ID (e.g. "CVE-2026-2950"), or browse/search NVD by keyword, CVSS severity, CWE, or a publication-date range. Every result is enriched with CISA KEV status (`kev`, non-null only if this CVE is a confirmed, actively-exploited-in-the-wild vulnerability — treat that as an urgent-patch signal regardless of CVSS score) and FIRST.org EPSS (`epss`, the probability of exploitation in the next 30 days — a better prioritization signal than CVSS severity alone, which measures impact, not likelihood). If the KEV or EPSS lookup itself fails (network/timeout/upstream outage), `kev`/`epss` come back `null` only because those fields have to be nullable — `kevCheckFailed`/`epssCheckFailed` (true in that case) is the real signal, and means "unknown", not "confirmed absent/unscored". For a search, a failed EPSS batch call sets `epssCheckFailed` on every result in that response, since one call scores every id together; `kevCheckFailed` is tracked per-CVE since each is looked up independently. For a single cveId lookup, if NVD has no record yet or hasn't scored it, this falls back to the raw MITRE CVE record automatically (`source: "mitre"` on the result) rather than returning nothing. NVD is NOT npm-scoped — unlike query_vulnerabilities/get_latest_advisories, search results can include CVEs for any ecosystem, so pass keywordSearch (e.g. the package name) to narrow it. Prefer this for the authoritative CVSS score/vector/KEV/EPSS data on a CVE already found via another tool, or when a user pastes a CVE ID/link directly; prefer get_latest_advisories for npm-specific browsing. NVD enforces a strict shared rate limit, so this tool may occasionally ask you to retry in a few seconds — do so rather than assuming failure.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'properties': {'cveId': {'type': 'string', 'pattern': '^CVE-\\d{4}-\\d{4,}$', 'description': 'Exact CVE ID for a single lookup, e.g. "CVE-2026-2950". When given, search filters below are ignored and should be omitted.'}, 'cweId': {'type': 'string', 'pattern': '^CWE-\\d+$', 'description': 'Filter by weakness type, e.g. "CWE-79"'}, 'severity': {'enum': ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'], 'type': 'string', 'description': 'Filter by CVSS v3 base severity'}, 'startIndex': {'type': 'integer', 'minimum': 0, 'description': 'Pagination offset for a search'}, 'keywordSearch': {'type': 'string', 'maxLength': 200, 'minLength': 1, 'description': 'Free-text search, e.g. a package or product name'}, 'publishedSince': {'type': 'string', 'pattern': '^\\d{4}-\\d{2}-\\d{2}$', 'description': 'Publication date range start (YYYY-MM-DD). Must be given together with publishedUntil.'}, 'publishedUntil': {'$ref': '#/properties/publishedSince', 'description': 'Publication date range end (YYYY-MM-DD). Must be given together with publishedSince; range is capped at 120 days.'}, 'resultsPerPage': {'type': 'integer', 'maximum': 50, 'minimum': 1, 'description': 'Max results for a search (default 10, capped at 50)'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'properties': {'id': {'type': 'string'}, 'kev': {'anyOf': [{'type': 'object', 'required': ['dateAdded', 'dueDate', 'knownRansomwareCampaignUse', 'requiredAction'], 'properties': {'dueDate': {'type': 'string'}, 'dateAdded': {'type': 'string'}, 'requiredAction': {'type': 'string'}, 'knownRansomwareCampaignUse': {'type': 'string'}}, 'additionalProperties': False}, {'type': 'null'}]}, 'cves': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'npmscanUrl', 'vulnStatus', 'description', 'published', 'lastModified', 'cvss', 'cwes', 'references', 'source', 'kev', 'epss', 'kevCheckFailed', 'epssCheckFailed'], 'properties': {'id': {'$ref': '#/properties/id'}, 'kev': {'$ref': '#/properties/kev'}, 'cvss': {'$ref': '#/properties/cvss'}, 'cwes': {'$ref': '#/properties/cwes'}, 'epss': {'$ref': '#/properties/epss'}, 'source': {'$ref': '#/properties/source'}, 'published': {'$ref': '#/properties/published'}, 'npmscanUrl': {'$ref': '#/properties/npmscanUrl'}, 'references': {'$ref': '#/properties/references'}, 'vulnStatus': {'$ref': '#/properties/vulnStatus'}, 'description': {'$ref': '#/properties/description'}, 'lastModified': {'$ref': '#/properties/lastModified'}, 'kevCheckFailed': {'$ref': '#/properties/kevCheckFailed'}, 'epssCheckFailed': {'$ref': '#/properties/epssCheckFailed'}}, 'additionalProperties': False}}, 'cvss': {'anyOf': [{'type': 'object', 'required': ['version', 'baseScore', 'baseSeverity', 'vectorString'], 'properties': {'version': {'enum': ['3.1', '3.0', '2.0'], 'type': 'string'}, 'baseScore': {'type': 'number'}, 'baseSeverity': {'type': ['string', 'null']}, 'vectorString': {'type': 'string'}}, 'additionalProperties': False}, {'type': 'null'}]}, 'cwes': {'type': 'array', 'items': {'type': 'string'}}, 'epss': {'anyOf': [{'type': 'object', 'required': ['score', 'percentile', 'date'], 'properties': {'date': {'type': 'string'}, 'score': {'type': 'number'}, 'percentile': {'type': 'number'}}, 'additionalProperties': False}, {'type': 'null'}]}, 'note': {'type': 'string'}, 'cveId': {'type': 'string'}, 'found': {'type': 'boolean'}, 'source': {'enum': ['nvd', 'mitre'], 'type': 'string'}, 'published': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'references': {'type': 'array', 'items': {'type': 'object', 'required': ['url', 'source', 'tags'], 'properties': {'url': {'type': 'string'}, 'tags': {'type': 'array', 'items': {'type': 'string'}}, 'source': {'type': ['string', 'null']}}, 'additionalProperties': False}}, 'startIndex': {'type': 'number'}, 'vulnStatus': {'type': ['string', 'null']}, 'description': {'type': ['string', 'null']}, 'lastModified': {'type': ['string', 'null']}, 'totalResults': {'type': 'number'}, 'kevCheckFailed': {'type': 'boolean'}, 'resultsPerPage': {'type': 'number'}, 'epssCheckFailed': {'type': 'boolean'}, 'dateRangeClamped': {'type': 'boolean'}}, 'additionalProperties': False}
get_latest_advisories
Get latest npm security advisories
Browse recently published npm security advisories and known-malicious-package findings. Three disjoint sources, selected via type: "reviewed" (default) is GitHub's curated, mostly CVE-backed advisories; "malware" is GitHub's own known-malicious-package advisories; "osv" is OSV.dev's OpenSSF malicious-packages feed, a separate dataset whose entries use MAL-/OSV ids rather than GHSA ids. None of "malware"/"osv" carry a CVE or meaningful CWE beyond "embedded malicious code". Filter by severity, vulnerability category (XSS, SQL/NoSQL Injection, SSRF, Access Control, Code Injection, etc. — reviewed only), an affected package name, or (reviewed/malware only) look up one exact advisory by GHSA or CVE ID. Paginated with an opaque cursor: pass a previous response's nextCursor back in as cursor to fetch the next page.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'properties': {'type': {'enum': ['reviewed', 'malware', 'osv'], 'type': 'string', 'description': 'Advisory source: "reviewed" (curated CVE-style, default), "malware" (GitHub-curated known-malicious packages), or "osv" (OSV.dev/OpenSSF malicious-packages feed)'}, 'cveId': {'type': 'string', 'description': 'Look up one exact advisory by its CVE ID (e.g. "CVE-2024-12345") â\x80\x94 reviewed/malware only'}, 'cursor': {'type': 'string', 'description': "Opaque pagination cursor from a previous response's nextCursor, to fetch the next page"}, 'ghsaId': {'type': 'string', 'description': 'Look up one exact advisory by its GHSA ID (e.g. "GHSA-xxxx-xxxx-xxxx") â\x80\x94 reviewed/malware only'}, 'affects': {'type': 'string', 'maxLength': 214, 'description': 'Filter to advisories affecting this npm package name'}, 'category': {'enum': ['access-control', 'dos', 'xss', 'ssrf', 'auth', 'code-injection', 'info-exposure', 'path-traversal', 'input-validation', 'prototype-pollution', 'command-injection', 'sqli', 'crypto', 'race-condition', 'open-redirect', 'csrf', 'crlf-injection', 'xml-injection', 'malicious-code', 'deserialization'], 'type': 'string', 'description': 'Filter by vulnerability category (reviewed only). One of: access-control, dos, xss, ssrf, auth, code-injection, info-exposure, path-traversal, input-validation, prototype-pollution, command-injection, sqli, crypto, race-condition, open-redirect, csrf, crlf-injection, xml-injection, malicious-code, deserialization'}, 'severity': {'enum': ['critical', 'high', 'medium', 'low', 'all'], 'type': 'string', 'description': 'Filter by severity (default all; not applicable to "malware"/"osv")'}, 'direction': {'enum': ['asc', 'desc'], 'type': 'string', 'description': 'Sort by published date, newest or oldest first (default desc)'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['type', 'severity', 'category', 'direction', 'nextCursor', 'advisories'], 'properties': {'type': {'enum': ['reviewed', 'malware', 'osv'], 'type': 'string'}, 'category': {'enum': ['all', 'access-control', 'dos', 'xss', 'ssrf', 'auth', 'code-injection', 'info-exposure', 'path-traversal', 'input-validation', 'prototype-pollution', 'command-injection', 'sqli', 'crypto', 'race-condition', 'open-redirect', 'csrf', 'crlf-injection', 'xml-injection', 'malicious-code', 'deserialization'], 'type': 'string'}, 'severity': {'enum': ['critical', 'high', 'medium', 'low', 'all'], 'type': 'string'}, 'direction': {'enum': ['asc', 'desc'], 'type': 'string'}, 'advisories': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'cve', 'summary', 'severity', 'publishedAt', 'ghsaUrl', 'npmscanUrl', 'cwes', 'categories', 'packages'], 'properties': {'id': {'type': 'string'}, 'cve': {'type': ['string', 'null']}, 'cwes': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'name'], 'properties': {'id': {'type': 'string'}, 'name': {'type': 'string'}}, 'additionalProperties': False}}, 'ghsaUrl': {'type': 'string'}, 'summary': {'type': 'string'}, 'packages': {'type': 'array', 'items': {'type': 'object', 'required': ['name', 'affectedRange', 'patchedVersion'], 'properties': {'name': {'type': 'string'}, 'affectedRange': {'type': ['string', 'null']}, 'patchedVersion': {'type': ['string', 'null']}}, 'additionalProperties': False}}, 'severity': {'type': 'string'}, 'categories': {'type': 'array', 'items': {'type': 'string'}}, 'npmscanUrl': {'type': 'string'}, 'publishedAt': {'type': 'string'}}, 'additionalProperties': False}}, 'nextCursor': {'type': ['string', 'null']}}, 'additionalProperties': False}
get_maintainer_profile
Get basic profile info for an npm maintainer
Given an npm username, returns every package npm's own maintainer:<username> search index currently returns for that account (registry.npmjs.org's /-/v1/search — the public registry API has no dedicated 'list packages by maintainer' endpoint otherwise), plus precomputed aggregates: currentlyMaintainsCount (still listed as maintainer right now vs. already-revoked), totalWeeklyDownloads and totalDependents summed across every returned package, and avatarUrl — a proxied Gravatar image (null if no email is on record). This is a plain info lookup — it does NOT run the publish-cluster / compromised-account detection that check_maintainer_blast_radius does; use that tool instead when the goal is a security read on whether this account's recent activity looks like a takeover, not just a profile summary. Natural pairing with check_maintainer_changes: once that tool names a maintainer on a package, call this with that maintainer's username to see the rest of what they touch. npmscanUrl is this account's profile page on npmscan itself; npmProfileUrl is the account's actual page on npmjs.com, included for verification since that's the authoritative record of the account.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['maintainerUsername'], 'properties': {'maintainerUsername': {'type': 'string', 'maxLength': 100, 'minLength': 1, 'description': 'Exact npm username, e.g. "sindresorhus" â\x80\x94 as shown at npmjs.com/~username. Not an email address, not a package name or scope.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['maintainerUsername', 'npmscanUrl', 'npmProfileUrl', 'avatarUrl', 'totalPackagesFound', 'packagesReturned', 'resultsTruncated', 'currentlyMaintainsCount', 'totalWeeklyDownloads', 'totalDependents', 'packages', 'note'], 'properties': {'note': {'type': ['string', 'null']}, 'packages': {'type': 'array', 'items': {'type': 'object', 'required': ['name', 'version', 'lastPublished', 'weeklyDownloads', 'dependentsCount', 'isCurrentMaintainer', 'npmscanUrl'], 'properties': {'name': {'type': 'string'}, 'version': {'type': 'string'}, 'npmscanUrl': {'type': 'string'}, 'lastPublished': {'type': ['string', 'null']}, 'dependentsCount': {'type': ['number', 'null']}, 'weeklyDownloads': {'type': ['number', 'null']}, 'isCurrentMaintainer': {'type': 'boolean'}}, 'additionalProperties': False}}, 'avatarUrl': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'npmProfileUrl': {'type': 'string'}, 'totalDependents': {'type': 'number'}, 'packagesReturned': {'type': 'number'}, 'resultsTruncated': {'type': 'boolean'}, 'maintainerUsername': {'type': 'string'}, 'totalPackagesFound': {'type': 'number'}, 'totalWeeklyDownloads': {'type': 'number'}, 'currentlyMaintainsCount': {'type': 'number'}}, 'additionalProperties': False}
get_package
Get npm package details
Fetch npm registry metadata for a package: latest version, install scripts (preinstall/postinstall are a key risk signal), maintainers, license, recent version history, weekly downloads, GitHub stars, TypeScript support, days since last publish, a topPackagesRank (position among npm's ~100k most-downloaded packages, from npmscan's own periodically-refreshed snapshot — not live), and a downloadTrend (growing/stable/declining vs. ~3 months ago). Also checks the LATEST version against OSV.dev for known vulnerabilities — isLatestVersionVulnerable/highestSeverity give a direct safe/not-safe answer, and each finding includes severity, a summary, and the fixedVersion to upgrade to (use get_package_version or query_vulnerabilities to check a specific older version instead). If the OSV.dev query itself fails (network/timeout/upstream outage), isLatestVersionVulnerable comes back `false` only because the field has to be a boolean — vulnerabilityCheckFailed:true is the real signal there, and means the safe/not-safe answer is unknown, not confirmed clean. Also returns popularityTier/maintenanceTier (deterministic rule-based labels, not model-generated) and a plain-language maintenanceSummary, plus a possibleTyposquatOf flag if the name is one typo away from a top-5,000 package while itself being obscure — read `deprecated` and maintenanceSummary before recommending a package, since a long gap since the last release can mean either a stable/finished package or a slowing one. Includes a link to the full npmscan.com analysis page.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['name'], 'properties': {'name': {'type': 'string', 'maxLength': 214, 'minLength': 1, 'description': 'Exact npm package name, e.g. "lodash" or "@scope/name"'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['name', 'description', 'license', 'homepage', 'repository', 'keywords', 'maintainers', 'distTags', 'latestVersion', 'latestVersionInfo', 'recentVersions', 'createdAt', 'modifiedAt', 'npmscanUrl', 'weeklyDownloads', 'githubStars', 'hasBuiltInTypes', 'daysSinceLastPublish', 'popularityTier', 'maintenanceTier', 'maintenanceSummary', 'topPackagesRank', 'downloadTrend', 'possibleTyposquatOf', 'isLatestVersionVulnerable', 'vulnerabilityCheckFailed', 'highestSeverity', 'vulnerabilities'], 'properties': {'name': {'type': 'string'}, 'license': {'type': ['string', 'null']}, 'distTags': {'type': 'object', 'additionalProperties': {'type': 'string'}}, 'homepage': {'type': ['string', 'null']}, 'keywords': {'type': 'array', 'items': {'type': 'string'}}, 'createdAt': {'type': ['string', 'null']}, 'modifiedAt': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'repository': {'type': ['string', 'null']}, 'description': {'type': ['string', 'null']}, 'githubStars': {'type': ['number', 'null']}, 'maintainers': {'type': 'array', 'items': {'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string'}, 'email': {'type': 'string'}}, 'additionalProperties': False}}, 'downloadTrend': {'type': 'object', 'required': ['direction', 'changePercent'], 'properties': {'direction': {'enum': ['growing', 'stable', 'declining', 'unknown'], 'type': 'string'}, 'changePercent': {'type': ['number', 'null']}}, 'additionalProperties': False}, 'latestVersion': {'type': ['string', 'null']}, 'popularityTier': {'enum': ['very-high', 'high', 'moderate', 'low', 'very-low', 'unknown'], 'type': 'string'}, 'recentVersions': {'type': 'array', 'items': {'type': 'object', 'required': ['version', 'publishedAt'], 'properties': {'version': {'type': 'string'}, 'publishedAt': {'type': ['string', 'null']}}, 'additionalProperties': False}}, 'hasBuiltInTypes': {'type': 'boolean'}, 'highestSeverity': {'type': ['string', 'null']}, 'maintenanceTier': {'enum': ['active', 'aging', 'stale', 'unknown'], 'type': 'string'}, 'topPackagesRank': {'type': ['number', 'null']}, 'vulnerabilities': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'summary', 'severity', 'aliases', 'publishedAt', 'fixedVersion', 'npmscanUrl'], 'properties': {'id': {'type': 'string'}, 'aliases': {'type': 'array', 'items': {'type': 'string'}}, 'summary': {'type': ['string', 'null']}, 'severity': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'publishedAt': {'type': ['string', 'null']}, 'fixedVersion': {'type': ['string', 'null']}}, 'additionalProperties': False}}, 'weeklyDownloads': {'type': ['number', 'null']}, 'latestVersionInfo': {'anyOf': [{'type': 'object', 'required': ['version', 'dependencies', 'scripts', 'deprecated', 'tarball'], 'properties': {'scripts': {'type': 'object', 'additionalProperties': {'type': 'string'}}, 'tarball': {'type': ['string', 'null']}, 'version': {'type': 'string'}, 'deprecated': {'type': ['string', 'null']}, 'dependencies': {'type': 'object', 'additionalProperties': {'type': 'string'}}}, 'additionalProperties': False}, {'type': 'null'}]}, 'maintenanceSummary': {'type': 'string'}, 'possibleTyposquatOf': {'anyOf': [{'type': 'object', 'required': ['name', 'rank'], 'properties': {'name': {'type': 'string'}, 'rank': {'type': 'number'}}, 'additionalProperties': False}, {'type': 'null'}]}, 'daysSinceLastPublish': {'type': ['number', 'null']}, 'vulnerabilityCheckFailed': {'type': 'boolean'}, 'isLatestVersionVulnerable': {'type': 'boolean'}}, 'additionalProperties': False}
get_package_version
Get a specific npm package version
Fetch registry metadata for one exact version of a package (dependencies, install scripts, tarball) AND check that exact version against OSV.dev for known vulnerabilities — isVulnerable/highestSeverity give a direct answer, and each finding includes severity, a summary, and the fixedVersion to upgrade to. Use this to check a version pinned in a lockfile rather than the latest release. If the OSV.dev query itself fails (network/timeout/upstream outage), isVulnerable comes back `false` only because the field has to be a boolean — vulnerabilityCheckFailed:true is the real signal there, and means the answer is unknown, not confirmed clean.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['name', 'version'], 'properties': {'name': {'type': 'string', 'maxLength': 214, 'minLength': 1, 'description': 'Exact npm package name'}, 'version': {'type': 'string', 'maxLength': 128, 'minLength': 1, 'description': 'Exact version string, e.g. "4.17.21"'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['name', 'version', 'description', 'license', 'dependencies', 'scripts', 'deprecated', 'tarball', 'shasum', 'npmscanUrl', 'isVulnerable', 'vulnerabilityCheckFailed', 'highestSeverity', 'vulnerabilities'], 'properties': {'name': {'type': 'string'}, 'shasum': {'type': ['string', 'null']}, 'license': {'type': ['string', 'null']}, 'scripts': {'type': 'object', 'additionalProperties': {'type': 'string'}}, 'tarball': {'type': ['string', 'null']}, 'version': {'type': 'string'}, 'deprecated': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'description': {'type': ['string', 'null']}, 'dependencies': {'type': 'object', 'additionalProperties': {'type': 'string'}}, 'isVulnerable': {'type': 'boolean'}, 'highestSeverity': {'type': ['string', 'null']}, 'vulnerabilities': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'summary', 'severity', 'aliases', 'publishedAt', 'fixedVersion', 'npmscanUrl'], 'properties': {'id': {'type': 'string'}, 'aliases': {'type': 'array', 'items': {'type': 'string'}}, 'summary': {'type': ['string', 'null']}, 'severity': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'publishedAt': {'type': ['string', 'null']}, 'fixedVersion': {'type': ['string', 'null']}}, 'additionalProperties': False}}, 'vulnerabilityCheckFailed': {'type': 'boolean'}}, 'additionalProperties': False}
get_remediation_playbook
Get the concrete remediation playbook for a flagged finding
Maps a finding's `rule` value from analyze_install_script, check_maintainer_changes, or check_package_provenance to the matching human-authored incident-response playbook (the same content published at /docs/playbooks) and returns its concrete, ordered steps, severity tier, real-incident references, and prevention tips — not just a link. Pass the exact `rule` string(s) a prior finding already returned (batch up to 10 in one call to cover a whole findings array; duplicates resolving to the same playbook are deduplicated) or an `id` to look up a specific playbook by slug directly. Each matched rule also gets its own short situationNote explaining specifically what that rule caught — so a batch of several different rules landing on the same playbook does not read as identical, repeated boilerplate. An unrecognized rule or id is not an error — it comes back with matched:false and a note, since a low-severity or baseline-only finding (e.g. analyze_install_script's lifecycle-present) legitimately has no dedicated playbook.
Solo lectura
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'properties': {'id': {'type': 'string', 'maxLength': 64, 'minLength': 1, 'description': 'A playbook slug to look up directly, e.g. "postinstall-binary" â\x80\x94 see /docs/playbooks'}, 'rules': {'type': 'array', 'items': {'type': 'string', 'maxLength': 64, 'minLength': 1}, 'maxItems': 10, 'minItems': 1, 'description': '1-10 exact `rule` values copied from findings already returned by analyze_install_script/check_maintainer_changes/check_package_provenance'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['matches', 'playbooks'], 'properties': {'matches': {'type': 'array', 'items': {'type': 'object', 'required': ['rule', 'requestedId', 'matched', 'playbookId', 'situationNote', 'note'], 'properties': {'note': {'type': 'string'}, 'rule': {'type': ['string', 'null']}, 'matched': {'type': 'boolean'}, 'playbookId': {'type': ['string', 'null']}, 'requestedId': {'type': ['string', 'null']}, 'situationNote': {'type': ['string', 'null']}}, 'additionalProperties': False}}, 'playbooks': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'title', 'severity', 'steps', 'references', 'preventionTips', 'npmscanUrl'], 'properties': {'id': {'type': 'string'}, 'steps': {'type': 'array', 'items': {'type': 'object', 'required': ['text', 'why'], 'properties': {'why': {'type': ['string', 'null']}, 'text': {'type': 'string'}}, 'additionalProperties': False}}, 'title': {'type': 'string'}, 'severity': {'enum': ['critical', 'high', 'moderate', 'low'], 'type': 'string'}, 'npmscanUrl': {'type': 'string'}, 'references': {'type': 'array', 'items': {'type': 'object', 'required': ['label', 'url', 'kind'], 'properties': {'url': {'type': 'string'}, 'kind': {'enum': ['incident', 'reading'], 'type': 'string'}, 'label': {'type': 'string'}}, 'additionalProperties': False}}, 'preventionTips': {'type': 'array', 'items': {'type': 'string'}}}, 'additionalProperties': False}}}, 'additionalProperties': False}
prioritize_remediation
Rank a batch of flagged vulnerabilities by what to fix first
Given a batch of vulnerability findings already flagged elsewhere (e.g. from batch_query_vulnerabilities, analyze_transitive_dependencies, or query_vulnerabilities across a whole package.json/lockfile audit), ranks them by what to actually fix first. Combines CISA KEV status (confirmed active exploitation in the wild — an automatic top-priority override), FIRST.org EPSS (probability of exploitation in the next 30 days — the primary ranking signal, since it measures likelihood rather than just impact), and severity (a secondary/fallback signal, most useful for a GHSA finding with no CVE alias) into one composite score and a remove-now/patch-now/patch-soon/scheduled/monitor tier per finding. A finding with `findingType: "malware"` (or a MAL-* advisoryId, auto-detected even when findingType is omitted) always lands in `remove-now` — the tier above patch-now — regardless of score: a confirmed-malicious package needs removal/replacement, not an "urgent patch" (there often isn't a fixed version to patch TO), and EPSS/severity don't meaningfully apply to "how malicious" the way they do to a genuine vulnerability. When EPSS data isn't available at all (no CVE id, or a real CVE that just isn't in FIRST.org's database) severity becomes the sole usable signal and is scored on its own scale instead of being diluted to a ~10% sliver of the composite — a bare CRITICAL/HIGH GHSA finding with no CVE alias lands in patch-soon/scheduled, not monitor, the way it would if severity kept its normal secondary weight with nothing else to combine it with. This does NOT re-query OSV/NVD itself — pass in the severity/CVE id findings other tools already returned; it only adds KEV/EPSS enrichment (the same data get_cve returns per-CVE) and ranks the batch. A CVE id shared by multiple findings in the same call is only looked up once.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['findings'], 'properties': {'findings': {'type': 'array', 'items': {'type': 'object', 'required': ['packageName'], 'properties': {'cveId': {'type': 'string', 'pattern': '^CVE-\\d{4}-\\d{4,}$', 'description': 'Exact CVE ID, e.g. "CVE-2024-12345" â\x80\x94 enables CISA KEV + FIRST.org EPSS enrichment. Omit for a GHSA advisory with no CVE alias; the finding is still ranked by severity alone.'}, 'severity': {'type': 'string', 'maxLength': 32, 'description': 'Severity from the source finding (OSV/GHSA: CRITICAL/HIGH/MODERATE/LOW, or NVD: CRITICAL/HIGH/MEDIUM/LOW) â\x80\x94 used as a fallback/secondary signal'}, 'advisoryId': {'type': 'string', 'maxLength': 64, 'description': 'GHSA/OSV advisory id, passed through unchanged for reference â\x80\x94 a MAL-* id is auto-detected as malware even without findingType set'}, 'findingType': {'enum': ['malware', 'vulnerability', 'supply-chain', 'install-script'], 'type': 'string', 'description': '"malware" forces the remove-now tier regardless of score/CVE/severity â\x80\x94 set this (or pass a MAL-* advisoryId) for a confirmed-malicious package. Omit for an ordinary vulnerability finding.'}, 'packageName': {'type': 'string', 'maxLength': 214, 'minLength': 1, 'description': 'npm package name this finding was flagged against'}, 'fixedVersion': {'type': 'string', 'maxLength': 128, 'description': 'Version that fixes this finding, passed through unchanged'}, 'currentVersion': {'type': 'string', 'maxLength': 128, 'description': 'Currently installed version, passed through unchanged'}}, 'additionalProperties': False}, 'maxItems': 200, 'minItems': 1, 'description': '1-200 previously-flagged vulnerability findings to rank'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['totalFindings', 'uniqueCveCount', 'summary', 'ranked'], 'properties': {'ranked': {'type': 'array', 'items': {'type': 'object', 'required': ['rank', 'packageName', 'cveId', 'advisoryId', 'currentVersion', 'fixedVersion', 'severity', 'kev', 'epss', 'score', 'tier', 'findingType', 'reason', 'npmscanUrl', 'cveNpmscanUrl'], 'properties': {'kev': {'anyOf': [{'type': 'object', 'required': ['dateAdded', 'dueDate', 'knownRansomwareCampaignUse', 'requiredAction'], 'properties': {'dueDate': {'type': 'string'}, 'dateAdded': {'type': 'string'}, 'requiredAction': {'type': 'string'}, 'knownRansomwareCampaignUse': {'type': 'string'}}, 'additionalProperties': False}, {'type': 'null'}]}, 'epss': {'anyOf': [{'type': 'object', 'required': ['score', 'percentile', 'date'], 'properties': {'date': {'type': 'string'}, 'score': {'type': 'number'}, 'percentile': {'type': 'number'}}, 'additionalProperties': False}, {'type': 'null'}]}, 'rank': {'type': 'number'}, 'tier': {'enum': ['remove-now', 'patch-now', 'patch-soon', 'scheduled', 'monitor'], 'type': 'string'}, 'cveId': {'type': ['string', 'null']}, 'score': {'type': 'number'}, 'reason': {'type': 'string'}, 'severity': {'type': ['string', 'null']}, 'advisoryId': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'findingType': {'enum': ['malware', 'vulnerability', 'supply-chain', 'install-script'], 'type': 'string'}, 'packageName': {'type': 'string'}, 'fixedVersion': {'type': ['string', 'null']}, 'cveNpmscanUrl': {'type': ['string', 'null']}, 'currentVersion': {'type': ['string', 'null']}}, 'additionalProperties': False}}, 'summary': {'type': 'object', 'required': ['removeNow', 'patchNow', 'patchSoon', 'scheduled', 'monitor', 'kevListedCount'], 'properties': {'monitor': {'type': 'number'}, 'patchNow': {'type': 'number'}, 'patchSoon': {'type': 'number'}, 'removeNow': {'type': 'number'}, 'scheduled': {'type': 'number'}, 'kevListedCount': {'type': 'number'}}, 'additionalProperties': False}, 'totalFindings': {'type': 'number'}, 'uniqueCveCount': {'type': 'number'}}, 'additionalProperties': False}
query_vulnerabilities
Query known vulnerabilities for a package
Query OSV.dev for known vulnerabilities affecting an npm package, optionally scoped to one exact version (e.g. to check whether a version pinned in a lockfile is safe). Returns isVulnerable and highestSeverity as a direct answer, plus each finding's severity, a plain-language summary, CVE aliases, and the fixedVersion to upgrade to — not a raw advisory dump. Also cross-checks the name/version against the npm registry: isVulnerable:false on a package that does not actually exist there (typo, wrong ecosystem) would otherwise look identical to a genuinely clean result — see packageExists/existenceCheckNote. A name or version not found on the registry does NOT discard already-fetched OSV data or short-circuit into an error: OSV/GHSA advisory data is independent of the package's current registry listing, and a package/version pulled from npm for being malicious (unpublished/yanked) is exactly the case where real vulnerability data must still be reported, not hidden behind a 404. Use before recommending, installing, or upgrading a package.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['name'], 'properties': {'name': {'type': 'string', 'maxLength': 214, 'minLength': 1, 'description': 'npm package name'}, 'version': {'type': 'string', 'maxLength': 128, 'description': 'Optional exact version to narrow results, e.g. to check one version pinned in a lockfile'}, 'ecosystem': {'type': 'string', 'maxLength': 32, 'description': 'OSV ecosystem, default "npm"'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['package', 'version', 'npmscanUrl', 'packageExists', 'existenceCheckNote', 'isVulnerable', 'highestSeverity', 'vulnerabilities'], 'properties': {'package': {'type': 'string'}, 'version': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'isVulnerable': {'type': 'boolean'}, 'packageExists': {'type': ['boolean', 'null']}, 'highestSeverity': {'type': ['string', 'null']}, 'vulnerabilities': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'summary', 'severity', 'aliases', 'publishedAt', 'fixedVersion', 'npmscanUrl'], 'properties': {'id': {'type': 'string'}, 'aliases': {'type': 'array', 'items': {'type': 'string'}}, 'summary': {'type': ['string', 'null']}, 'severity': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'publishedAt': {'type': ['string', 'null']}, 'fixedVersion': {'type': ['string', 'null']}}, 'additionalProperties': False}}, 'existenceCheckNote': {'type': ['string', 'null']}}, 'additionalProperties': False}
search_packages
Search npm packages
Search the npm registry by name or keywords. Each result includes its current weekly/monthly download counts, dependentsCount (how many other npm packages depend on it), topPackagesRank (position among npmscan's own top-100k-by-downloads snapshot — not live, but a second independent popularity signal), and deterministic (not model-generated) popularityTier/maintenanceTier labels — a package matching the query with a 'very-low' popularityTier, zero dependents, or a 'stale' maintenanceTier is very likely an abandoned, copy-paste, or squatted package, not a real contender, regardless of how relevant its name/description look. A result may also carry possibleTyposquatOf — set when its name is one typo away (e.g. 'raect' vs 'react') from a top-5,000 package while itself having very low popularity; treat that as a red flag to call out explicitly, not silently filter. Use these (not name recognition or the package's own README) to judge which candidates are actually established, and call get_package on your shortlist for install-script risk, TypeScript support, and GitHub stars before recommending one. Includes a link to each package's full npmscan.com risk/analysis page.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['query'], 'properties': {'limit': {'type': 'integer', 'maximum': 50, 'minimum': 1, 'description': 'Max results to return (default 20, max 50)'}, 'query': {'type': 'string', 'maxLength': 64, 'minLength': 2, 'description': 'Search text, e.g. a package name or keywords'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['query', 'total', 'results'], 'properties': {'query': {'type': 'string'}, 'total': {'type': 'number'}, 'results': {'type': 'array', 'items': {'type': 'object', 'required': ['name', 'version', 'description', 'keywords', 'publisher', 'lastPublished', 'links', 'npmscanUrl', 'weeklyDownloads', 'monthlyDownloads', 'dependentsCount', 'topPackagesRank', 'popularityTier', 'maintenanceTier', 'possibleTyposquatOf'], 'properties': {'name': {'type': 'string'}, 'links': {'type': 'object', 'properties': {'npm': {'type': 'string'}, 'homepage': {'type': 'string'}, 'repository': {'type': 'string'}}, 'additionalProperties': False}, 'version': {'type': 'string'}, 'keywords': {'type': 'array', 'items': {'type': 'string'}}, 'publisher': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'description': {'type': ['string', 'null']}, 'lastPublished': {'type': ['string', 'null']}, 'popularityTier': {'enum': ['very-high', 'high', 'moderate', 'low', 'very-low', 'unknown'], 'type': 'string'}, 'dependentsCount': {'type': ['number', 'null']}, 'maintenanceTier': {'enum': ['active', 'aging', 'stale', 'unknown'], 'type': 'string'}, 'topPackagesRank': {'type': ['number', 'null']}, 'weeklyDownloads': {'type': ['number', 'null']}, 'monthlyDownloads': {'type': ['number', 'null']}, 'possibleTyposquatOf': {'anyOf': [{'type': 'object', 'required': ['name', 'rank'], 'properties': {'name': {'type': 'string'}, 'rank': {'type': 'number'}}, 'additionalProperties': False}, {'type': 'null'}]}}, 'additionalProperties': False}}}, 'additionalProperties': False}
simulate_dependency_upgrade
Simulate an npm dependency upgrade
Given a package and a current/target version, tells you whether that specific upgrade is a safe patch/minor bump or a likely-breaking major bump, before you actually run npm install. Natural follow-up to prioritize_remediation: pass its `packageName` + `currentVersion` + `fixedVersion` straight in to check whether the suggested fix is a drop-in patch or something that needs a review pass. Classifies the jump by semver (major/minor/patch/prerelease), treats a minor bump between two pre-1.0 (0.x) versions as breaking-risk per semver's own "the API isn't stable yet" convention, and flags skipping over multiple major versions in one jump (e.g. 2.x -> 5.x) as needing a per-major changelog review rather than just a diff against the final target. Beyond semver, it also checks the registry for real signals the version number alone won't tell you: whether the target version is marked deprecated, whether it introduces a preinstall/install/postinstall/prepare lifecycle script the current version didn't have, whether it tightens its engines.node requirement, and whether it is itself a prerelease. Finally it batch-checks both versions against OSV.dev and reports vulnerabilityDelta (introduced/fixed/still-vulnerable/still-clean) — catching the case where a suggested "fix" version doesn't actually clear every open CVE. Combines all of this into one riskTier (safe/low-risk/review-recommended/breaking-change-likely/unknown) with a reasons list explaining exactly which signals drove it. This does NOT read the package's changelog/release notes or scan the target tarball's source diff for actual breaking API usage — it's a fast, deterministic pre-check, not a substitute for reading the release notes on a flagged major bump. For simulating more than one upgrade at once — e.g. every "patch-now" finding prioritize_remediation just ranked — pass `packages: [{packageName, currentVersion, targetVersion?}, ...]` (1-100 items) instead of `packageName`/`currentVersion`/`targetVersion`, not both. Registry fetches are deduped/parallelized and all OSV checks for the whole batch run as one call, so this is not the same cost as N single-item calls. A package that can't be resolved at all (typo, unpublished, registry error) shows up as its own `results` entry with `fetchError` set instead of failing the whole batch.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'properties': {'packages': {'type': 'array', 'items': {'type': 'object', 'required': ['packageName', 'currentVersion'], 'properties': {'packageName': {'type': 'string', 'maxLength': 214, 'minLength': 1, 'description': 'Exact npm package name, e.g. "lodash" or "@scope/name"'}, 'targetVersion': {'type': 'string', 'maxLength': 128, 'minLength': 1, 'description': 'Version to simulate upgrading to â\x80\x94 exact version, range, or dist-tag. Omit to use the registry\'s "latest" dist-tag.'}, 'currentVersion': {'type': 'string', 'maxLength': 128, 'minLength': 1, 'description': 'Currently installed version â\x80\x94 an exact version, a semver range, or a dist-tag'}}, 'additionalProperties': False}, 'maxItems': 100, 'minItems': 1, 'description': 'Batch of upgrades to simulate (1-100 items), each mirroring the single-item packageName/currentVersion/targetVersion fields. Use this OR packageName/currentVersion, not both. Natural pairing with prioritize_remediation: pass its ranked findings straight in as one call instead of one simulate_dependency_upgrade call per finding.'}, 'packageName': {'type': 'string', 'maxLength': 214, 'minLength': 1, 'description': 'Exact npm package name, e.g. "lodash" or "@scope/name". Use this (with currentVersion) OR `packages`, not both.'}, 'targetVersion': {'type': 'string', 'maxLength': 128, 'minLength': 1, 'description': 'Version to simulate upgrading to â\x80\x94 exact version, range, or dist-tag (e.g. the fixedVersion a prioritize_remediation finding named). Omit to use the registry\'s "latest" dist-tag. Only applies to the single-item `packageName` form.'}, 'currentVersion': {'type': 'string', 'maxLength': 128, 'minLength': 1, 'description': 'Currently installed version â\x80\x94 an exact version (e.g. "4.17.20"), a semver range (e.g. "^4.17.0"), or a dist-tag. Required when `packageName` is used.'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'properties': {'reasons': {'type': 'array', 'items': {'type': 'string'}}, 'results': {'type': 'array', 'items': {'type': 'object', 'required': ['packageName', 'npmscanUrl', 'requestedCurrentVersion', 'requestedTargetVersion', 'resolvedCurrentVersion', 'resolvedTargetVersion', 'currentVersionNote', 'targetVersionNote', 'direction', 'semverBump', 'isBreakingBySemver', 'majorVersionsSkipped', 'zeroMajorNote', 'targetIsPrerelease', 'targetDeprecated', 'installScriptIntroduced', 'engineChange', 'currentIsVulnerable', 'targetIsVulnerable', 'vulnerabilityDelta', 'targetVulnerabilities', 'riskTier', 'reasons', 'verdict', 'fetchError'], 'properties': {'reasons': {'type': 'array', 'items': {'type': 'string'}}, 'verdict': {'type': 'string'}, 'riskTier': {'enum': ['safe', 'low-risk', 'review-recommended', 'breaking-change-likely', 'unknown'], 'type': 'string'}, 'direction': {'enum': ['upgrade', 'downgrade', 'same', 'unresolved'], 'type': 'string'}, 'fetchError': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'semverBump': {'anyOf': [{'enum': ['major', 'premajor', 'minor', 'preminor', 'patch', 'prepatch', 'prerelease'], 'type': 'string'}, {'type': 'null'}]}, 'packageName': {'type': 'string'}, 'engineChange': {'anyOf': [{'type': 'object', 'required': ['before', 'after', 'tightened'], 'properties': {'after': {'type': ['string', 'null']}, 'before': {'type': ['string', 'null']}, 'tightened': {'type': 'boolean'}}, 'additionalProperties': False}, {'type': 'null'}]}, 'zeroMajorNote': {'type': ['string', 'null']}, 'targetDeprecated': {'type': ['string', 'null']}, 'targetVersionNote': {'type': ['string', 'null']}, 'currentVersionNote': {'type': ['string', 'null']}, 'isBreakingBySemver': {'type': ['boolean', 'null']}, 'targetIsPrerelease': {'type': ['boolean', 'null']}, 'targetIsVulnerable': {'type': ['boolean', 'null']}, 'vulnerabilityDelta': {'anyOf': [{'enum': ['introduced', 'fixed', 'still-vulnerable', 'still-clean', 'unknown'], 'type': 'string'}, {'type': 'null'}]}, 'currentIsVulnerable': {'type': ['boolean', 'null']}, 'majorVersionsSkipped': {'type': ['number', 'null']}, 'resolvedTargetVersion': {'type': ['string', 'null']}, 'targetVulnerabilities': {'type': 'array', 'items': {'$ref': '#/properties/targetVulnerabilities/items'}}, 'requestedTargetVersion': {'type': 'string'}, 'resolvedCurrentVersion': {'type': ['string', 'null']}, 'installScriptIntroduced': {'type': ['boolean', 'null']}, 'requestedCurrentVersion': {'type': 'string'}}, 'additionalProperties': False}}, 'verdict': {'type': 'string'}, 'riskTier': {'enum': ['safe', 'low-risk', 'review-recommended', 'breaking-change-likely', 'unknown'], 'type': 'string'}, 'direction': {'enum': ['upgrade', 'downgrade', 'same', 'unresolved'], 'type': 'string'}, 'npmscanUrl': {'type': 'string'}, 'semverBump': {'anyOf': [{'enum': ['major', 'premajor', 'minor', 'preminor', 'patch', 'prepatch', 'prerelease'], 'type': 'string'}, {'type': 'null'}]}, 'packageName': {'type': 'string'}, 'batchSummary': {'type': 'object', 'required': ['totalRequested', 'fetchFailedCount', 'riskTierCounts', 'vulnQueryFailedCount'], 'properties': {'riskTierCounts': {'type': 'object', 'required': ['safe', 'lowRisk', 'reviewRecommended', 'breakingChangeLikely', 'unknown'], 'properties': {'safe': {'type': 'number'}, 'lowRisk': {'type': 'number'}, 'unknown': {'type': 'number'}, 'reviewRecommended': {'type': 'number'}, 'breakingChangeLikely': {'type': 'number'}}, 'additionalProperties': False}, 'totalRequested': {'type': 'number'}, 'fetchFailedCount': {'type': 'number'}, 'vulnQueryFailedCount': {'type': 'number'}}, 'additionalProperties': False}, 'engineChange': {'anyOf': [{'type': 'object', 'required': ['before', 'after', 'tightened'], 'properties': {'after': {'type': ['string', 'null']}, 'before': {'type': ['string', 'null']}, 'tightened': {'type': 'boolean'}}, 'additionalProperties': False}, {'type': 'null'}]}, 'zeroMajorNote': {'type': ['string', 'null']}, 'targetDeprecated': {'type': ['string', 'null']}, 'targetVersionNote': {'type': ['string', 'null']}, 'currentVersionNote': {'type': ['string', 'null']}, 'isBreakingBySemver': {'type': ['boolean', 'null']}, 'targetIsPrerelease': {'type': ['boolean', 'null']}, 'targetIsVulnerable': {'type': ['boolean', 'null']}, 'vulnerabilityDelta': {'anyOf': [{'enum': ['introduced', 'fixed', 'still-vulnerable', 'still-clean', 'unknown'], 'type': 'string'}, {'type': 'null'}]}, 'currentIsVulnerable': {'type': ['boolean', 'null']}, 'majorVersionsSkipped': {'type': ['number', 'null']}, 'resolvedTargetVersion': {'type': ['string', 'null']}, 'targetVulnerabilities': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'summary', 'severity', 'aliases', 'publishedAt', 'fixedVersion', 'npmscanUrl'], 'properties': {'id': {'type': 'string'}, 'aliases': {'type': 'array', 'items': {'type': 'string'}}, 'summary': {'type': ['string', 'null']}, 'severity': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'publishedAt': {'type': ['string', 'null']}, 'fixedVersion': {'type': ['string', 'null']}}, 'additionalProperties': False}}, 'requestedTargetVersion': {'type': 'string'}, 'resolvedCurrentVersion': {'type': ['string', 'null']}, 'installScriptIntroduced': {'type': ['boolean', 'null']}, 'requestedCurrentVersion': {'type': 'string'}}, 'additionalProperties': False}
suggest_alternative
Suggest better-maintained npm alternatives
Given a package that looks deprecated, vulnerable, abandoned, or suspicious, suggest better-maintained alternatives in the same category. This tool first checks the source package's own latest-version health (deprecation, latest-version OSV verdict, popularity/maintenance tiers, typosquat flag), then combines maintainer-provided deprecation hints with deterministic npm search-based category matching. It ranks candidates using category overlap plus search_packages-style popularity/maintenance signals, filters out typosquats and weak/stale contenders, and returns a short list with plain-language whySuggested notes. A candidate is also never suggested if it's deprecated, has a confirmed HIGH/CRITICAL OSV vulnerability, or its own OSV check itself failed (network/timeout/upstream outage) — an unverifiable candidate is excluded the same as a confirmed-bad one, not defaulted to 'looks fine', since this tool's entire purpose is not recommending something dangerous. Best for turning a 'don't use this package' warning into an actionable replacement shortlist. If the OSV.dev vulnerability check fails for the SOURCE package (as opposed to a candidate, which gets excluded per above), source.isLatestVersionVulnerable comes back `false` only because the field has to be a boolean — source.vulnerabilityCheckFailed:true is the real signal there, and means that safe/not-safe answer is unknown, not confirmed clean.
Solo lectura Acceso externo
Esquema de entrada
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['name'], 'properties': {'name': {'type': 'string', 'maxLength': 214, 'minLength': 1, 'description': 'Exact npm package name, e.g. "request" or "node-sass"'}, 'limit': {'type': 'integer', 'maximum': 10, 'minimum': 1, 'description': 'Max suggestions to return (default 5, max 10)'}, 'reason': {'enum': ['deprecated', 'vulnerable', 'abandoned', 'typosquat', 'general'], 'type': 'string', 'description': 'Optional reason to bias filtering/ranking'}}, 'additionalProperties': False}
Esquema de salida
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['source', 'reason', 'confidence', 'categoryTokens', 'searchedQueries', 'nonPackageAlternatives', 'suggestions'], 'properties': {'reason': {'enum': ['deprecated', 'vulnerable', 'abandoned', 'typosquat', 'general'], 'type': 'string'}, 'source': {'type': 'object', 'required': ['name', 'latestVersion', 'deprecated', 'isLatestVersionVulnerable', 'vulnerabilityCheckFailed', 'highestSeverity', 'popularityTier', 'maintenanceTier', 'possibleTyposquatOf', 'npmscanUrl'], 'properties': {'name': {'type': 'string'}, 'deprecated': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'latestVersion': {'type': ['string', 'null']}, 'popularityTier': {'enum': ['very-high', 'high', 'moderate', 'low', 'very-low', 'unknown'], 'type': 'string'}, 'highestSeverity': {'type': ['string', 'null']}, 'maintenanceTier': {'enum': ['active', 'aging', 'stale', 'unknown'], 'type': 'string'}, 'possibleTyposquatOf': {'anyOf': [{'type': 'object', 'required': ['name', 'rank'], 'properties': {'name': {'type': 'string'}, 'rank': {'type': 'number'}}, 'additionalProperties': False}, {'type': 'null'}]}, 'vulnerabilityCheckFailed': {'type': 'boolean'}, 'isLatestVersionVulnerable': {'type': 'boolean'}}, 'additionalProperties': False}, 'confidence': {'enum': ['high', 'medium', 'low'], 'type': 'string'}, 'suggestions': {'type': 'array', 'items': {'type': 'object', 'required': ['name', 'version', 'description', 'npmscanUrl', 'weeklyDownloads', 'dependentsCount', 'githubStars', 'hasBuiltInTypes', 'deprecated', 'isLatestVersionVulnerable', 'vulnerabilityCheckFailed', 'highestSeverity', 'popularityTier', 'maintenanceTier', 'topPackagesRank', 'categoryOverlap', 'matchedQueries', 'whySuggested'], 'properties': {'name': {'type': 'string'}, 'version': {'type': ['string', 'null']}, 'deprecated': {'type': ['string', 'null']}, 'npmscanUrl': {'type': 'string'}, 'description': {'type': ['string', 'null']}, 'githubStars': {'type': ['number', 'null']}, 'whySuggested': {'type': 'string'}, 'matchedQueries': {'type': 'array', 'items': {'type': 'string'}}, 'popularityTier': {'enum': ['very-high', 'high', 'moderate', 'low', 'very-low', 'unknown'], 'type': 'string'}, 'categoryOverlap': {'type': 'array', 'items': {'type': 'string'}}, 'dependentsCount': {'type': ['number', 'null']}, 'hasBuiltInTypes': {'type': 'boolean'}, 'highestSeverity': {'type': ['string', 'null']}, 'maintenanceTier': {'enum': ['active', 'aging', 'stale', 'unknown'], 'type': 'string'}, 'topPackagesRank': {'type': ['number', 'null']}, 'weeklyDownloads': {'type': ['number', 'null']}, 'vulnerabilityCheckFailed': {'type': 'boolean'}, 'isLatestVersionVulnerable': {'type': 'boolean'}}, 'additionalProperties': False}}, 'categoryTokens': {'type': 'array', 'items': {'type': 'string'}}, 'searchedQueries': {'type': 'array', 'items': {'type': 'string'}}, 'nonPackageAlternatives': {'type': 'array', 'items': {'type': 'string'}}}, 'additionalProperties': False}
Modificado
simulate_dependency_upgrade
1 de October de 2026 a las 02:50
Modificado
check_maintainer_blast_radius
1 de October de 2026 a las 02:50
Modificado
check_maintainer_changes
1 de October de 2026 a las 02:50
Modificado
get_latest_advisories
1 de October de 2026 a las 02:50
Modificado
get_maintainer_profile
1 de October de 2026 a las 02:50
Modificado
enrich_npm_audit
27 de September de 2026 a las 02:49
Modificado
enrich_npm_audit
25 de September de 2026 a las 02:58
Modificado
batch_query_vulnerabilities
25 de September de 2026 a las 02:58
Modificado
compare_packages
23 de September de 2026 a las 02:49
Modificado
suggest_alternative
23 de September de 2026 a las 02:49
Modificado
get_cve
23 de September de 2026 a las 02:49
Modificado
get_package_version
23 de September de 2026 a las 02:49
Modificado
get_package
23 de September de 2026 a las 02:49
Modificado
generate_sbom
21 de September de 2026 a las 02:56
Modificado
audit_github_repository
21 de September de 2026 a las 02:56
Modificado
prioritize_remediation
21 de September de 2026 a las 02:56
Modificado
diff_dependencies
21 de September de 2026 a las 02:56
Modificado
analyze_transitive_dependencies
21 de September de 2026 a las 02:56
Modificado
batch_query_vulnerabilities
21 de September de 2026 a las 02:56
Modificado
query_vulnerabilities
21 de September de 2026 a las 02:56
Modificado
diff_dependencies
19 de September de 2026 a las 02:47
Modificado
batch_query_vulnerabilities
19 de September de 2026 a las 02:47
Añadido
enrich_npm_audit
17 de September de 2026 a las 12:52
Añadido
generate_sbom
17 de September de 2026 a las 12:52
Añadido
get_remediation_playbook
17 de September de 2026 a las 12:52
Añadido
audit_github_repository
17 de September de 2026 a las 12:52
Añadido
compare_packages
17 de September de 2026 a las 12:52
Añadido
suggest_alternative
17 de September de 2026 a las 12:52
Añadido
simulate_dependency_upgrade
17 de September de 2026 a las 12:52
Añadido
prioritize_remediation
17 de September de 2026 a las 12:52

hyperion

com.thetempleofdoom.hyperion/hyperion

Acts as a paid MCP tool marketplace and utility gateway with server discovery, HTTP and JavaScript tools, research, data conversi…

Vee3

io.github.Vee3io/vee3

Manages Clerk authentication infrastructure, including users, organizations, domains, sessions, tokens, OAuth, SSO, machines, per…

IA-QA — 130+ QA & Dev Tools for AI Agents

io.github.JcJamet/ia-qa-toolbox

Provides deterministic QA, evaluation, testing, code analysis, prompt and RAG checks, model comparison, and web security diagnost…

validoria-mcp

com.validoria/validoria-mcp

Runs continuous website, API, and webshop tests covering security, SEO, performance, accessibility, browser journeys, and inciden…

HubVibe: Pay-per-Call Tools for AI Agents: Web Search, Email Verify, KYC, Stocks, Crypto, News, Data

io.github.Its-fortunatefolly/hubvibe

Offers paid utilities for web audits, HTTP fetching and extraction, BigQuery analysis, LLM processing, code execution, blockchain…

developer-tools

net.programmes/developer-tools

Provides general-purpose developer utilities for encoding, hashing, encryption, JSON, HTML, CSS, networking, and related data tra…

Qiniso

io.github.qinisolabs/qiniso

Provides deterministic formatting, parsing, holiday and tax lookups, address handling, and checksum or structure validation for i…

ContrastAPI

com.contrastcyber/api

Provides security research and assessment tools covering CVEs, IOCs, dependencies, secrets, injection risks, HTTP headers, domain…