Repository navigation
Security sweep: hostile repositories, terminal, updater, DoS; tests that pin the security rules - #21
Conversation
- git: no transport for any git call (GIT_ALLOW_PROTOCOL="", GIT_NO_LAZY_FETCH=1): a partial clone's promisor remote config could run a program when blobs were read. Blank blame.ignoreRevsFile; accept viewed folders named "..x". - pty: ignore non-object JSON control frames (a throw exits the server); floor upgrade sizes. - update: the whole release tag must be a semver version. - index: new symlinks to files outside the root are not listed. - client: bidi controls isolated in the code view and HEAD peek; names, tabs, palette, blame and terminal titles show hidden characters; tabs stay tabs in diffs, search previews and Markdown code; parseTarget handles U+2028/U+2029; esc escapes single quotes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Px3ERqxxjWWCw6ty21M5S
…he checked real path Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Px3ERqxxjWWCw6ty21M5S
…idden characters The -c blame.ignoreRevsFile= override never reset the list (git sorts the values); use --no-ignore-revs-file. Breadcrumbs, the commit pill, File History details and the status bar root and branch now show controls and bidi overrides as escapes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Px3ERqxxjWWCw6ty21M5S
- http: never Bun's development error page (development:false, an error handler, Host checked before URL parsing); own-key MIME lookups; whole-byte ?limit; /api/open opens files only. - files: openRegular(abs, root) verifies the file it opened is still inside the root (a parent swapped for a symlink); backslash is a separator only on Windows. - settings: refuse deep nesting and cap the written file (indented output was quadratic). - index: files created during a build are no longer lost. - client: linear JS regex-after-word check, Go to Symbol, YAML keys, Markdown headings and bare-URL trimming (each froze the UI thread on hostile files). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Px3ERqxxjWWCw6ty21M5S
…s, survive a deleted folder - terminal: clusters capped at 64 units; REP repeats the base code point, at most a screenful; OSC 8 uri map, 2 KB targets, ids never reused; at most 256 OSC 4 answers. - pty: replay applies the mode changes in the skipped head; carry from the last escape; C1 CSI (windows-1252 decoding) and ':' sub-parameters; a hidden cursor is restored. - git: a failed spawn (viewed folder deleted) is a failed run, not an unhandled rejection that exited the server. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Px3ERqxxjWWCw6ty21M5S
…only copy on a failed swap; pin actions Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Px3ERqxxjWWCw6ty21M5S
…ssions) - git: never look inside submodules (their own filters ran via diff); fail closed when the driver listing is cut; re-list drivers per operation (included configs); rename limits, UTF-8 log output and --root forced; a timed-out diff is truncated, not clean. - server: a shell that cannot start no longer exits the server, at most 64 shells; index deletes are not quadratic; git status refresh is throttled, not starved; search reports symlinked matches under the real path and falls back to the index in an ignored folder. - client: open() line races, events-socket resync, Changes refresh on edits, Cmd+B/J in the terminal, image blob URLs revoked, IME Enter, stale gutter base, tooltips escaped; settings saved as merged PATCHes of changed keys, tabs: roots pruned, layout flushed on close. - terminal: a capped REP leaves the cursor where the full count would. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Px3ERqxxjWWCw6ty21M5S
🚀 Deploying Preview to Cloudflare 🚀Preview Deployments by commit
|
… a plain object Keys come from the request body; a Map never treats __proto__/constructor as anything but data. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Px3ERqxxjWWCw6ty21M5S
The almost-full-ring test detached its first client as soon as FLOODED appeared; a prompt printed after that reached the replay but not the client, so under load the two outputs differed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Px3ERqxxjWWCw6ty21M5S
|
Workers Builds: codeviewer (Cloudflare) is red here, but the failure doesn't come from this PR.
There's no fix to make from the repository. The Cloudflare project's build settings need a look in the dashboard. CodeQL reported one new high-severity alert on the earlier head. I couldn't read the alert from this session. The settings PATCH merge wrote request-supplied keys onto a plain object ( Generated by Claude Code |
|
Generated by Claude Code |
…omplete sanitization) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Px3ERqxxjWWCw6ty21M5S
…ecurity rules Fixes (each reproduced first): - build: never autoload bunfig.toml/.env in the compiled server (a repository's preload ran in it); the Mac app starts the server in /. - git: no index refresh and no hooks (git diff wrote the index and ran post-index-change); special files in .git (a /dev/zero symlink, FIFOs) turn git off; GIT_DIR-style variables dropped. - tokens: the app window runs --incognito (a terminal process could read the session token from the profile and type into other terminals); boot page removed on connect and on quit; token URL printed only to a terminal; no-store JSON; CORP same-origin. - search: startup root, stat before open, opened-fd containment check. - pty: a ModeTracker that mirrors the client parser (bracketed paste could be dropped on replay). - updater: strict install detection, apply installs only its own newer release, capped reads. - terminal: bell/title coalescing, legacy mouse limit, DECRQM prefix, references with command substitution refused; SVG previews from data: URLs; CSS lexer and stripLinks made linear; WebRTC disabled in the app window; Mac relaunch gated, ln -sfh; codeviewer open local-only. Tests: invariants.static, http.routes (every route), redos.matrix (every language), terminal.fuzz, files.resolve.fuzz, git.hostile-config, pty.tracker.diff. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Px3ERqxxjWWCw6ty21M5S
- codeview: one bidi marker per run, at most 32 per line (a marker per character, my regression,
made 248 000 elements); HEAD peek capped at 500 rows x 4000 columns.
- images: SVG <use> bombs (expanded reference graph, cycles) and raster decompression bombs
(PNG/GIF/JPEG/WebP/BMP headers, 50 Mpx) are refused before decoding.
- highlighter: lex at most 2000 columns, regex literals scan 512 characters, shell ${...} stops
at the next {; the slow-input matrix gained multi-character openers.
- diff: middles over 200 000 lines are one replaced hunk without interning.
- blame: a new request aborts the previous one and the server kills its git process.
- test: the palette timing comparison takes the best of five runs (it flaked 1 run in 3).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Px3ERqxxjWWCw6ty21M5S
…n tests written as escapes The budget test counted raw controls with a replace(/<span…/) (the pattern CodeQL flags as incomplete sanitization); it now counts characters. Raw U+202A-202E/2066-2069 in seven test files are \\u escapes (same values, no hidden characters in review), and a hygiene test keeps it that way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Px3ERqxxjWWCw6ty21M5S
test (macos-15) failed 'many list lines: doubling the input costs less than 3x' at 3.0x. The parser grows 2.1x per doubling; all test files share one process, and the heavier suite on this branch left garbage whose collection landed inside a sample. The timing helpers in markdown.limits, fuzzy and the slow-input matrix now run Bun.gc(true) before each sample (best of five in markdown.limits). With a large live heap the measured ratio peaked at 2.85x before and 2.48x after; the bounds are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Px3ERqxxjWWCw6ty21M5S
This PR collects one manual review and four adversarial review passes (the last by eight reviewers, each on a separate area). Each finding was reproduced before it was fixed, and each fix has a regression test. DESIGN.md §24 has the findings → fixes tables; SECURITY.md is updated.
Critical
Opening a folder ran its code. The compiled server autoloaded
bunfig.tomland.envfrom its working directory, which is often the viewed folder, so a repository's preload script ran inside the server. Fixed with--no-compile-autoload-*; the Mac app now starts the server in/.Git ran programs named by the repository:
git diff;git diffrewrote the index and ran thepost-index-changehook.Now: no transports, no hooks, no index refresh, submodules ignored, and the driver overrides fail closed and are rebuilt for every operation.
High and medium
--incognito, and the boot page is removed as soon as the page connects..git(a/dev/zerosymlink, a FIFO) could exhaust memory; git is now turned off for such a folder.data:URLs; SVG<use>bombs and image decompression bombs refused before decoding.Tests
The suite went from 1368 to 1459 tests. New files:
invariants.static— the AGENTS.md rules, checked against the source.http.routes— every route found inhttp.ts: auth, Host, CSRF, headers.redos.matrix— every highlighter and Go to Symbol language, plus the Markdown parser, against pathological input.terminal.fuzz— seeded hostile terminal output.files.resolve.fuzz— random paths through symlinks in and out of the root.git.hostile-config— every hook and program-naming key armed;.gitis snapshotted before and after.pty.tracker.diff— differential check of the server's mode tracking against the page's parser.Needs a Mac
packaging/macos/main.swiftchanged but could not be compiled here:/ln -sfhRun
xcrun swiftc -typecheck -target arm64-apple-macos13.3 -framework Cocoa -framework WebKit packaging/macos/main.swiftbefore merging.Recommendations (not done here)
main.main.🤖 Generated with Claude Code
https://claude.ai/code/session_011Px3ERqxxjWWCw6ty21M5S