Skip to content

fix(security): close two open GitHub Security Advisories#9281

Open
JSONbored wants to merge 2 commits into
mainfrom
fix/ghsa-v6v4-v3j4-security-advisories
Open

fix(security): close two open GitHub Security Advisories#9281
JSONbored wants to merge 2 commits into
mainfrom
fix/ghsa-v6v4-v3j4-security-advisories

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Summary

GHSA-v6v4-mh5m-5mqq — the miner-ui dev/preview auth middleware stamped its Set-Cookie session token on every response that wasn't itself rejected, including a wholly unauthenticated GET / and every static asset. Any local process (not just a browser) could curl the root path and read a valid, replayable token, then use it against the mutating /api/* routes. Replaced with a one-shot bootstrap path (visit ?token=<value> printed to the server's own stdout/journal once per process start) — the cookie is now only ever (re)stamped on a request that already proves it holds the token. Also switched the cookie comparison to a constant-time equality check.

GHSA-v3j4-j27j-fxw6 — eleven MCP tools accepted a caller-supplied baseRef with no leading-dash guard, passed positionally to git before any -- terminator — a ref starting with - (e.g. "--output=/some/path") is parsed by git as an option, not a revision, letting git diff overwrite an arbitrary file silently (gitOutput swallows all errors). Rejects any leading-dash ref at the choke point in collectLocalBranchMetadata (defense in depth alongside the zod schema layer), adds --end-of-options to every git invocation taking a caller-supplied ref, and pre-resolves baseRef to a real SHA once so only that SHA — never the raw string — reaches every downstream git call.

Test plan

  • npx tsc --noEmit -p tsconfig.json --incremental false — clean
  • New regression tests for both: test/unit/local-branch.test.ts (4 new tests, including a real temp-git-repo exploit reproduction proving the target file survives untouched) and apps/loopover-miner-ui/src/auth.test.ts (updated + new tests covering the bootstrap path and the never-leak-Set-Cookie-on-anonymous-request regression)
  • npx vitest run test/unit/local-branch.test.ts — 79/79 passing
  • apps/loopover-miner-ui's own vitest run src/auth.test.ts — 26/26 passing
  • npm run cf-typegen / npm run selfhost:env-reference / npm run db:migrations:check / npm run branding-drift:check — all clean, no drift

Confirmed via a clean origin/main checkout that 8 test files (12 test cases)
were failing independently of any in-flight PR. Root causes, all real bugs
or stale test assertions from recent merges:

1. linked-issue-label-propagation-fetch.ts: a merge-conflict resolution's
   fix (the direct-ownership-match exemption from the reward-label
   satisfaction-verdict check, #9161/#9077) was verified locally but never
   actually committed before its branch was pushed -- silently lost.
   Re-applied.

2. config-lint.ts's mergeReadinessCompositeWarnings fired even when
   gate.mergeReadiness is explicitly "off", which is a genuine no-op and
   never worth warning about -- only null/unset and off should both
   short-circuit.

3. predicted-gate-engine.test.ts asserted gateMode(undefined) === "advisory",
   the pre-#9167 fallback; #9167 intentionally made this fail closed
   ("block") for a malformed value. Test updated to match.

4. loopover-engine-scaffold.test.ts asserted a stale package.json "files"
   shape; #9064's engine-coverage work legitimately changed it to
   source-map-friendly glob patterns. Test updated to match.

5. The "merge-readiness-composite-preserves-explicit-block" engine-parity
   fixture encoded a "composite only fills in an unset sub-gate" semantic
   that was deliberately reverted (see applyMergeReadinessGate's own doc
   comment: unreachable in practice, since every sub-gate mode is already a
   concrete DB-defaulted value by the time it reaches GateCheckPolicy).
   Renamed and corrected to assert the actual (override) behavior, with a
   fresh golden recorded via scripts/record-engine-parity-goldens.ts.
   queue-5.test.ts's REGRESSION (#4528) test hit the same reward-label gate
   from a different angle and needed the same two assertions corrected.

6. reputation-wiring.test.ts's seedReviewTarget helper still wrote into
   review_targets, frozen by the 2026-06-22 convergence cutover (#9136
   repointed getSubmitterReputation/getSubmitterReputationAcrossInstall
   onto the live review_audit ledger, but this test helper was never
   updated to match). Rewritten to seed review_audit + pull_requests
   directly, mirroring submitter-reputation.ts's own query shape; also
   registered the synthetic repos an install-wide test needs (the
   cross-repo query joins on repositories.installation_id) and repointed
   a stale review_targets backdating UPDATE at pull_requests (#9015
   already repointed the cadence query itself).
GHSA-v6v4-mh5m-5mqq: the miner-ui dev/preview auth middleware stamped its
Set-Cookie session token on every response that wasn't itself rejected --
including a wholly unauthenticated GET / and every static asset. Any local
process (not just a browser) could curl the root path and read a valid,
replayable token, then use it against the mutating /api/* routes. Replaced
with a one-shot bootstrap path (visit ?token=<value> printed to the
server's own stdout/journal once per process start) -- the cookie is now
only ever (re)stamped on a request that already proves it holds the token.
Also switched the cookie comparison to a constant-time equality check.

GHSA-v3j4-j27j-fxw6: eleven MCP tools accepted a caller-supplied baseRef
with no leading-dash guard, passed positionally to git before any
terminator -- a ref starting with '-' (e.g. "--output=/some/path") is
parsed by git as an option, not a revision, letting  overwrite
an arbitrary file silently (gitOutput swallows all errors). Rejects any
leading-dash ref at the choke point in collectLocalBranchMetadata (defense
in depth alongside the zod schema layer), adds --end-of-options to every
git invocation taking a caller-supplied ref, and pre-resolves baseRef to a
real SHA once so only that SHA -- never the raw string -- reaches every
downstream git call.
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
loopover-ui a445c1c Commit Preview URL

Branch Preview URL
Jul 27 2026, 11:17 AM

@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

❌ 5 Tests Failed:

Tests completed Failed Passed Skipped
23107 5 23102 21
View the top 3 failed test(s) by shortest run time
test/unit/selfhost-pg-retention.test.ts > runRetentionPrune + processJob on the Postgres backend (#977) > processJob prune-retention deletes eligible rows and records a success audit event on Postgres
Stack Traces | 0.00579s run time
AssertionError: expected 3 to be +0 // Object.is equality

- Expected
+ Received

- 0
+ 3

 ❯ test/unit/selfhost-pg-retention.test.ts:119:44
test/unit/selfhost-pg-retention.test.ts > pruneExpiredRecords on the Postgres backend (#977) > deletes across multiple bounded batches and stops at the per-table cap, same as the SQLite path
Stack Traces | 0.0136s run time
AssertionError: expected +0 to be 4 // Object.is equality

- Expected
+ Received

- 4
+ 0

 ❯ test/unit/selfhost-pg-retention.test.ts:76:33
test/unit/selfhost-metrics.test.ts > DEFAULT_METRIC_META completeness (drift guard, 2026-07 fix) > every literal metric name emitted anywhere in src/ has a registered DEFAULT_METRIC_META entry
Stack Traces | 0.158s run time
AssertionError: expected [ …(2) ] to deeply equal []

- Expected
+ Received

- []
+ [
+   "loopover_orb_relay_multiple_live_enrollments_total",
+   "loopover_private_manifest_warnings_total",
+ ]

 ❯ test/unit/selfhost-metrics.test.ts:498:21
test/unit/worker-entry-boundary.test.ts > worker entry boundary > does not reference pixelmatch, pngjs, visual-diff, gifenc, or sharp in worker-reachable source
Stack Traces | 0.621s run time
AssertionError: worker-reachable files must not mention Node-only visual diff/GIF/image deps: .../review/visual/visual-findings.ts: expected [ Array(1) ] to deeply equal []

- Expected
+ Received

- []
+ [
+   ".../review/visual/visual-findings.ts",
+ ]

 ❯ test/unit/worker-entry-boundary.test.ts:82:118
View the full list of 1 ❄️ flaky test(s)
test/unit/salvageability.test.ts > resolveAiReviewSalvageableHold > defaults: no configured floor uses the gate default, and a confidence-less blocker counts as certainty (at/above floor)

Flake rate in main: 100.00% (Passed 0 times, Failed 10 times)

Stack Traces | 0.00739s run time
AssertionError: expected undefined to be defined
 ❯ test/unit/salvageability.test.ts:88:18

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@JSONbored JSONbored self-assigned this Jul 27, 2026
@loopover-orb loopover-orb Bot added the gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. label Jul 27, 2026
@loopover-orb

loopover-orb Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Caution

🛑 LoopOver review result - fixes required

Review updated: 2026-07-27 11:43:51 UTC

15 files · 1 AI reviewer · 2 blockers · CI failing · unstable

🛑 Suggested Action - Manual Review

Review summary
The AI review returned non-blocking notes for this change but did not include a separate narrative summary. Review the nits below before deciding this PR.

Nits — 4 non-blocking
  • codecov/patch is reported at 0.00% of diff hit against a 99% target — worth adding/confirming coverage on the changed lines in the non-security files bundled into this diff (e.g. config-lint.ts, linked-issue-label-propagation-fetch.ts) before merge.
  • vite-auth.ts:73 hardcodes the 48-char token length assumption only in a comment; consider a named constant (e.g. TOKEN_HEX_LENGTH) if that invariant is ever checked in code, not just documented.
  • The bootstrap path's 404-vs-401 status codes (vite-auth.ts:109/117) and the redirect's 302 (vite-auth.ts:139) are fine as plain HTTP semantics and don't need named constants.
  • If the gateMode(undefined) → 'block' fail-closed change (test/unit/predicted-gate-engine.test.ts) is intentional hardening, it deserves its own description and issue link, not a silent inclusion in a security-advisory PR.

Why this is blocked

  • No linked issue detected: No closing reference or linked issue number was found in the PR metadata/body. — If this PR is intended to solve an issue, link it explicitly in the PR body.
  • Maintainer requires a linked issue: This repo's maintainer focus manifest requires every PR to reference a tracked issue. — Link the relevant issue (for example Closes #123) before opening the PR.
📋 Copy for AI agents — paste into your coding agent
Fix the following blocker(s) from this PR review:

1. No linked issue detected: No closing reference or linked issue number was found in the PR metadata/body. — If this PR is intended to solve an issue, link it explicitly in the PR body.

2. Maintainer requires a linked issue: This repo's maintainer focus manifest requires every PR to reference a tracked issue. — Link the relevant issue (for example `Closes #123`) before opening the PR.

CI checks failing

  • validate
  • codecov/patch — 0.00% of diff hit (target 99.00%)
  • validate-tests
  • validate-code

Decision drivers

  • ❌ Code review — 2 blockers (1 reviewer)
  • ❌ Gate result — Blocking (Repo-configured hard blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ⚠️ Missing No linked issue or no-issue rationale found.
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (no linked issue context).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 13 registered-repo PR(s), 13 merged, 307 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 13 PR(s), 307 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: moderate
Review context
  • Author: JSONbored
  • Role context: owner (maintainer lane)
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: Python, TypeScript, Ruby, Go, MDX, Shell, Solidity, JavaScript
  • Official Gittensor activity: 13 PR(s), 307 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Treat this as maintainer-lane context rather than normal contributor-lane activity.
  • Then work through the remaining 2 steps in the Signals table above.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

Visual preview
Route Viewport Before (production) After (this PR's preview) Diff
/ desktop before /
before /
after /
after /
/ mobile before / (mobile)
before / (mobile)
after / (mobile)
after / (mobile)

Click any thumbnail to open the full-size screenshot. Before = production · After = this PR's preview deploy.

Scroll preview
Route Before (production) After (this PR's preview)
/ before / (scroll)
before / (scroll)
after / (scroll)
after / (scroll)

A short scroll-through clip (desktop) — click either thumbnail to open the full animation. Evidence for scroll-linked behavior a single screenshot can't show.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@loopover-orb loopover-orb Bot added the manual-review Gittensor contributor context label Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. manual-review Gittensor contributor context

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant