Hacktoberfest 2026 : les issues que les mainteneurs ont marquées pour octobre, ouvertes et accessibles aux débutants. Parcourir les issues Hacktoberfest

Agent-mode npm apply, apply --check and vex skip a declared workspace member in a hidden directory (.github/actions/x, .config/tool), so its nested copy stays unpatched while VEX attests not_affected

Ouverte
#1,827 1 commentaire 0 réactions 0 personnes assignées Voir sur GitHub

Les mainteneurs répondent en général sous 1 jour

Personne n'a encore pris cette issue.

Évaluation

Difficulté
4/5
Temps estimé
3-5 jours
Accessibilité débutants
53/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
Active
Stack technique
bun, node.js, rust
Domaine
cli, security

Piste de recherche

Start with skipped_members_of and workspace_children in crates/socket-patch-core/src/crawlers/npm_crawler.rs, then read docs/ecosystems.md for the documented workspace behavior. Reproduce with the .github/actions/x workspace example and compare agent-mode scanning with the nested node_modules copy. Done when the declared hidden workspace member is crawled, or checks and VEX clearly flag the unpatched copy.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

bug bughunt pm:npm

[agent] Found by the scheduled npm bug-hunt routine (ledger #302).

Summary

#1627 made the agent-mode node_modules walk crawl a declared workspace member whose path crosses a SKIP_DIRS name (packages/build, vendor/lib). A declared member inside a hidden directory is still pruned. A common example is a JavaScript GitHub Action kept as an npm workspace at .github/actions/<name>, matched by "workspaces": [".github/actions/*"]. Another is an explicit ".config/tool" entry. npm 7+ treats these as workspace members and installs each member's unhoistable dependencies into <member>/node_modules from the root lock, so the copy there is live.

skipped_members_of (crates/socket-patch-core/src/crawlers/npm_crawler.rs:109) walks the patterns with a walkable filter that rejects every name starting with . (line 121). It also only adds a member when its path crosses a SKIP_DIRS name (line 183). The main walk's workspace_children drops hidden dirs too (line 3476). The result:

  • scan --mode agent patches every other copy of the same name@version, skips the hidden member's copy, and exits 0.
  • apply --check reports "Patches are in sync".
  • vex writes a not_affected statement for the vulnerability, though npm runs the unpatched bytes from .github/actions/x/node_modules/left-pad.

If the hidden member holds the only copy, scan --mode agent prints [skip] pkg:npm/[email protected] (not installed; run your package manager's install first …) and exits 0. The package is installed.

Impact

A false VEX attestation, the same class as #1627: a scanner consuming the VEX suppresses a vulnerability in code that is installed and executed (for example by the Action at runtime). Nothing in the output warns about it.

Repro (npm 10.9.4, Node 22.22.0, Linux)

The patch API is a local mock. Any patch for [email protected] shows it; a hand-staged .socket/manifest.json works the same way.

mkdir -p proj/.github/actions/x proj/packages/y && cd proj
echo '{"name":"root","version":"1.0.0","private":true,"workspaces":["packages/*",".github/actions/*"],"dependencies":{"left-pad":"1.3.0"}}' > package.json
echo '{"name":"x","version":"1.0.0","dependencies":{"left-pad":"1.2.0"}}' > .github/actions/x/package.json
echo '{"name":"y","version":"1.0.0","dependencies":{"left-pad":"1.2.0"}}' > packages/y/package.json
npm install
# lock: node_modules/left-pad (1.3.0), packages/y/node_modules/left-pad and
#       .github/actions/x/node_modules/left-pad (both 1.2.0)
socket-patch scan --mode agent --yes --api-url <mock> --org test-org --api-token fake
head -c 20 packages/y/node_modules/left-pad/index.js          # /* SOCKET-PATCHED */
head -c 20 .github/actions/x/node_modules/left-pad/index.js   # /* This program is f   <- unpatched
socket-patch apply --check …   # "Patches are in sync (1 patch checked)", exit 0
socket-patch vex … -O v.json   # 1 statement, status not_affected, exit 0

Expected vs actual

docs/ecosystems.md, "npm: which node_modules trees are crawled": the walk skips hidden directories and build dirs, "except that a workspace member the root package.json workspaces field declares … still has its own node_modules crawled. npm, yarn and Bun install a member's unhoistable dependencies there from the root lock." The usage docs say agent VEX attests "Installed patched files, checked against the manifest's hashes".

  • Expected: the declared member .github/actions/x has its node_modules crawled and patched. At the least, apply --check / vex must not report the patch as in sync or attest not_affected while that copy is unpatched.
  • Actual: the copy is never seen. apply, --check and vex all succeed.

Matrix (Linux, Node 22.22.0)

socket-patch npm member path result
main ecd4924 8.19.4 .github/actions/x (glob) fail
main ecd4924 10.9.4 .github/actions/x (glob) fail (2/2)
main ecd4924 10.9.4 .config/tool (explicit pattern) fail
main ecd4924 12.2.1 .github/actions/x (glob) fail
main ecd4924 10.9.4 tools/build/x (control, #1627 shape) pass
v5.0.1 10.9.4 .github/actions/x fail

This isn't a regression: v5.0.1 does the same. macOS and Windows are untested; the cause is platform-independent. Hosted and vendored modes are unaffected, because the pin is lock-driven and npm ci installs the patched tarball into the hidden member too. The walk is shared, so yarn and Bun workspaces probably behave the same (not verified).

Suspect code

  • crates/socket-patch-core/src/crawlers/npm_crawler.rs:121: walkable in skipped_members_of rejects hidden names, including the literal prefix of a pattern such as .github/actions/*.
  • crates/socket-patch-core/src/crawlers/npm_crawler.rs:183: members are only added when the path crosses a SKIP_DIRS name, so a hidden segment would need the same treatment.
  • crates/socket-patch-core/src/crawlers/npm_crawler.rs:3476: workspace_children prunes hidden dirs.

No probe runs: probe branches are blocked for this routine (see the ledger).

Langage dominant
Rust
Étoiles
8
Forks
2
Merge moyen
19 h 31 min
PR mergées (30 j)
686

Préparer son environnement

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de SocketDev/socket-patch

Toutes les issues de SocketDev/socket-patch

Issues similaires

Plus d'issues Rust

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.