We Scanned Ourselves: 86 Vulnerabilities Found (and Fixed) with OtterSight
We used OtterSight's MCP server to scan our own monorepo. Found 86 vulnerabilities — 5 critical, 1 actively exploited. Fixed all of them. Here's exactly what happened.
We built an MCP server so AI assistants can run OtterSight scans inside your editor. The first thing we did with it was scan ourselves.
86 vulnerabilities. 5 critical. 1 actively exploited.
This is the full story of what we found, what was real, what was noise, and how we fixed it.
Phase 12: OtterSight Gets an MCP Server
Model Context Protocol (MCP) is the open standard for connecting AI assistants to external tools. If you use Claude Code, Cursor, Windsurf, or any MCP-compatible editor, you can now run OtterSight scans without leaving your conversation.
We shipped @ottersight/mcp with three tools:
scan— run a full SBOM + vulnerability scan on any local projectlookup-euvd— query the EU Vulnerability Database for a specific CVEcheck-kev— check if a CVE is on CISA’s Known Exploited Vulnerabilities list
The idea is simple: your AI assistant already helps you write code and review PRs. Now it can also check whether the dependencies you’re pulling in have known vulnerabilities — using live data, not training data.
The Scan: /ottersight-scan on Our Own Monorepo
The OtterSight codebase is a TypeScript monorepo: Hono API, Astro web app, shared Drizzle schemas, BullMQ workers. A real production application with real dependencies.
We ran the scan from inside Claude Code:
/ottersight-scan
Syft generated a CycloneDX SBOM. Grype matched it against NVD, GHSA, and OSV. OtterSight enriched every finding with EUVD, EPSS, and KEV data.
The result:
86 vulnerabilities found
├── 5 Critical
├── 34 High
├── 44 Medium
└── 3 Low
For a project that was passing npm audit without issues, this was a wake-up call.
What We Found
The Actively Exploited One
The most urgent finding was CVE-2023-44487 — the HTTP/2 Rapid Reset attack. CISA has it on the KEV catalog, meaning it has been actively exploited in the wild. EPSS score: high. This is the kind of vulnerability that makes your infrastructure team lose sleep.
It was flagged in a Go standard library HTTP/2 implementation — but we’ll get to the nuance of that in a moment.
The Real npm Vulnerabilities
Among the 86 findings, 8 were real npm dependency vulnerabilities — packages we directly or transitively depend on that had published fixes:
- path-to-regexp — ReDoS vulnerability allowing denial of service via crafted route patterns
- picomatch — ReDoS in glob pattern matching
- brace-expansion — ReDoS in brace expansion parsing
- yaml — Prototype pollution via crafted YAML input
- smol-toml — Prototype pollution in TOML parsing
Three different ReDoS vectors in pattern-matching libraries. One prototype pollution in a YAML parser. One in a TOML parser. All with published fixes.
None of these showed up in npm audit. Grype’s broader database coverage found what npm’s built-in tooling missed.
The Fix: 8 Minutes of Work
pnpm update
That resolved most of the vulnerable packages. One transitive dependency needed a pnpm.overrides entry in package.json to force the patched version:
{
"pnpm": {
"overrides": {
"path-to-regexp@>=6.0.0 <6.3.0": "6.3.0"
}
}
}
Total time from “we have 8 real npm vulnerabilities” to “all fixed”: about 8 minutes.
The fixes were trivial. Finding the vulnerabilities was the hard part — or it would have been, without a scanner.
The False Positives: Go Binaries in node_modules
That leaves 74 vulnerabilities. Where did those come from?
Every single one was a Go standard library CVE. Go’s net/http, crypto/tls, encoding/xml, archive/tar — the full spread of Go stdlib advisories.
But we don’t write Go. We’re a TypeScript project.
The answer: esbuild. The esbuild bundler ships pre-compiled Go binaries inside its npm package (@esbuild/darwin-arm64, @esbuild/linux-x64, etc.). These are native executables that run during your build process. Grype correctly identifies them as Go binaries and correctly flags the Go stdlib CVEs they contain.
Technically accurate. Practically irrelevant.
These Go binaries are build tools. They run on your development machine or CI server during npm run build. They don’t ship in your production artifact. They don’t handle user input. They don’t listen on network ports. The HTTP/2 Rapid Reset vulnerability in Go’s net/http is real — but it can’t be exploited through esbuild’s build-time file transformation.
This is the fundamental challenge of binary SCA scanning: the scanner sees a vulnerable component, but it can’t know whether the vulnerable code path is reachable in your specific usage context.
Managing False Positives Properly
Ignoring false positives is not the same as managing them. We created a .grype.yaml configuration file to explicitly document our exclusions:
ignore:
# Go binaries in node_modules are build tools, not runtime code
- package:
type: go-module
name: stdlib
- package:
type: go-module
name: github.com/evanw/esbuild
This is the right way to handle false positives:
- Document the exclusion — future you (or your auditor) needs to know why
- Scope it narrowly — exclude Go modules inside esbuild, not all Go modules everywhere
- Add a review trigger — re-evaluate on esbuild upgrades
- Keep it in version control — the
.grype.yamlfile is committed alongside your code
After applying the configuration: 86 vulnerabilities down to 0.
Why AI Training Data Isn’t Enough
Here’s a scenario that should concern you.
You ask your AI assistant: “Are my dependencies secure?” The AI looks at your package.json, recognizes the packages, and based on its training data says: “These are well-maintained packages with no known critical vulnerabilities.”
The AI is wrong. Not because it’s hallucinating — because its training data has a cutoff. Vulnerabilities disclosed after training are invisible. The NVD publishes new CVEs daily. CISA adds new KEV entries weekly. Your AI assistant is checking against a static snapshot of vulnerability data that’s months old.
OtterSight’s MCP integration solves this by giving the AI access to live vulnerability databases. When your AI assistant calls /ottersight-scan, it’s not consulting training data — it’s running Syft and Grype against current NVD, GHSA, and OSV data, then enriching with live EUVD, EPSS, and KEV feeds.
The difference between “probably fine based on what I last learned” and “verified clean against today’s vulnerability databases” is the difference between hope and evidence.
The EUVD Angle
Every vulnerability in our scan was cross-referenced against the EU Vulnerability Database. For the CVEs that had EUVD entries, we got ENISA’s European context alongside the NVD data — including EU-specific severity assessments and related CERT-EU advisories.
For organizations subject to NIS2 or preparing for the Cyber Resilience Act, this matters. Having EUVD identifiers in your vulnerability reports demonstrates that you’re referencing the European canonical source, not just the US-operated NVD.
This is not about replacing the NVD. It’s about having both perspectives, especially when the NVD has had enrichment gaps and the EU regulatory landscape explicitly references ENISA’s database.
What We Learned
1. npm audit has blind spots. Grype found vulnerabilities that npm audit didn’t flag. If your security posture relies solely on npm audit, you have gaps.
2. Binary scanning creates noise. Any project using esbuild, SWC, or other tools that ship native binaries will see Go/Rust stdlib CVEs that aren’t exploitable in context. You need a way to manage this.
3. False positive management is a feature, not a bug. The .grype.yaml exclusion file is as important as the scan itself. Knowing which vulnerabilities don’t apply to you is half the battle.
4. The fix is usually trivial. pnpm update plus one override fixed everything. The hard part isn’t patching — it’s knowing you need to.
5. Dogfooding works. We built the MCP server, used it immediately, found real issues, and fixed them. If you’re building developer tools and you’re not using them on your own codebase, you’re missing the most obvious test environment.
Try It Yourself
OtterSight CLI
Scan any project right now, no account required:
npx @ottersight/cli scan .
MCP Server for AI Editors
Add OtterSight to Claude Code with one command:
mkdir -p ~/.claude/skills/ottersight-scan && curl -sSL \
https://raw.githubusercontent.com/Ottersight/ottersight-cli/main/packages/mcp/SKILL.md \
-o ~/.claude/skills/ottersight-scan/SKILL.md
Then type /ottersight-scan. The skill handles the rest.
Once configured, your AI assistant can scan projects, look up EUVD records, and check KEV status — all with live data.
OtterSight Cloud
The hosted dashboard adds scheduled scans, historical tracking, team notifications (300+ channels via Apprise), and multi-repo security posture. Built on the same scan engine, hosted on EU servers.
Join the waitlist at ottersight.com
86 vulnerabilities. 8 real, 78 noise. All resolved. The otter scanned itself and came out clean.