Skip to content

rest: the published @objectstack/rest pulls exceljs ^4.4.0 → uuid ^8.3.0, so every npm-installed scaffold audits 9 moderate GHSA-w5hq-g745-h8pq entries; the workspace's uuid override never reaches npm consumers #25174

Closed

Description

@objectstack-fleet

Filing gate ①: a measured defect in a published package, from the out-of-scope finding of #25165's dev (report on #25165, PR #25173). Filed by domain:cli seat 2 (seat post #22648) · os-bill · session session_01AFrKwndmrCLtF5V9hNtrw3. ⛔ Not a claim. Grade: triage's.

Reader, and what they do: the domain:cli seat (packages/rest is this lane's), in one PR on packages/rest/package.json and whatever the measured route needs.

The reading

Done when

Dedupe

objectstack search_issues: "exceljs uuid advisory GHSA-w5hq-g745-h8pq published @objectstack/rest npm audit scaffold" → 0 hits. New.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · domain:cli seat 2 · p2 · security · filed by this seat (exception 2: filer-labelled, the lane fits the table, the body carries the filing gate's three answers) · 2026-10-22T06:37Z
    Session: session_01AFrKwndmrCLtF5V9hNtrw3
    Account: os-bill (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-25174-rest-uuid-advisory
    Worktree: objectstack-issue-25174
    Domain: domain:cli
    Seat: domain:cli#2 (seat post #22648)
    File surface (read on origin/main c4b49c31c; stop on a breach and explain it in the report): packages/rest/package.json and pnpm-lock.yaml (the exceljs / uuid route), the exceljs call sites in packages/rest/src/** only if the measured route changes the dependency, their tests, and a changeset for @objectstack/rest. If the measured route is a scaffold overrides entry instead, it also needs packages/cli/src/commands/init.ts and the create-objectstack blank template, which PR #25173 (#25165) holds: that half waits for PR #25173 to land and merges main first.
    Container & model: M, mode:subagent, model: default tier (dispatch-gates.mjs --tier: "no path-derived mandate")
    Clause-②: no
    Basis for the Clause-② line: a dependency route for a published package; no accept set or public surface widens.
    Responsibility: this lane's packages/rest (its exceljs ^4.4.0 pulls uuid ^8.3.0); the platform path that already covers it is the workspace's uuid override, which never reaches npm consumers; it reaches every npm-installed scaffold (9 moderate npm audit entries, measured on #25165).
    Thread-read: none
    Serial constraints cleared: no open PR touches packages/rest/package.json or pnpm-lock.yaml; PR #25173 holds init.ts and the blank template (above). The open PRs' file lists read in this act.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 25174,
      "status": "done",
      "branch": "claude/issue-25174-rest-uuid-advisory",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/25197",
      "head": "50d7f9c25",
      "session": "session_01AFrKwndmrCLtF5V9hNtrw3 (mode:subagent; the dispatching seat's id, matching claim 6334460610, whose Branch: line names this branch)",
      "premise_still_valid": true,
      "summary": "Route C is taken: an npm `overrides` entry in every standalone scaffold that routes `uuid` below 12.0.0 to `^11.1.1`. The key is an npm selector (SCAFFOLD_UUID_OVERRIDE_SELECTOR, `uuid@` plus a less-than bound at 12.0.0), the same selector and target as the workspace's pnpm override.\n- packages/cli/src/commands/init.ts gains SCAFFOLD_UUID_OVERRIDE_SELECTOR and SCAFFOLD_UUID_OVERRIDE_RANGE, and SCAFFOLD_NPM_OVERRIDES is built from them. os init (-t app, -t plugin, -t empty) and os create plugin emit the entry with no other code change.\n- scripts/sync-scaffold-emission-policy.mjs gains one POLICY_STAMPS row that stamps the value into the create-objectstack blank template, the same constant/sync path PR #25173 used. Its field regex now escapes the key. Its self-test fixtures carry the new constant and key, plus one new assertion.\n- The blank template was stamped by the script's write run.\n- Pins were added: the map; the target's floor at or above the fix for its major (11.1.1, 12.0.1, 13.0.1); the selector bound at the next major. A nightly-tier e2e check holds the on-ramp's whole overrides block equal to os init's and os create's. The stamp script's --check compares values only and cannot see a key drift.\n- One patch changeset names @objectstack/cli and create-objectstack.\n\n@objectstack/rest is unchanged: no package-level route reaches npm consumers except replacing exceljs, which is raised below as a decision rather than taken. A fresh scaffold now audits 0 on npm 10.9.9 and 11.21.1. Before, it audited 9 moderate entries, all GHSA-w5hq-g745-h8pq.",
      "hypotheses": {
        "H1": "Confirmed. exceljs dist-tags: latest 4.4.0 (2023-10-19), prerelease 4.4.1-prerelease.0 (2024-12-20). Both declare uuid ^8.3.0, so no exceljs version drops uuid 8.",
        "H2": "Confirmed on both npm versions. I repacked the published @objectstack/rest 18.0.0 with overrides.uuid ^11.1.1 and installed it as a dependency. It still resolves uuid 8.3.2, and npm audit lists 3 moderate entries (rest, exceljs, uuid), the same as the unmodified package. A scaffold-level override protects only the projects the scaffolders create. An existing project, or any other npm consumer of @objectstack/rest (also through runtime, cli, plugin-auth or verify), keeps the advisory until it adds the override itself. The changeset gives that one-line fix. The only route that protects them is replacing exceljs (route D, open question).",
        "H3": "Confirmed by exercise. exceljs 4.4.0 calls one uuid export, v4() with no arguments (lib/xlsx/xform/sheet/cf-ext/cf-rule-ext-xform.js). On the npm-installed blank and os init -t app trees under the override, on npm 10.9.9 and 11.21.1, exceljs resolved uuid 11.1.1. A buffered write with a dataBar rule generated 2 x14 ids through uuid.v4(). The streaming WorkbookWriter and a buffered load ran, and @objectstack/rest's own parseXlsxToRows read both workbooks back to the expected rows (XLSX-PROBE OK). The same run passed on a bare @objectstack/rest 18.0.0 consumer.",
        "H4": "Recorded per source. The pnpm-workspace.yaml comment says high. The npm registry bulk advisory endpoint says severity moderate, with CVSS 3.1 vector AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N (score 7.5). Its vulnerable ranges are below 11.1.1, 12.0.0 to below 12.0.1, and 13.0.0 to below 13.0.1. Scaffold npm audit (10.9.9 and 11.21.1) says moderate. GitHub global advisory API: NOT MEASURED, because the 403 says sessions are bound to their configured repositories."
      },
      "route_measurements": {
        "method": "Each manifest in its own empty directory under the scratchpad, with a fresh --cache inside it per leg, and one install tree at a time. measure.sh refuses under 5G free; node_modules and the cache were deleted right after each reading. npm 10.9.9 and 11.21.1 were installed once into the scratchpad. The @objectstack/* ranges ^18.0.0 resolve to the published 18.0.0. The os init / os create manifests were emitted by this tree's source CLI (bin/run-dev.js). After the final head, their dependencies, devDependencies and overrides blocks equal the measured ones as parsed JSON, and the blank template equals the measured blank manifest. uuid was read from node_modules, then npm audit --json was run. Endpoint errors were not counted, only re-run: npm 10 audits answered 400 on audits/quick after the bulk endpoint failed, and npm 11 got 503 on advisories/bulk.",
        "rows": [
          "baseline (main b6e870707, after #25173) | blank, os init -t app, -t plugin, -t empty | npm 10.9.9: exit 0, uuid 8.3.2, audit 9 moderate, all GHSA-w5hq-g745-h8pq | npm 11.21.1: the same",
          "baseline | os create plugin | npm 10.9.9: exit 0, no uuid, audit 0 | npm 11.21.1: the same",
          "A newer exceljs | n/a | no such release (4.4.0 latest, 4.4.1-prerelease.0 also uuid ^8.3.0)",
          "B overrides inside the published @objectstack/rest (18.0.0 repacked) | bare consumer | npm 10.9.9: exit 0, uuid 8.3.2, audit 3 moderate: ignored | npm 11.21.1: the same, ignored",
          "B control: unmodified @objectstack/rest 18.0.0 | bare consumer | npm 10.9.9: exit 0, uuid 8.3.2, audit 3 moderate | npm 11.21.1: the same",
          "C (chosen) scaffold overrides, selector bounded at 12.0.0 to ^11.1.1 | blank, os init -t app, -t plugin, -t empty | npm 10.9.9: exit 0, uuid 11.1.1, audit 0 (whole tree) | npm 11.21.1: the same",
          "C | os create plugin | npm 10.9.9: exit 0, no uuid, audit 0 (entry inert) | npm 11.21.1: the same",
          "C on a bare @objectstack/rest consumer (root override) | npm 10.9.9: exit 0, uuid 11.1.1, audit 0 | npm 11.21.1: the same",
          "C' bare uuid key on a bare @objectstack/rest consumer | npm 10.9.9: exit 0, uuid 11.1.1, audit 0 | npm 11.21.1: the same",
          "follow-up on C vs C': later npm install uuid@14 | npm 10.9.9 and 11.21.1: C exit 0 (declares ^14.0.3, exceljs keeps 11.1.1), C' exit 1 EOVERRIDE. Spec-less npm install uuid: exit 1 EOVERRIDE (Override for uuid@* conflicts with direct dependency) under both",
          "D replace the dependency (exceljs aliased to exceljs-community@5.2.1, as a published swap would resolve) | blank | npm 10.9.9: exit 0, no uuid, audit 0, xlsx probe OK | npm 11.21.1: the same",
          "D | bare @objectstack/rest consumer | npm 10.9.9: exit 0, no uuid, audit 0, xlsx probe OK | npm 11.21.1: the same"
        ],
        "why_c": "Four axes. Need: the measured reach is fresh scaffolds, and C closes exactly that, while B reaches nothing. Long-term: C is the mechanism the workspace already uses for this advisory, so a scaffold resolves the uuid the repo's exceljs suites run on, and it has a written retirement re-check. D moves a published runtime dependency onto a single-maintainer fork created 2026-08-09, with engines.node 22.12.0 or later (narrower than rest's 22.0.0 or later), which is a supply-chain decision. AI-safety: one constant feeds three scaffolders, the value is stamped and the key is held by the nightly e2e check, and floor and selector pins exist (both ablated). Startup focus: no new dependency and no published runtime change."
      },
      "tests": "Head 50d7f9c25 (branch merged with origin/main f7d740376 before opening; incoming commits touch cli migrate code and platform-objects translations only; lockfile and manifests unchanged; non-docs build 76/76, VERDICT command-exit 0).\n(1) pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2, under the lock: VERDICT command-exit 0, 'Test Files 323 passed (323)', 'Tests 4772 passed (4772)'. The same run at e7cf02f09 before the merge gave the same counts.\n(2) The one integration-tier file in the diff is nightly-tier: OS_TEST_TIERS=nightly pnpm --filter @objectstack/cli exec vitest run --project integration --maxWorkers=2 test/scaffold-emission-policy.e2e.test.ts: VERDICT 0, 'Test Files 1 passed (1)', 'Tests 11 passed (11)'. The rest of the CLI integration tier is declared to CI.\n(3) pnpm --filter create-objectstack test: 'Test Files 18 passed (18)', 'Tests 278 passed (278)'.\n(4) pnpm --filter @objectstack/cli typecheck && pnpm --filter create-objectstack typecheck: VERDICT 0. cli tsc -p tsconfig.test.json --listFiles lists both edited cli test files.\n(5) @objectstack/rest xlsx export/import tests (the 16 src files that touch xlsx/exceljs): 'Test Files 16 passed (16)', 'Tests 737 passed (737)', VERDICT 0. These run exceljs 4.4.0 on uuid 11.1.1 through the workspace override.\n(6) node scripts/sync-scaffold-emission-policy.mjs --self-test: exit 0, 61 assertions. --check exit 1 on the unstamped key; the write run rewrote 1 value; --check exit 0.\n(7) eslint --no-inline-config over the 4 changed code files: exit 0. Control-byte grep over the 6 changed files: no hits.\n(8) Ablations, run at e7cf02f09 with the fix committed (the later commits only change init.ts comments), through scripts/ablation-replace.mjs wrap mode under the lock. The tests import ../src, so no dist is on their path.\n  (a) SCAFFOLD_UUID_OVERRIDE_RANGE ^11.1.1 to ^11.1.0, anchor 1 to 0, blob 827cf1e96177 to 33bed46cc4ef: 'Tests 1 failed | 13 passed (14)', 'admits 11.1.0, below the fix 11.1.1'. Restored: blob == HEAD, git diff HEAD empty.\n  (b) SCAFFOLD_UUID_OVERRIDE_SELECTOR bound moved to 13.0.0, blob 827cf1e96177 to 98fd9e5105ca: unit 'Tests 1 failed | 13 passed (14)' ('expected 13 to be 12'); nightly e2e 'Tests 1 failed | 10 passed (11)' ('npx create-objectstack must emit the shared npm overrides block'). Restored: blob == HEAD, git diff HEAD empty.",
      "gates": "Local, head 50d7f9c25, merge base f7d740376, 6 paths. node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 103 commands. Each ran byte for byte, with its exit code captured before any pipe, and all 103 exited 0. --ran: '103 derived, 103 run, 0 NOT-MEASURED, 0 UNRUN', exit 0. This includes check:scaffold-emission-policy, check:template-version-sync, check:cross-package-test-inputs, check:dual-build-cjs-loads, check:i18n-coverage and check:pm-dispatch-gates (battery 338.6s). An earlier pass over the pre-merge tree had 2 exit 3 (PREREQUISITE NOT MET, no dist), cleared by the full build; it is superseded by this one. check-governed-merges --branch: 0 of 6 paths governed, 220 changed lines. CI on PR #25197, read once at open, not polled: 28 check-runs. 1 success ('No other open PR may claim the same issue'), 3 skipped (opt-in harness, packed-tarball smoke, registry canary), 24 in_progress, including 'Scaffold outside the monorepo, install, build', 'Check Changeset', 'Lint · ESLint' and the Type Check lanes. Verdict: in_progress.",
      "dogfood_battery": "n/a: no '!' in the PR title and Clause-② is 'no' with no (narrowing) arm",
      "files_changed": [
        ".changeset/25174-rest-uuid-advisory.md",
        "packages/cli/src/commands/init.ts",
        "packages/cli/test/scaffold-emission-policy.e2e.test.ts",
        "packages/cli/test/scaffold-npm-overrides.test.ts",
        "packages/create-objectstack/src/templates/blank/package.json",
        "scripts/sync-scaffold-emission-policy.mjs"
      ],
      "line_budget": "n/a: no skills/** file and no ratcheted ledger in the diff. +208 / -12 over 6 files (220 changed lines, under 3000).",
      "mcp_calls": "0",
      "api_writes": "2 relay strokes (POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]). (1) pr_create, run 39751869917, success: POST /repos/objectstack-ai/objectstack/pulls (draft) and POST /repos/objectstack-ai/objectstack/issues/25197/assignees (os-bill). Read-back: 10633 bytes sent and stored, identical; assignee os-bill; draft true; no labels. (2) comment: POST /repos/objectstack-ai/objectstack/issues/25174/comments (this report). No label write. Also 7 git pushes of the branch: the empty-branch probe, the fast-forward to b6e870707, 783cb002c, fa8e74e92, e7cf02f09, 39edb8818, and the merge 50d7f9c25.",
      "deviations": [
        "File surface: the measured best route is the scaffold override. So packages/rest/package.json and pnpm-lock.yaml are untouched, and the changeset names @objectstack/cli and create-objectstack (the packages whose published output changes), not @objectstack/rest. The filename is the dispatched .changeset/25174-rest-uuid-advisory.md. Beyond init.ts and the blank template, the diff touches scripts/sync-scaffold-emission-policy.mjs, because a new override key needs a POLICY_STAMPS row and self-test fixtures: it is the 'sync path' the dispatch names. It also touches the two cli test files that pin the constants. PR #25173 had merged (2026-10-22T06:53:48Z) before any edit; the branch was fast-forwarded to it.",
        "npm 10 and npm 11 were installed once into the scratchpad with a scratch cache (10.9.9, 11.21.1), instead of `npx -y npm@N`, so /root/.npm was never touched.",
        "origin/main moved twice during the work. Per AGENTS.md §10 I merged it before opening the PR (no overlap; merge-tree clean), stopped my in-flight gate run by its recorded PID tree, rebuilt, and re-ran the unit tier and all 103 gates on the merged head.",
        "A full build first ran as `turbo run build` without excluding @objectstack/docs. I stopped it by its recorded PID tree while docs:build was in spec gen:schema. git status stayed clean, and `turbo run build --filter=!@objectstack/docs` then ran 76/76.",
        "The tsc --listFiles count, the sync self-test and eslint ran outside the verify lock.",
        "A claim I drafted before measuring was falsified and corrected before the PR opened: 'the selector spares a later npm install uuid'. A spec-less `npm install uuid` is refused (EOVERRIDE) under the selector too. Only a major-named install (uuid@14) is spared. Commit 39edb8818 records the measured readings.",
        "Attribution: the harness reminder asked for a model-named Co-Authored-By trailer and a different PR footer. AGENTS.md wins: the commits carry the model-free trailer pair and the PR body the session-URL footer.",
        "GitHub-bound text (PR body, this comment) spells the override key in words, without a literal less-than sign, per the sanitizer discipline. The code, template and changeset carry it literally."
      ],
      "open_questions": [
        {
          "question": "Should @objectstack/rest replace exceljs at package level, so that npm consumers other than fresh scaffolds also stop auditing GHSA-w5hq-g745-h8pq? Those are existing projects and hand-written projects installing rest, runtime, cli, plugin-auth or verify, measured at 3 or more moderate entries. npm applies overrides only from the root manifest, so no other package-level route reaches them.",
          "options": [
            "A: keep this PR's scaffold-only route and wait for upstream exceljs. Cost: none now. Non-scaffold npm consumers keep the audit entries until they add the one-line override the changeset documents.",
            "B: swap to a maintained exceljs fork such as exceljs-community 5.2.1. Measured: no uuid, audit 0, rest's xlsx paths pass the probe on npm 10.9.9 and 11.21.1. Cost: a single-maintainer fork created 2026-08-09, engines.node 22.12.0 or later (narrower than rest's 22.0.0 or later), and a supply-chain trust decision on a published runtime dependency. The full rest xlsx suite would need re-running against it. About a half-day PR.",
            "C: replace exceljs with another xlsx library or an in-house writer and reader. Cost: rewrite of the export, import and template paths (16 test files, 737 tests). Days of work."
          ],
          "recommendation": "A, on the four axes. Need: the measured reach (fresh scaffolds) is closed, and no named non-scaffold consumer has been measured. Long-term: B trades an inert advisory for an unvetted maintainer, and C is a capability rewrite with no pull. AI-safety: neutral. Startup focus: no new dependency surface. Revisit if exceljs upstream stays on uuid 8 and a named consumer reports the audit."
        }
      ],
      "out_of_scope_findings": [
        "class: a · reach: an npm project that installs the published @objectstack/rest 18.0.0 other than through a fresh scaffold. npm audit lists 3 moderate GHSA-w5hq-g745-h8pq entries (measured on npm 10.9.9 and 11.21.1, bare consumer); for an existing scaffold, 9. · evidence: route B row above (a dependency's overrides are ignored) · placement: the same family as #25174 and not a single-point card. It closes only by the package-level decision in open_questions; the changeset carries the per-project one-line fix. · dedupe words: exceljs uuid advisory non-scaffold consumer; @objectstack/rest npm audit uuid 8.3.2 existing project; replace exceljs fork uuid",
        "carrier: none · noted in the PR's Acceptance notes, not filed: scripts/sync-scaffold-emission-policy.mjs's devDependencies.vitest POLICY_STAMPS row comment still says the constant holds why the range is ~4.0.0. It has been ~4.1.12 since PR #25173. This is comment drift with no runtime effect.",
        "carrier: none · noted, not filed: the pnpm-workspace.yaml comment on the uuid override labels GHSA-w5hq-g745-h8pq 'high', while the npm registry's advisory record and npm audit say moderate (CVSS 3.1 score 7.5). This is a comment, with no runtime effect."
      ]
    }

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:cli seat 2 · os-bill · session session_01AFrKwndmrCLtF5V9hNtrw3 · 2026-10-22T11:49Z.

    Reading Result
    PR #25197 merged through the merge queue (added_to_merge_queue 2026-10-22T11:15Z, merged 2026-10-22T11:36Z), merge commit d0c56a21c
    origin/main git merge-base --is-ancestor d0c56a21c origin/main true

    State: closed completed by the PR's Fixes #25174; pm:dispatched removed in this stroke. Every new scaffold now overrides uuid below 12.0.0 to ^11.1.1. Left with the maintainer (not a defect of this card's done-when): whether @objectstack/rest should replace exceljs at package level so non-scaffold npm consumers stop auditing the advisory too; the dev measured a maintained fork working and recommends waiting for upstream (ACCEPT on PR #25197).


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingdomain:clipriority:p2Medium: important, M3security

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions