Skip to content

Security scans miss nested manifests — submodule vulnerabilities are structurally invisible #145

Description

@alamb-hex

A registered project is scanned at its root path only. Any package.json / lockfile below that — git submodules, nested apps, vendored packages — is never scanned, so findings there cannot appear on /security at all.

Concrete case

hextant (Hextant Boardroom, /home/aaron/Projects/hextant-v2) reports clean: 543 packages, 0 findings, complete: true.

It has 13 git submodules. Four carry their own package.json + package-lock.json:

submodule packages findings
agents/vcfo 70 3 high
agents/vcmo 70 3 high
agents/vcio 36 0
agents/vcro 21 0

The six high-severity advisories (axios 1.16.1, js-yaml 4.1.1, form-data 4.0.5 — prototype pollution, NO_PROXY bypass, several quadratic-CPU DoS) were found only by running cve-lite manually against each submodule path. They are now patched in Hexaxia-AI/vcfo#1 and Hexaxia-AI/vcmo#1.

Nothing about the dashboard indicated a gap. The project showed a complete, clean scan while carrying six unpatched highs.

Why this matters beyond hextant

The blind spot is structural, not specific to submodules:

  • monorepo roots whose workspace packages hold their own lockfiles
  • vendored or nested apps under a registered root
  • any submodule with dependencies

It is the same class as the nested-lockfile gap hit during the ChainDrop sweep earlier today, where the registry-driven scan could not reach nested lockfiles and the check had to be run by hand across ~/Projects.

Options

  1. Discover nested manifests during a scan — walk the project root for package.json with an adjacent lockfile (excluding node_modules, respecting .gitignore), scan each, and attribute findings to <project> › <relative/path>. Highest coverage; needs a depth bound and a way to skip fixture directories.
  2. Let submodules be registered as first-class projects. Simple and explicit, but manual, easy to forget, and clutters the project list.
  3. Per-project scanPaths setting — an explicit list of additional roots. Middle ground: opt-in, no discovery cost, still manual.

Option 1 is the only one that fails safe; the others require someone to already know the nested manifest exists, which is exactly what failed here.

Whichever route, the scan result should state what was covered. A project with unscanned nested manifests should not present as an unqualified clean complete: true — surfacing "N nested manifests found, M scanned" would have made this visible without any of the above.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions