{"id":79421,"date":"2026-04-17T09:32:04","date_gmt":"2026-04-17T04:02:04","guid":{"rendered":"https:\/\/www.tothenew.com\/blog\/?p=79421"},"modified":"2026-04-22T11:26:52","modified_gmt":"2026-04-22T05:56:52","slug":"vulnerability-detection-using-osv-dev-terminal-only-approach","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/vulnerability-detection-using-osv-dev-terminal-only-approach\/","title":{"rendered":"Vulnerability Detection Using OSV.dev (Terminal-Only Approach)"},"content":{"rendered":"<h1>Introduction<\/h1>\n<p>Modern JavaScript applications\u2014especially React Native\u2014depend on hundreds of npm packages. The real risk isn\u2019t just outdated packages, but <strong>hidden vulnerabilities inside your dependency tree.<\/strong><\/p>\n<p>Traditional tools like npm audit often overwhelm developers with noisy output and low-context alerts. What we actually need is:<\/p>\n<ul>\n<li>Accurate vulnerability detection<\/li>\n<li>Minimal noise<\/li>\n<li>Actionable output<\/li>\n<\/ul>\n<p>This is where <strong>OSV.dev (Open Source Vulnerabilities)<\/strong> comes in.<\/p>\n<h1>\u00a0Why OSV.dev?<\/h1>\n<p>OSV.dev provides a <strong>unified vulnerability database<\/strong> that aggregates data from multiple ecosystems and security sources.<\/p>\n<p>Unlike traditional tools:<\/p>\n<ul>\n<li>It focuses on <strong>real known vulnerabilities<\/strong><\/li>\n<li>It supports <strong>precise version matching<\/strong><\/li>\n<li>It reduces false positives<\/li>\n<\/ul>\n<p>It has already flagged multiple malicious npm packages like:<\/p>\n<ul>\n<li>react-native-website \u2192 malicious code injected<\/li>\n<li>react-native-latest \u2192 executes suspicious commands<\/li>\n<li>react-native-show-message-extension \u2192 compromised package<\/li>\n<\/ul>\n<p>This proves one thing: you cannot trust dependencies blindly anymore.<\/p>\n<h1>How Vulnerability Detection Works<\/h1>\n<p>The process is simple but powerful:<\/p>\n<ol>\n<li>Read all installed dependencies<\/li>\n<li>Extract exact versions (not ranges)<\/li>\n<li>Send them to OSV.dev API<\/li>\n<li>Check if vulnerabilities exist<\/li>\n<li>Show ONLY affected packages<\/li>\n<\/ol>\n<h1>Step 1: Read Installed Packages<\/h1>\n<p>We extract dependencies directly from:<\/p>\n<ul>\n<li>package.json<\/li>\n<li>node_modules (for exact installed version)<\/li>\n<\/ul>\n<h2>\u00a0readPackages.js<\/h2>\n<pre><span style=\"color: #339966;\">const fs = require(\"fs\");<\/span>\r\n<span style=\"color: #339966;\">const path = require(\"path\");<\/span>\r\n\r\n<span style=\"color: #339966;\">function getInstalledPackages(projectRoot) {<\/span>\r\n<span style=\"color: #339966;\">const pkgPath = path.join(projectRoot, \"package.json\");<\/span>\r\n<span style=\"color: #339966;\">const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf8\"));<\/span>\r\n\r\n<span style=\"color: #339966;\">const allDeps = {<\/span>\r\n<span style=\"color: #339966;\">...pkg.dependencies,<\/span>\r\n<span style=\"color: #339966;\">...pkg.devDependencies,<\/span>\r\n<span style=\"color: #339966;\">};<\/span>\r\n\r\n<span style=\"color: #339966;\">const result = [];<\/span>\r\n\r\n<span style=\"color: #339966;\">for (const dep of Object.keys(allDeps)) {<\/span>\r\n<span style=\"color: #339966;\">try {<\/span>\r\n<span style=\"color: #339966;\">const depPkgPath = path.join(<\/span>\r\n<span style=\"color: #339966;\">projectRoot,<\/span>\r\n<span style=\"color: #339966;\">\"node_modules\",<\/span>\r\n<span style=\"color: #339966;\">dep,<\/span>\r\n<span style=\"color: #339966;\">\"package.json\"<\/span>\r\n<span style=\"color: #339966;\">);<\/span>\r\n\r\n<span style=\"color: #339966;\">if (fs.existsSync(depPkgPath)) {<\/span>\r\n<span style=\"color: #339966;\">const depPkg = JSON.parse(fs.readFileSync(depPkgPath, \"utf8\"));<\/span>\r\n\r\n<span style=\"color: #339966;\">result.push({<\/span>\r\n<span style=\"color: #339966;\">name: dep,<\/span>\r\n<span style=\"color: #339966;\">version: depPkg.version,<\/span>\r\n<span style=\"color: #339966;\">});<\/span>\r\n<span style=\"color: #339966;\">}<\/span>\r\n<span style=\"color: #339966;\">} catch (err) {<\/span>\r\n<span style=\"color: #339966;\">\/\/ ignore broken deps<\/span>\r\n<span style=\"color: #339966;\">}<\/span>\r\n<span style=\"color: #339966;\">}<\/span>\r\n\r\n<span style=\"color: #339966;\">return result;<\/span>\r\n<span style=\"color: #339966;\">}<\/span>\r\n\r\n<span style=\"color: #339966;\">module.exports = { getInstalledPackages };<\/span><\/pre>\n<h1>Step 2: Check Vulnerabilities via OSV<\/h1>\n<p>We call OSV\u2019s batch API:<\/p>\n<p>https:\/\/api.osv.dev\/v1\/querybatch<\/p>\n<p>This allows us to check multiple packages at once.<\/p>\n<h2>\u00a0osvSecurity.js<\/h2>\n<pre><span style=\"color: #339966;\">const OSV_API = \"https:\/\/api.osv.dev\/v1\/querybatch\";<\/span>\r\n\r\n<span style=\"color: #339966;\">async function checkVulnerabilities(packages) {<\/span>\r\n<span style=\"color: #339966;\">const queries = packages.map((pkg) =&gt; ({<\/span>\r\n<span style=\"color: #339966;\">package: {<\/span>\r\n<span style=\"color: #339966;\">name: pkg.name,<\/span>\r\n<span style=\"color: #339966;\">ecosystem: \"npm\",<\/span>\r\n<span style=\"color: #339966;\">},<\/span>\r\n<span style=\"color: #339966;\">version: pkg.version,<\/span>\r\n<span style=\"color: #339966;\">}));<\/span>\r\n\r\n<span style=\"color: #339966;\">const response = await fetch(OSV_API, {<\/span>\r\n<span style=\"color: #339966;\">method: \"POST\",<\/span>\r\n<span style=\"color: #339966;\">headers: {<\/span>\r\n<span style=\"color: #339966;\">\"Content-Type\": \"application\/json\",<\/span>\r\n<span style=\"color: #339966;\">},<\/span>\r\n<span style=\"color: #339966;\">body: JSON.stringify({ queries }),<\/span>\r\n<span style=\"color: #339966;\">});<\/span>\r\n\r\n<span style=\"color: #339966;\">const data = await response.json();<\/span>\r\n\r\n<span style=\"color: #339966;\">const vulnerablePackages = [];<\/span>\r\n\r\n<span style=\"color: #339966;\">data.results.forEach((result, index) =&gt; {<\/span>\r\n<span style=\"color: #339966;\">if (result.vulns &amp;&amp; result.vulns.length &gt; 0) {<\/span>\r\n<span style=\"color: #339966;\">vulnerablePackages.push({<\/span>\r\n<span style=\"color: #339966;\">name: packages[index].name,<\/span>\r\n<span style=\"color: #339966;\">version: packages[index].version,<\/span>\r\n<span style=\"color: #339966;\">vulnerabilities: result.vulns.map((v) =&gt; ({<\/span>\r\n<span style=\"color: #339966;\">id: v.id,<\/span>\r\n<span style=\"color: #339966;\">summary: v.summary,<\/span>\r\n<span style=\"color: #339966;\">severity: v.severity || \"UNKNOWN\",<\/span>\r\n<span style=\"color: #339966;\">})),<\/span>\r\n<span style=\"color: #339966;\">});<\/span>\r\n<span style=\"color: #339966;\">}<\/span>\r\n<span style=\"color: #339966;\">});<\/span>\r\n\r\n<span style=\"color: #339966;\">return vulnerablePackages;<\/span>\r\n<span style=\"color: #339966;\">}<\/span>\r\n\r\n<span style=\"color: #339966;\">module.exports = { checkVulnerabilities };<\/span><\/pre>\n<h1>\ud83d\udcc4 checkVulnerabilities.js (FINAL SCRIPT)<\/h1>\n<pre><span style=\"color: #339966;\">#!\/usr\/bin\/env node<\/span>\r\n\r\n<span style=\"color: #339966;\">const path = require(\"path\");<\/span>\r\n<span style=\"color: #339966;\">const { getInstalledPackages } = require(\".\/readPackages\");<\/span>\r\n<span style=\"color: #339966;\">const { checkVulnerabilities } = require(\".\/osvSecurity\");<\/span>\r\n\r\n<span style=\"color: #339966;\">const PROJECT_ROOT = process.cwd();<\/span>\r\n\r\n<span style=\"color: #339966;\">async function run() {<\/span>\r\n<span style=\"color: #339966;\">console.log(\"\ud83d\udd0d Scanning for vulnerabilities...\\n\");<\/span>\r\n\r\n<span style=\"color: #339966;\">const packages = getInstalledPackages(PROJECT_ROOT);<\/span>\r\n\r\n<span style=\"color: #339966;\">if (!packages.length) {<\/span>\r\n<span style=\"color: #339966;\">console.log(\"No packages found.\");<\/span>\r\n<span style=\"color: #339966;\">return;<\/span>\r\n<span style=\"color: #339966;\">}<\/span>\r\n\r\n<span style=\"color: #339966;\">const vulnerable = await checkVulnerabilities(packages);<\/span>\r\n\r\n<span style=\"color: #339966;\">if (!vulnerable.length) {<\/span>\r\n<span style=\"color: #339966;\">console.log(\"\u2705 No vulnerabilities found.\");<\/span>\r\n<span style=\"color: #339966;\">return;<\/span>\r\n<span style=\"color: #339966;\">}<\/span>\r\n\r\n<span style=\"color: #339966;\">console.log(\"\ud83d\udea8 Vulnerable Packages Found:\\n\");<\/span>\r\n\r\n<span style=\"color: #339966;\">vulnerable.forEach((pkg) =&gt; {<\/span>\r\n<span style=\"color: #339966;\">console.log(`\ud83d\udce6 ${pkg.name}@${pkg.version}`);<\/span>\r\n\r\n<span style=\"color: #339966;\">pkg.vulnerabilities.forEach((vuln) =&gt; {<\/span>\r\n<span style=\"color: #339966;\">console.log(` \u26a0\ufe0f ${vuln.id}`);<\/span>\r\n<span style=\"color: #339966;\">console.log(` \ud83d\udcdd ${vuln.summary || \"No description\"}`);<\/span>\r\n<span style=\"color: #339966;\">console.log(` \ud83d\udd25 Severity: ${vuln.severity}`);<\/span>\r\n<span style=\"color: #339966;\">console.log(\"\");<\/span>\r\n<span style=\"color: #339966;\">});<\/span>\r\n<span style=\"color: #339966;\">});<\/span>\r\n<span style=\"color: #339966;\">}<\/span>\r\n\r\n<span style=\"color: #339966;\">run().catch((err) =&gt; {<\/span>\r\n<span style=\"color: #339966;\">console.error(\"Error:\", err.message);<\/span>\r\n<span style=\"color: #339966;\">});<\/span><\/pre>\n<h1>How to Run<\/h1>\n<p>Install dependency:<\/p>\n<pre><span style=\"color: #339966;\">npm install node-fetch<\/span><\/pre>\n<p>Run:<\/p>\n<pre><span style=\"color: #339966;\">node checkVulnerabilities.js<\/span><\/pre>\n<h1>Sample Output<\/h1>\n<p>\ud83d\udd0d Scanning for vulnerabilities&#8230;<\/p>\n<p>\ud83d\udea8 Vulnerable Packages Found:<\/p>\n<p>\ud83d\udce6 lodash@4.17.15<br \/>\n\u26a0\ufe0f GHSA-xxxx<br \/>\n\ud83d\udcdd Prototype Pollution vulnerability<br \/>\n\ud83d\udd25 Severity: HIGH<\/p>\n<p>\ud83d\udce6 minimist@0.0.8<br \/>\n\u26a0\ufe0f GHSA-yyyy<br \/>\n\ud83d\udcdd Arbitrary code execution issue<br \/>\n\ud83d\udd25 Severity: CRITICAL<\/p>\n<p>&nbsp;<\/p>\n<div id=\"attachment_79469\" style=\"width: 1144px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-79469\" decoding=\"async\" loading=\"lazy\" class=\"size-full wp-image-79469\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2026\/04\/Screenshot-2026-04-06-at-10.56.08\u202fPM.png\" alt=\"vulnerablePackages\" width=\"1134\" height=\"392\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2026\/04\/Screenshot-2026-04-06-at-10.56.08\u202fPM.png 1134w, \/blog\/wp-ttn-blog\/uploads\/2026\/04\/Screenshot-2026-04-06-at-10.56.08\u202fPM-300x104.png 300w, \/blog\/wp-ttn-blog\/uploads\/2026\/04\/Screenshot-2026-04-06-at-10.56.08\u202fPM-1024x354.png 1024w, \/blog\/wp-ttn-blog\/uploads\/2026\/04\/Screenshot-2026-04-06-at-10.56.08\u202fPM-768x265.png 768w, \/blog\/wp-ttn-blog\/uploads\/2026\/04\/Screenshot-2026-04-06-at-10.56.08\u202fPM-624x216.png 624w\" sizes=\"(max-width: 1134px) 100vw, 1134px\" \/><p id=\"caption-attachment-79469\" class=\"wp-caption-text\">vulnerablePackages<\/p><\/div>\n<h1>Final Thought<\/h1>\n<p>Dependency security is no longer optional.<\/p>\n<p>With real-world incidents of malicious npm packages and even critical RCE vulnerabilities in widely used tools, relying on blind trust is risky.<\/p>\n<p>A simple terminal-based vulnerability scanner like this gives you:<\/p>\n<ul>\n<li>Immediate visibility<\/li>\n<li>Zero noise<\/li>\n<li>Real security insights<\/li>\n<\/ul>\n<p>If it\u2019s not secure, it should be visible instantly.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Modern JavaScript applications\u2014especially React Native\u2014depend on hundreds of npm packages. The real risk isn\u2019t just outdated packages, but hidden vulnerabilities inside your dependency tree. Traditional tools like npm audit often overwhelm developers with noisy output and low-context alerts. What we actually need is: Accurate vulnerability detection Minimal noise Actionable output This is where OSV.dev [&hellip;]<\/p>\n","protected":false},"author":1816,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":4},"categories":[5881],"tags":[1303,8570,5853,8569],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/79421"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/1816"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=79421"}],"version-history":[{"count":3,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/79421\/revisions"}],"predecessor-version":[{"id":79668,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/79421\/revisions\/79668"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=79421"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=79421"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=79421"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}