Fixes the three critical and two of the high findings from the 2026-10-13 audit (teahub #109), after pausing the venture loop (venture.yml disabled, TIME_VENTURE=off).
Critical
Forged state beats.beats_of accepted <!-- time {...} --> from any comment author; on a public repo a stranger could post a pr/planned beat and the next tick would merge a chosen PR or build a chosen page. Now only comments by github-actions[bot] count (is_time).
Token served to model-written JS. The browser pass cloned gh-pages with the token in the URL, served the whole clone over http.server, and ran the page in a networked Chrome. Now .git is dropped after the clone, only ventures/<slug>/ is served, and Chrome runs with --host-resolver-rules that resolve nothing but localhost.
Worker shell next to secrets. A scrubbed env= did not stop cat /proc/<pid>/environ on the same uid. Hands.run now executes in a throwaway container (checkout mounted, nothing else) when TIME_RUN_IMAGE names an image; heartbeat.yml/venture.yml set node:22-bookworm. Unset = host shell, as before (local runs, tests).
High
/time retry counts only from owner/member/collaborator (was: any non-bot).
verdict trusts Time's own comments and trusted associations; any other bot is a stranger.
touches_protected paginates pulls/N/files and counts a rename under both names (was: first 100 files, renames invisible).
Tests: fake comments carry logins; new cases for a stranger's retry and a forged beat; the fake GitHub paginates files. python3 .github/time/test_time.py green.
Not in this PR (audit follow-ups): require a named CI context rather than the worker's own status before auto-merge; heartbeat.yml ticking on any Approve/Object comment; labs-aicharts.yml step-output interpolation.
Fixes the three critical and two of the high findings from the 2026-10-13 audit (teahub #109), after pausing the venture loop (`venture.yml` disabled, `TIME_VENTURE=off`).
**Critical**
- **Forged state beats.** `beats_of` accepted `<!-- time {...} -->` from any comment author; on a public repo a stranger could post a `pr`/`planned` beat and the next tick would merge a chosen PR or build a chosen page. Now only comments by `github-actions[bot]` count (`is_time`).
- **Token served to model-written JS.** The browser pass cloned `gh-pages` with the token in the URL, served the whole clone over `http.server`, and ran the page in a networked Chrome. Now `.git` is dropped after the clone, only `ventures/<slug>/` is served, and Chrome runs with `--host-resolver-rules` that resolve nothing but localhost.
- **Worker shell next to secrets.** A scrubbed `env=` did not stop `cat /proc/<pid>/environ` on the same uid. `Hands.run` now executes in a throwaway container (checkout mounted, nothing else) when `TIME_RUN_IMAGE` names an image; `heartbeat.yml`/`venture.yml` set `node:22-bookworm`. Unset = host shell, as before (local runs, tests).
**High**
- `/time retry` counts only from owner/member/collaborator (was: any non-bot).
- `verdict` trusts Time's own comments and trusted associations; any other bot is a stranger.
- `touches_protected` paginates `pulls/N/files` and counts a rename under both names (was: first 100 files, renames invisible).
Tests: fake comments carry logins; new cases for a stranger's retry and a forged beat; the fake GitHub paginates files. `python3 .github/time/test_time.py` green.
Not in this PR (audit follow-ups): require a named CI context rather than the worker's own status before auto-merge; `heartbeat.yml` ticking on any Approve/Object comment; `labs-aicharts.yml` step-output interpolation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01CYHXFvWMCs1GUmRmpySqQ6
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Fixes the three critical and two of the high findings from the 2026-10-13 audit (teahub #109), after pausing the venture loop (
venture.ymldisabled,TIME_VENTURE=off).Critical
beats_ofaccepted<!-- time {...} -->from any comment author; on a public repo a stranger could post apr/plannedbeat and the next tick would merge a chosen PR or build a chosen page. Now only comments bygithub-actions[bot]count (is_time).gh-pageswith the token in the URL, served the whole clone overhttp.server, and ran the page in a networked Chrome. Now.gitis dropped after the clone, onlyventures/<slug>/is served, and Chrome runs with--host-resolver-rulesthat resolve nothing but localhost.env=did not stopcat /proc/<pid>/environon the same uid.Hands.runnow executes in a throwaway container (checkout mounted, nothing else) whenTIME_RUN_IMAGEnames an image;heartbeat.yml/venture.ymlsetnode:22-bookworm. Unset = host shell, as before (local runs, tests).High
/time retrycounts only from owner/member/collaborator (was: any non-bot).verdicttrusts Time's own comments and trusted associations; any other bot is a stranger.touches_protectedpaginatespulls/N/filesand counts a rename under both names (was: first 100 files, renames invisible).Tests: fake comments carry logins; new cases for a stranger's retry and a forged beat; the fake GitHub paginates files.
python3 .github/time/test_time.pygreen.Not in this PR (audit follow-ups): require a named CI context rather than the worker's own status before auto-merge;
heartbeat.ymlticking on any Approve/Object comment;labs-aicharts.ymlstep-output interpolation.🤖 Generated with Claude Code
https://claude.ai/code/session_01CYHXFvWMCs1GUmRmpySqQ6