.be anchors — store-root redirect, TOML injection
dog/HOME.c's cwd-walk discovery is the git CVE-2022-24765 class: it probes every ancestor for .be and adopts the first hit with ZERO trust validation. For a secondary-worktree anchor (a .be regular file), home_anchor_resolve (HOME.c:637-682) takes row-0's URI path VERBATIM and makes it h->root — the store root — with no ownership check, no symlink rejection (FILEStat follows symlinks; FILELStat exists and is unused), and no containment/absolute-path requirement. Running any dog inside a hostile cloned/untarred directory then routes rw opens (home_ensure_markers, DOGPupCreate) to an attacker-chosen path. Separately home_bootstrap_config (HOME.c:110-125) writes git config user.name/email into .be/config as name = "<value>" with NO escaping, so a value containing " or \n injects arbitrary TOML (e.g. forging the HOMEHost ref-authority). Method: Issues.
home_walk_up (HOME.c:922-983) → home_anchor_resolve (:637-682) → DOGRepoFromBe sets h->root from row-0 (home_peek_repo_uri :562-587); nothing bounds it to the worktree.FILEStat (HOME.c:650, :997 home_is_exe) resolves symlinks; a planted .be symlink or a symlinked sibling exe is followed, then the caller execvps it (TOCTOU between stat and exec).getenv("PATH") scan (HOME.c:1056) picks the sibling binary to exec — an attacker-controlled PATH chooses the code that runs.HOME.c:110-125, value slice {name_start,name[0]} fed raw; also silent truncation (256-byte emailbuf, FILEEnsureSoft fills what fits).DOGPupThinTail (DOG.c:714-733) unlinks a recomposed path decoupled from the mmap it released — check/unlink race in a shared .be dir... NOT rejected in project/branch segments: PATHu8sVerifySegment rejects //NUL/CR/LF/TAB but not ./..; DOGProjectFromBe (DOG.h:227-251) rejects only .be; DPATHBranchNormFeed (DPATH.h:57-78) never rejects ... A row-0 path or ref containing .. composes <root>/.be/.. (= <root>) so shard mkdir -p/refs reads+writes ESCAPE the .be store. (DPATH already ships the correct rejecter DPATHu8sDrainSeg/DPATHVerify — applied to git tree names, not to these segments; reuse it here.)FILECreate (abc/FILE.c) opens O_CREAT|O_RDWR|O_TRUNC with NO O_NOFOLLOW (and no O_EXCL on the pup tmp): callers HOME.c:128 (.be/config), :154 (wtlog), DOG.c:674 (pup tmp). A planted symlink at <repo>/.be/config or the <seqno>.<ext>.tmp redirects create+truncate to an arbitrary victim-writable file — classic repo-dir symlink TOCTOU.home_be_subdirs returns fail(OK) on the subdirs>1 break BEFORE setting *out_count (HOME.c:786-796), so it stays 0; home_dir_shieldlike (:963) then misclassifies a populated MULTI-project store as shieldlike and adopts the wrong anchor instead of walking past it.geteuid vs FILELStat owner) and reject symlinked .be; make row-0 store roots resolve inside the discovered worktree (absolute + realpath containment) or fail.", \, and control bytes in config values before emitting TOML; never silently truncate a value.../. in project + branch segments (reuse DPATHVerify) so no composed store path escapes .be; re-normalize before filesystem use.O_NOFOLLOW on .be/config/wtlog creates and O_EXCL on the pup tmp.home_be_subdirs to set *out_count before the multi-shard break.dog/ libdog, ABC style; keep the ordinary single-user primary-worktree flow (own .be/) working unchanged — the guard only bites foreign/planted anchors.safe.directory intent: an anchor is trusted only if owned by the invoking uid (or explicitly allow-listed); no ambient adoption..be file whose row-0 points the store root outside the tree; assert be refuses instead of writing there.FILELStat symlink checks on the discovered anchor...//relative/outside; reject ../. project+branch segments (reuse DPATHVerify).home_bootstrap_config; reject NUL/newline; O_NOFOLLOW/O_EXCL on the marker + pup creates.home_be_subdirs *out_count on the multi-shard break.DOGParseURI/DOGRepoFromBe/home_peek_repo_uri (attacker URIs).DOGRepoFromBe/DOGParseURI (DOG.h:186-280, DOG.c:238-284) is bounds-safe today but fragile; cleanup tracked under PTR-002.79612854 — raw TOML value feed HOME.c:108-125, no FILELStat/geteuid/O_NOFOLLOW anywhere in HOME.c, home_be_subdirs multi-shard break still skips *out_count (the fail(__) with __==OK precedes the assignment). NOTHING landed; WIP fix UNLANDED in worktree ~/src/DOG-009 (HOME.c modified).