Skip to content

[SEC-REVIEW-2] Independent trust-boundary review and the carried compose exposure #89

Description

@lemonishi

TASKS ID: SEC-REVIEW (parts 4–5)
PRD: 0.3, 13, 17

Successor to #49, which has now been closed three times with its scope unsatisfied — twice by a linked PR, the last of which was mine. Its title and history no longer match what remains, so this issue carries the remainder with precise scope.

docs/TASKS.md records SEC-REVIEW as PARTIAL at 70%, parts 1–3 evidenced and parts 4–5 open.

Already done (evidence in docs/BUILD_LOG.md, integrated at a62e29b)

  • Part 1 — canary scan. Pass. Exactly two credentials, both threaded as sensitiveValues; no path found by which either reaches persisted state, a model prompt, a 4xx/5xx body, the DOM, browser storage, a URL, the logger, or a tracked file. Two low observations recorded: /api/system has no redaction pass, and ARK_API_KEY has no minimum length against a 4-character redaction floor.
  • Part 2 — five invariant-mutation cases. All caught by existing tests: bearer auth rejection, promotion refusal on failed final re-verification, fast-forward-only protected-ref CAS, contract-cannot-broaden-authority, verifier Plane containment. Two invariants excluded with reasons recorded.
  • Part 3 — boundary audit. Route inventory, traversal, identity, authority and promotion all hold. It failed on one sub-surface and found SEC-01.

Remaining

Part 4 — independent read-only security review

Must not be performed by @lemonishi. That constraint is not procedural throat-clearing; it has already paid for itself. Inside this issue's audit surface sits code I wrote: config.ts's token floor, scripts/check-deploy-auth-token.mjs, the deploy-existing-ecs.sh guard, the OPS-06 A-gate tests, and the SEC-01 fix itself.

SEC-01 is the argument. The part-3 audit found that the bearer hook decided from the raw request target while Fastify percent-decodes before routing, so GET /%61pi/system returned 200 unauthenticated where /api/system returned 401 — on every route, including POST /%61pi/shepherd/demo/reset, which removes Plane worktrees and restores protected HEAD. I had worked beside that hook repeatedly without seeing it, and my first correction silently widened the /api/health exemption. Both were caught by a reviewer who was not me. The existing suite could not see it: app.test.ts enumerates 16 control routes and asserts 401 for each, all canonical spellings.

Part 5 — fix every High/Medium finding with causal tests

Depends on part 4.

The carried OPS-06 High finding — a posture decision, not an implementation detail

docker-compose.yml:16 sets HOST: 0.0.0.0 and :23 publishes "${PUBLIC_PORT:-3000}:3000" — short syntax with no address prefix binds every interface. README:169 documents docker compose up --build and README:258/264 the .env.production lifecycle commands, all against that same file. The guard in scripts/deploy-existing-ecs.sh cannot reach any of them, so a tokenless server can still be published on every interface by a documented command.

The API behind it performs prompt-triggered command and file execution (SECURITY.md), and in container-volume mode the control plane holds the container engine socket (docs/DEVIATIONS.md), so this is not only API abuse.

Options, with the one already rejected and why:

  • Pin docker-compose.yml to 127.0.0.1 — matches docker-compose.state-volume.yml:60, but the existing-ECS profile is meant to be reachable behind a security group (README:261-263) and the same file serves the local Docker path. AGENTS.md's minimal-fix rule forbids removing intended functionality, so this was not taken.
  • Require a token only on a non-loopback bind — restores the loadConfig guard that e6a5878 deleted. Closes the exposure for every compose entry point at once, keeps the tokenless loopback demo, and would make the deploy-script guard and its Compose-parser machinery unnecessary. Probably the strongest option.
  • Split the compose profiles so the public one requires a token and the local one does not.
  • Accept the documented security-group requirement as sufficient, and record that decision explicitly.

Acceptance

  • independent read-only security review by someone other than the author of the code under review
  • every High/Medium finding fixed with causal tests
  • an explicit, recorded decision on the compose exposure
  • C,S,I
  • docs/TASKS.md SEC-REVIEW row and docs/BUILD_LOG.md updated from observed results

Note for whoever takes this

Do not put a closing keyword for this issue in a PR body unless the PR genuinely completes every part. That is what closed #49 twice, including once by me.

SEC-REVIEW is listed under Required before submission in both PRD 13 and the hackathon cut in docs/TASKS.md.

Activity

  1. added
    bugSomething isn't working
    hackathon-readyRequired for the minimum TechJam Track 1 submission cut
    priority:P0Must complete before hackathon submission
    on Aug 30, 2026
  2. self-assigned this
    on Aug 31, 2026
  3. sanjey99 commented on Aug 31, 2026

    @sanjey99
    Collaborator

    Taking over as authorized for consolidated remediation on branch fix/96-release-readiness-audit, based on current origin/main f935fdb. Primary ownership is limited to the concrete exact-main audit findings and their causal tests/evidence. No UI redesign. Issue #96 is the umbrella tracker and this issue remains linked for its own acceptance semantics. Independent review will not be self-claimed.

  4. sanjey99 commented on Aug 31, 2026

    @sanjey99
    Collaborator

    PR #97 candidate-remediates the remaining concrete release-audit code findings: durable collections are bounded and Agent publication is atomic; tokenless access is loopback Host plus same-origin Origin only; every effective public bind requires a strong token; and runtime credentials no longer enter Terraform variables, cloud-init, plans, or state. Terraform validation passes with the pinned 1.9.8 container and Volcengine provider 0.0.58; npm audit reports zero vulnerabilities; bounded credential/state/artifact scans are clean. The author cannot satisfy the required independent part-5 security review, so this issue stays open for that review and protected-main integration evidence.

  5. sanjey99 commented on Aug 31, 2026

    @sanjey99
    Collaborator

    PR #97 is integrated as 53f2529. Its concrete release-audit remediations (bounded durable retention, atomic Agent publication, tokenless Host/Origin enforcement, strong-token public bind, and Terraform credential-state removal) pass on the exact merge, including protected-main run 33396729636. Draft PR #98 records the integration. The required independent security acceptance remains open and is not self-certified.

  6. sanjey99 commented on Aug 31, 2026

    @sanjey99
    Collaborator

    Re-opened acceptance work — Medium credential boundary

    The independent exact-main review found one reachable Medium issue: the configured Ark key enters the Agent container PID namespace, where a same-UID command can read process environment through /proc and write the secret into an otherwise authorized Git artifact; changed blobs are not currently rejected against configured secret bytes before verification/promotion.

    I am taking this concrete remainder on branch fix/89-ark-secret-boundary, based on current origin/main at 61fba86.

    Primary ownership: apps/server/src/container-codex-runner.ts and causal tests; Shepherd changed-blob validation/promotion boundary and causal tests. Excluded: UI, dependency changes, all non-README documentation, external live execution. The fix will keep raw provider credentials out of the Agent PID namespace where feasible and add fail-closed secret scanning before artifacts can verify/promote. Issue #89 remains open until the fix is merged and independently re-audited.

  7. sanjey99 commented on Aug 31, 2026

    @sanjey99
    Collaborator

    Remediation is committed in PR #108 (e34b2ac) and is undergoing independent re-audit. The branch adds binary-safe configured-sensitive-value scanning at both trust transitions (Agent workspace → trusted Plane and exact detached commit → promotion), fail-closed filesystem identity checks, non-disclosing authority-denial persistence, and causal regressions.

    Observed branch gates: npm run check green (862 server + 20 web), coverage >=80% in all metrics, Playwright 48/48 at both viewports, real container 1/1, no-model live preflight green, Terraform valid, npm audit 0. Issue remains open until the independent verdict.

  8. sanjey99 commented on Aug 31, 2026

    @sanjey99
    Collaborator

    Completed on protected main via PR #108, merge commit 52ef61968185d659cd2ad95e218800e19223b25a.

    Independent read-only re-audit verdict: pass; no High/Medium blocker remains. The auditor passed 125/125 affected tests and independently proved the real /proc boundary with a synthetic-key negative control: readable to the same UID without Codex sandboxing, unreadable while scanning every /proc/*/environ under codex sandbox linux --full-auto. It verified import-before-mutation scanning, tracked/untracked/ignored coverage, fail-closed symlink/special/race handling, Plane rollback, exact immutable pre-verifier/CAS snapshot scanning, non-disclosing errors, and complete production service wiring.

    Exact merged-main npm run check also passed: 26 root tests, 862 server passed + 3 documented live-only skips, 20 web, strict types, and both builds. Branch evidence additionally passed all 80% coverage floors, Playwright 48/48 across both viewports, real container 1/1, Terraform validation, npm audit 0, and live no-spend discovery.

    One non-blocking Low edge remains documented: configured sensitive values shorter than four characters are not scanned. Real Ark credentials exceed that floor; this does not reopen the completed High/Medium acceptance. Per the user’s explicit documentation constraint, no non-README project docs were modified.

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

Metadata

Metadata

Assignees

Labels

bugSomething isn't workinghackathon-readyRequired for the minimum TechJam Track 1 submission cutpriority:P0Must complete before hackathon submission

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions