Skip to content

fix(dashboard): pass -R repo to gh commands so multi-remote setups work (replay of 416244f)#25

Open
antfleet-ops wants to merge 2 commits into
mainfrom
bench/pr-169
Open

fix(dashboard): pass -R repo to gh commands so multi-remote setups work (replay of 416244f)#25
antfleet-ops wants to merge 2 commits into
mainfrom
bench/pr-169

Conversation

@antfleet-ops

Copy link
Copy Markdown

Benchmark replay

This PR replays upstream commit 416244f ("fix(dashboard): pass -R repo to gh commands so multi-remote setups work") as a diff against its parent.

Not for merge. Purpose: AntFleet two-model PR review evaluation.

See BENCHMARK.md for the policy.

aaronjmars and others added 2 commits May 18, 2026 15:26
…rk (aeonfun#169)

* fix(dashboard): pass -R repo to gh commands so multi-remote setups work

When a fork adds upstream as a second remote (recommended by README's
two-repo strategy), `gh secret list/set/delete` errors with
"multiple remotes detected" because it can't pick a default repo. The
auth and secrets API routes invoked gh without -R, so authentication
and secret management both broke as soon as upstream was added.

Both routes now resolve the active repo via `gh repo set-default --view`
(falls back to `gh repo view`) and pass it explicitly via -R.

* refactor(dashboard): unify gh repo helper on execFileSync + array form

Both routes share the same ghRepo/ghArgsRepo pattern now — strip the
shell-string ghRepoFlag() from auth and switch its three gh invocations
to execFileSync. Also drop the unused listSecrets shell branch in
secrets. Behaviour-identical; just kills the inconsistency between the
two routes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: traewang <traewang@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Initial review missed in 30-PR burst on 2026-05-18 (rate limit
hit on first batch). Re-firing pull_request.synchronize webhook.
@antfleet

antfleet Bot commented May 18, 2026

Copy link
Copy Markdown

AntFleet · 3 findings

Both reviewers flagged the items below on the changed files. AntFleet posts only what two independent frontier models agree on.


Security · Critical — Missing authentication/authorization on secret-management endpoints
dashboard/app/api/secrets/route.ts:95-145

Both route handlers expose the ability to read which secrets are set, create/overwrite arbitrary GitHub Actions secrets (including ANTHROPIC_API_KEY / CLAUDE_CODE_OAUTH_TOKEN), and delete them. There is no authentication, no session check, no CSRF token, and no origin/host verification. If the Next.js dashboard is ever exposed beyond localhost (or reachable from a browser visiting a malicious page that POSTs JSON with a simple Content-Type to bypass CORS preflight is harder, but a curl/proxy or…

Fix: Require authentication for all mutating routes (and arguably GET, which leaks which secrets exist). At minimum, bind the dev server to 127.0.0.1, verify a same-origin/Host header, require a CSRF token, and gate behind a session cookie or local-only token. Also reject requests if NODE_ENV === 'produ…


Bug · High — Token reassembly from claude setup-token can splice in non-token text and write garbage to CLAUDE_CODE_OAUTH_TOKEN
dashboard/app/api/auth/route.ts:81-108

The first-line push is tokenChars.push(trimmed) without filtering — trimmed is the entire first line starting at sk-ant-oat, which in real claude setup-token output is wrapped inside an ANSI/box-drawing TUI and often contains trailing spaces, box characters, or ANSI escape sequences. Because no regex is applied to the first line, ANSI escape bytes and box-drawing glyphs get concatenated into token. The resulting token is then written to the GitHub secret as the OAuth token, silently…

Fix: Strip ANSI escapes first (e.g. output.replace(/\x1b\[[0-9;]*[A-Za-z]/g, '')), then extract with a strict regex like /sk-ant-oat[A-Za-z0-9_-]+/ over the cleaned text, possibly joined across line breaks first by removing all whitespace inside the matched run. Validate length/format before calling…


Performance · Low — Synchronous child_process calls block the Node event loop on every request
dashboard/app/api/secrets/route.ts:30-75

Every GET/POST/DELETE fans out to multiple synchronous gh invocations (auth status, repo detection, secret list). On a multi-user dashboard this serializes all other requests handled by the same Node worker for hundreds of ms per call. The dashboard is described as a local tool, so severity is low, but the comment // Check if ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN is set in GET hides that it actually shells out three times.

Fix: Use the async execFile (promisified) and await it; or batch results behind a short in-memory cache (e.g. 5s TTL) for repo and auth-status checks.

Review 6017bf3f · claude-opus-4-7 + gpt-5 (unanimous) · 126s · ~$0.40

@antfleet

antfleet Bot commented May 18, 2026

Copy link
Copy Markdown

AntFleet · finding 6017bf3f-2 closed in 4b9b492

Performance · Low — Synchronous child_process calls block the Node event loop on every request
dashboard/app/api/secrets/route.ts:30-75

Originally flagged in the AntFleet review. Receipt automated.

@antfleet

antfleet Bot commented May 18, 2026

Copy link
Copy Markdown

AntFleet · finding 6017bf3f-1 closed in 4b9b492

Bug · High — Token reassembly from claude setup-token can splice in non-token text and write garbage to CLAUDE_CODE_OAUTH_TOKEN
dashboard/app/api/auth/route.ts:81-108

Originally flagged in the AntFleet review. Receipt automated.

@antfleet

antfleet Bot commented May 18, 2026

Copy link
Copy Markdown

AntFleet · finding 6017bf3f-0 closed in 4b9b492

Security · Critical — Missing authentication/authorization on secret-management endpoints
dashboard/app/api/secrets/route.ts:95-145

Originally flagged in the AntFleet review. Receipt automated.

aaronjmars added a commit to aeonfun/aeon that referenced this pull request May 19, 2026
…#188)

Closes the 3 critical findings AntFleet flagged in #184:
- C1 · /api/skills/[name]/run — unauthenticated POST triggers
  `gh workflow run aeon.yml`
- C2 · /api/secrets GET — unauthenticated read of secret name set
- C3 · /api/secrets POST/DELETE — unauthenticated set / delete of
  any GitHub secret on the repo

Same root cause: every dashboard `/api/*` route assumes "the OS user
owns localhost". Two paths break that assumption — a malicious page
that DNS-rebinds `attacker.example` to `127.0.0.1` and POSTs to the
loopback socket, and a browser cross-origin no-cors POST that bypasses
preflight. Both reach the routes today; both write GitHub secrets or
trigger Actions on the operator's behalf.

Add a single Next middleware (`dashboard/middleware.ts`) that gates
every `/api/*` request through `dashboard/lib/security/api-gate.ts`:

  - Host header must resolve to a loopback variant (127.0.0.1,
    localhost, ::1, [::1], 0.0.0.0) — defeats DNS rebinding.
  - On non-GET/HEAD/OPTIONS, Origin (with Referer fallback) must also
    resolve to a loopback variant — defeats no-cors CSRF.

Two operator hatches preserve LAN/Tailscale/reverse-proxy setups:

  - `AEON_DASHBOARD_ALLOWED_HOSTS=aeon.local,box.tail-xxx.ts.net` —
    extend the allowlist (comma-separated; case + port insensitive).
  - `AEON_DASHBOARD_ALLOW_ANY_HOST=1` — bypass entirely, intended for
    a trusted proxy that owns Host policy. Loudly insecure; not the
    default.

Pure stdlib in `api-gate.ts` (Set + URL parsing); no new deps. Smoke
tests in `api-gate.test.ts` cover stripPort, the env-driven wrapper,
the loopback-accept happy path, both rejection paths, and both env
hatches — run with `node --test dashboard/lib/security/api-gate.test.ts`.

README gains a `### Dashboard access` block under Quick start
documenting the env vars + the two threat-model paths the gate
defeats.

Refs: AntFleet receipts
- AntFleet#1 (comment)
- AntFleet#3 (comment)
- AntFleet#25 (comment)
aaronjmars pushed a commit to aeonfun/aeon that referenced this pull request May 20, 2026
…-token reassembly (#194)

The prior loop pushed line.trim() unconditionally for the first line,
which included any trailing terminal prose, spaces, or ANSI sequences
that appeared after the token text on that line. Those bytes were
then concatenated into the stored CLAUDE_CODE_OAUTH_TOKEN, writing
a malformed credential to the GitHub secret.

Fix: apply the same /^[A-Za-z0-9_\-]+/ extraction to every line
(including the first). The regex anchors at the start of the trimmed
line and stops at the first non-token character, so only the token
alphabet is ever appended. Add a post-loop guard that returns a 400
if the assembled value does not start with "sk-ant-oat", making
extraction failures explicit instead of silently storing garbage.

Ref: AntFleet bench receipt AntFleet#25 (comment)

Co-authored-by: a11 <augstar@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants