|
| 1 | +# Analog Case Study |
| 2 | + |
| 3 | +> Tested with CVE Lite CLI v1.6.0 |
| 4 | +
|
| 5 | +<p align="center"> |
| 6 | + <img src="https://raw.githubusercontent.com/analogjs/analog/main/apps/docs-app/static/img/logos/analog-logo.svg" alt="Analog logo" width="260"/> |
| 7 | +</p> |
| 8 | + |
| 9 | +## Summary |
| 10 | + |
| 11 | +- **Project:** [Analog](https://github.com/analogjs/analog) — fullstack Angular meta-framework powered by Vite and Nitro, bringing file-based routing, SSR/SSG, and integrated API routes to the Angular ecosystem |
| 12 | +- **Revision:** `3b9463ecf9782dc792a049c2e1741060cfdf2dcc` |
| 13 | +- **Lockfile:** `pnpm-lock.yaml` (3,367 resolved packages, lockfileVersion 9.0) |
| 14 | +- **Baseline findings:** 37 unique vulnerable packages (1 critical · 19 high · 16 medium · 1 low) |
| 15 | +- **Direct vs transitive:** 5 direct / 32 transitive |
| 16 | +- **Time to first actionable fix command:** under 30 seconds |
| 17 | +- **Validated fix command groups generated:** 3 |
| 18 | + |
| 19 | +--- |
| 20 | + |
| 21 | +## What this case study demonstrates |
| 22 | + |
| 23 | +Analog is a large, actively maintained monorepo. Its lockfile resolves 3,367 packages — more than twice the size of the NestJS and Juice Shop scans — and it uses pnpm's lockfile v9 format, which is the default for any project created with a current pnpm installation. |
| 24 | + |
| 25 | +The direct/transitive split (5 direct, 32 transitive) tells the story immediately: the vast majority of the risk in this codebase is not in packages the project controls. It lives in the toolchain — the documentation generator, the monorepo orchestrator, the CLI, the test runner, and the SSR framework utilities. A developer running `pnpm audit` sees 85 findings with no guidance on which ones they can act on. CVE Lite surfaces 5 directly fixable packages, 3 copy-and-run command groups, and a clear view of which transitive chains are worth investigating and which are structural. |
| 26 | + |
| 27 | +The most instructive chains here are not obvious ones. `@compodoc/compodoc` — the Angular documentation generator — pulls in `handlebars@4.7.8`, the only critical finding in the scan. `@angular/cli` pulls in `@modelcontextprotocol/sdk`, which carries its own high-severity advisory through `hono`. Neither of these paths would surface in a typical developer's mental model of where their security risk lives. |
| 28 | + |
| 29 | +--- |
| 30 | + |
| 31 | +## Comparison Note: CVE Lite CLI vs pnpm audit |
| 32 | + |
| 33 | +Both tools were run against the same `pnpm-lock.yaml` on the same machine. |
| 34 | + |
| 35 | +| Metric | pnpm audit | CVE Lite CLI v1.6.0 | |
| 36 | +|---|---:|---:| |
| 37 | +| Total reported findings | 85 | 37 | |
| 38 | +| Critical | 1 | 1 | |
| 39 | +| High | 34 | 19 | |
| 40 | +| Moderate / Medium | 47 | 16 | |
| 41 | +| Low | 3 | 1 | |
| 42 | +| Direct vs transitive breakdown | ✗ | ✓ (5 / 32) | |
| 43 | +| Validated fix targets | ✗ | ✓ | |
| 44 | +| Breaking change awareness | ✗ | ✓ | |
| 45 | +| Parent chain identified for transitive issues | ✗ | ✓ | |
| 46 | +| Specific copy-and-run commands | ✗ | ✓ | |
| 47 | + |
| 48 | +**Why CVE Lite reports fewer findings — and why that is not a coverage gap:** |
| 49 | + |
| 50 | +`pnpm audit` counts advisories, not packages. A single vulnerable package with multiple advisories, or one that appears in several dependency paths, contributes multiple entries. CVE Lite counts each unique vulnerable package once. That is why the totals differ: 85 vs 37. |
| 51 | + |
| 52 | +This deduplication is intentional. `lodash` appears three times in this lockfile — `4.17.21` via `@docusaurus/core`, `4.17.23` via `@compodoc/compodoc`, and `lodash-es@4.17.23` via `mermaid`. Each version affects two advisories, each appears in multiple paths. `pnpm audit` counts each advisory-path combination separately. CVE Lite surfaces three distinct package versions, each once, with their parent chains — a more accurate representation of the actual exposure surface. |
| 53 | + |
| 54 | +CVE Lite does not suppress advisories. Every advisory that contributed to a finding is recorded in the `IDs` column of the full table (`--verbose --all`). The deduplication is in the presentation layer, not in the detection layer. |
| 55 | + |
| 56 | +`pnpm audit`'s fix guidance: |
| 57 | + |
| 58 | +``` |
| 59 | +Run "pnpm audit --fix" to fix 0 of 85 vulnerabilities. |
| 60 | +85 vulnerabilities require manual review. See the full report for details. |
| 61 | +``` |
| 62 | + |
| 63 | +CVE Lite generates: |
| 64 | + |
| 65 | +```bash |
| 66 | +# High severity direct fixes |
| 67 | +pnpm add @angular/platform-server@21.2.9 defu@6.1.5 happy-dom@20.8.9 vite@8.0.5 @angular/cli@22.0.0-next.0 @vitest/ui@4.1.2 nitropack@2.13.3 nx@22.6.5 |
| 68 | + |
| 69 | +# Medium severity direct fix |
| 70 | +pnpm add h3@1.15.9 |
| 71 | + |
| 72 | +# Medium severity parent upgrades |
| 73 | +pnpm add @docusaurus/core@3.9.2-alpha.0 start-server-and-test@3.0.2 |
| 74 | +``` |
| 75 | + |
| 76 | +Each command is a validated non-vulnerable target. `pnpm audit --fix` marks all 85 findings as requiring manual review and offers no commands. CVE Lite identifies 11 packages with confident fix targets, groups them by severity, and separates direct upgrades from parent-chain moves. |
| 77 | + |
| 78 | +--- |
| 79 | + |
| 80 | +## Fix Journey |
| 81 | + |
| 82 | +In a modern Angular monorepo, the instinct is to chase the critical finding first. Here, the critical issue — `handlebars@4.7.8` via `@compodoc/compodoc` — has no direct fix command. CVE Lite makes that explicit: the top priority section flags it as a transitive issue requiring a parent-chain upgrade, and the fix plan separates it from the 5 directly actionable packages. |
| 83 | + |
| 84 | +The five direct packages with confident upgrades span two severity levels: |
| 85 | + |
| 86 | +**High severity** (8 packages, one command group): `@angular/platform-server`, `defu`, `happy-dom`, `vite`, `@angular/cli`, `@vitest/ui`, `nitropack`, and `nx`. All have validated non-vulnerable targets. The `@angular/cli` upgrade from `21.2.6` to `22.0.0-next.0` is flagged as a breaking change — it clears the `hono` transitive chain but carries a major version bump. |
| 87 | + |
| 88 | +**Medium severity** (2 groups): `h3@1.15.9` is a clean direct upgrade. `@docusaurus/core` and `start-server-and-test` are parent upgrades that resolve `estree-util-value-to-estree` and `axios` transitive chains respectively. |
| 89 | + |
| 90 | +After those passes, the remaining work belongs to the structural tier: multiple `path-to-regexp` and `picomatch` versions, `serialize-javascript`, `node-forge`, `minimatch`, and `lodash` variants spread across documentation and diagram tooling chains. These are not first-pass candidates — they require tooling upgrades or dependency replacement decisions rather than confident `pnpm add` commands. |
| 91 | + |
| 92 | +--- |
| 93 | + |
| 94 | +## Why this matters |
| 95 | + |
| 96 | +Analog is not a neglected project. It has active maintainers, a growing community, and regular releases. A lockfile scan still surfaces 37 vulnerable packages — 32 of them transitive. |
| 97 | + |
| 98 | +That pattern is consistent across every modern JavaScript framework scan: the risk is not in the application code or the framework's runtime dependencies. It is in the toolchain that developers install, trust, and rarely audit — documentation generators, test runners, monorepo orchestrators, and build utilities. |
| 99 | + |
| 100 | +Two chains in this scan are worth naming specifically: |
| 101 | + |
| 102 | +`@compodoc/compodoc` → `handlebars@4.7.8` (critical). Most Angular developers use `@compodoc` to generate API documentation. It is a devDependency, rarely updated independently, and not a package most teams include in their security review surface. CVE Lite names it as the parent for the only critical finding in the scan. |
| 103 | + |
| 104 | +`@angular/cli` → `@modelcontextprotocol/sdk` → `hono` (high). Angular CLI recently incorporated MCP SDK support. That SDK pulls in `hono`, which carries a high-severity advisory. A developer auditing their Angular application would not think to trace security risk through the CLI tool itself. The parent chain makes this visible. |
| 105 | + |
| 106 | +For a team doing a pre-release check, the operationally useful question is not "how many advisories exist?" It is "what do I do right now, and what is structural?" CVE Lite answers that in under 30 seconds: three command groups for the confident first pass, and a clear separation of the transitive remainder. |
| 107 | + |
| 108 | +--- |
| 109 | + |
| 110 | +## Scan command |
| 111 | + |
| 112 | +Run from the Analog repository root: |
| 113 | + |
| 114 | +```bash |
| 115 | +npx cve-lite-cli . --verbose --all |
| 116 | +``` |
| 117 | + |
| 118 | +--- |
| 119 | + |
| 120 | +## Baseline findings |
| 121 | + |
| 122 | +Full vulnerable package list at scan time: |
| 123 | + |
| 124 | +| Package | Version | Severity | Relationship | Fix hint | Advisory IDs | |
| 125 | +|---|---|---|---|---|---| |
| 126 | +| handlebars | 4.7.8 | critical | transitive | 4.7.9 | GHSA-q42p-pg8m-cqh6, GHSA-442j-39wm-28r2 | |
| 127 | +| @angular/platform-server | 21.2.7 | high | direct | 21.2.9 | GHSA-5pq3-h73f-66hr | |
| 128 | +| defu | 6.1.4 | high | direct | 6.1.5 | GHSA-737v-mqg7-c878 | |
| 129 | +| flatted | 3.4.1 | high | transitive | 3.4.2 | GHSA-rf6f-7fwh-wjgh | |
| 130 | +| happy-dom | 20.8.4 | high | direct | 20.8.8 | GHSA-6q6h-j7hj-3r64, GHSA-w4gp-fjgq-3q4g | |
| 131 | +| hono | 4.11.5 | high | transitive | 4.11.7 | GHSA-26pp-8wgv-hjvm, GHSA-458j-xx4x-437… | |
| 132 | +| lodash-es | 4.17.23 | high | transitive | 4.18.0 | GHSA-f23m-r3pf-42rh, GHSA-r5fr-rjxr-66jc | |
| 133 | +| lodash | 4.17.21 | high | transitive | 4.17.23 | GHSA-f23m-r3pf-42rh, GHSA-r5fr-rjxr-66jc | |
| 134 | +| lodash | 4.17.23 | high | transitive | 4.18.0 | GHSA-f23m-r3pf-42rh, GHSA-r5fr-rjxr-66jc | |
| 135 | +| minimatch | 3.0.8 | high | transitive | 3.1.3 | GHSA-23c5-xmqv-rm74, GHSA-3ppc-4f35-3m2… | |
| 136 | +| node-forge | 1.3.3 | high | transitive | 1.4.0 | GHSA-2328-f5f3-gj25, GHSA-5m6q-g25r-mvw… | |
| 137 | +| path-to-regexp | 0.1.12 | high | transitive | 0.1.13 | GHSA-37ch-88jc-xwx2 | |
| 138 | +| path-to-regexp | 1.8.0 | high | transitive | 0.1.10 | GHSA-9wv6-86v2-598j | |
| 139 | +| path-to-regexp | 8.3.0 | high | transitive | 8.4.0 | GHSA-27v5-c462-wpq7, GHSA-j3q9-mxjg-w52f | |
| 140 | +| picomatch | 2.3.1 | high | transitive | 2.3.2 | GHSA-3v7f-55p6-f55p, GHSA-c2c7-rcm5-vvqj | |
| 141 | +| picomatch | 4.0.3 | high | transitive | 2.3.2 | GHSA-3v7f-55p6-f55p, GHSA-c2c7-rcm5-vvqj | |
| 142 | +| serialize-javascript | 6.0.2 | high | transitive | 7.0.3 | GHSA-5c6j-r48x-rmvq, GHSA-qj8w-gfj5-8c6v | |
| 143 | +| svgo | 3.3.2 | high | transitive | 2.8.1 | GHSA-xpqw-6gx7-v673 | |
| 144 | +| vite | 8.0.0 | high | direct | 6.4.2 | GHSA-4w7w-66w2-5vf9, GHSA-p9ff-h696-f58… | |
| 145 | +| @hono/node-server | 1.19.11 | medium | transitive | 1.19.13 | GHSA-92pp-h63x-v22m | |
| 146 | +| ajv | 8.17.1 | medium | transitive | 6.14.0 | GHSA-2g4f-4pwh-qvx6 | |
| 147 | +| axios | 1.13.6 | medium | transitive | 0.31.0 | GHSA-3p68-rc4w-qgx5, GHSA-fvcv-3m26-pcqx | |
| 148 | +| brace-expansion | 1.1.12 | medium | transitive | 1.1.13 | GHSA-f886-m6hf-6m8v | |
| 149 | +| brace-expansion | 2.0.2 | medium | transitive | 1.1.13 | GHSA-f886-m6hf-6m8v | |
| 150 | +| brace-expansion | 5.0.4 | medium | transitive | 1.1.13 | GHSA-f886-m6hf-6m8v | |
| 151 | +| dompurify | 3.3.3 | medium | transitive | 3.4.0 | GHSA-39q2-94rc-95cp | |
| 152 | +| estree-util-value-to-estree | 3.1.1 | medium | transitive | 3.3.3 | GHSA-f7f6-9jq7-3rqj | |
| 153 | +| file-type | 20.5.0 | medium | transitive | 21.3.1 | GHSA-5v7r-6r5c-r473, GHSA-j47w-4g3g-c36v | |
| 154 | +| follow-redirects | 1.15.11 | medium | transitive | 1.16.0 | GHSA-r4q5-vmmm-2653 | |
| 155 | +| h3 | 1.15.6 | medium | direct | 1.15.9 | GHSA-4hxc-9384-m385, GHSA-72gr-qfp7-vwhw | |
| 156 | +| mdast-util-to-hast | 13.1.0 | medium | transitive | 13.2.1 | GHSA-4fh9-h7wg-q85m | |
| 157 | +| serialize-javascript | 7.0.4 | medium | transitive | 7.0.5 | GHSA-qj8w-gfj5-8c6v | |
| 158 | +| smol-toml | 1.6.0 | medium | transitive | 1.6.1 | GHSA-v3rj-xjv7-4jmq | |
| 159 | +| yaml | 1.10.2 | medium | transitive | 1.10.3 | GHSA-48c2-rrv3-qjmp | |
| 160 | +| yaml | 2.8.2 | medium | transitive | 1.10.3 | GHSA-48c2-rrv3-qjmp | |
| 161 | +| @angular/cli | 21.2.6 | low | direct | 22.0.0-next.0 (breaking change) | — | |
| 162 | + |
| 163 | +--- |
| 164 | + |
| 165 | +## Want your project reviewed? |
| 166 | + |
| 167 | +If you maintain an interesting JavaScript or TypeScript project and want CVE Lite CLI considered for a public case study, open an issue in the [CVE Lite CLI repository](https://github.com/sonukapoor/cve-lite-cli/issues). |
| 168 | + |
| 169 | +Please include: |
| 170 | + |
| 171 | +- the repository link |
| 172 | +- why the project would make a useful case study |
| 173 | +- whether the dependency graph is publicly reproducible |
| 174 | + |
| 175 | +Not every project will be selected. Preference will go to projects that are publicly useful, technically interesting, and strong examples of realistic dependency remediation workflows. |
0 commit comments