file remaining review #5 issues #115-#117
Message
file remaining review #5 issues #115-#117
Diff
.forge/issues/84471c41-0394-4e55-a408-0a4fbd5f6fff/issue.md+31 −0
--- /dev/null+++ b/.forge/issues/84471c41-0394-4e55-a408-0a4fbd5f6fff/issue.md@@ -0,0 +1,31 @@1+---2+id: 84471c41-0394-4e55-a408-0a4fbd5f6fff3+title: serve omits the Referrer-Policy header that Pages sends globally4+state: open5+labels:6+- kind:security7+assignees: []8+milestone: null9+created: 2026-10-27T19:38:02.842303681Z10+updated: null11+---12+## Problem13+14+`hu13 serve` does not send the `Referrer-Policy: strict-origin-when-cross-origin` header that the generated Pages `_headers` file applies to every path. Static responses are therefore not single-shape and can leak full internal URLs/paths as referrers.15+16+Verified:17+18+```19+$ curl -I http://127.0.0.1:39444/20+HTTP/1.1 200 OK21+Content-Type: text/html; charset=utf-822+Content-Length: 1580623+X-Content-Type-Options: nosniff24+Connection: close25+```26+27+No `Referrer-Policy`. `src/build.rs` `HEADERS_FILE` carries it for Pages; `src/serve.rs` `respond`/`respond_file_head` do not.28+29+## Fix30+31+Send the same `Referrer-Policy` on static, 404, and inbox responses (or explicitly document why `serve` differs); add a header parity test.
.forge/issues/b05b67af-8f59-4937-9107-8bee57577889/issue.md+30 −0
--- /dev/null+++ b/.forge/issues/b05b67af-8f59-4937-9107-8bee57577889/issue.md@@ -0,0 +1,30 @@1+---2+id: b05b67af-8f59-4937-9107-8bee575778893+title: Pages inbox quota stops checking at 1000 objects; rate map has no hard cap4+state: open5+labels:6+- kind:security7+assignees: []8+milestone: null9+created: 2026-10-27T19:38:20.426674442Z10+updated: null11+---12+## Problem13+14+The Pages inbox quota is only checked against the first 1000 R2 objects. `overQuota` calls `bucket.list({ limit: Math.min(limit, 1000) })` once; if `INBOX_QUOTA` is above 1000, submissions keep being stored after the limit because the returned list can never reach the configured quota.15+16+Verified with the real `onRequestPost` and a fake bucket containing 1001 objects, `INBOX_QUOTA=1500`:17+18+```19+status 200 stored 100220+```21+22+Expected 503. `functions/inbox/[kind].js:276-279`.23+24+The isolate-local rate-limit map also has no hard cap: it only prunes expired entries when `size > 10000`, so an attacker rotating source IPs can keep growing it. Cloudflare's WAF rule is the documented durable control, but the in-function map should still fail closed at a fixed key limit like `serve`'s `RATE_MAX_KEYS` (f0rge #65).25+26+## Fix27+28+- Paginate `bucket.list` with `cursor` until `limit` objects are counted or the list ends.29+- Add a hard `MAX_KEYS` check for new rate-limit keys after the expiry sweep.30+- Add Node tests for quota 1500 and the rate-map cap.
.forge/issues/e366f211-4815-4f08-8003-56c5b11f8b6b/issue.md+31 −0
--- /dev/null+++ b/.forge/issues/e366f211-4815-4f08-8003-56c5b11f8b6b/issue.md@@ -0,0 +1,31 @@1+---2+id: e366f211-4815-4f08-8003-56c5b11f8b6b3+title: serve prepare_git_dir follows a repo.bundle symlink outside www4+state: open5+labels:6+- kind:security7+assignees: []8+milestone: null9+created: 2026-10-27T19:38:26.533319234Z10+updated: null11+---12+## Problem13+14+`serve`'s smart-HTTP setup clones `www/repo.bundle` without the static path's symlink/prefix check. A symlinked bundle pointing outside `www` is materialized and advertised by `/repo.bundle/info/refs`, so a local symlink can expose a private repository over HTTP.15+16+Verified:17+18+```19+ln -s /tmp/rev5-private.bundle /tmp/rev5-bundle-www/repo.bundle20+hu13 serve --www /tmp/rev5-bundle-www --inbox-dir /tmp/rev5-bundle-inbox --listen 127.0.0.1:3944321+curl 'http://127.0.0.1:39443/repo.bundle/info/refs?service=git-upload-pack'22+HTTP/1.1 200 OK23+Content-Type: application/x-git-upload-pack-advertisement24+0000000 0 0 1 e # s e r v i c e = g i t - u p l o a d - p a c k25+```26+27+The normal static `/repo.bundle` route rejects the outside symlink; only `prepare_git_dir` follows it. `src/serve.rs:119-150`.28+29+## Fix30+31+Resolve `www/repo.bundle` and require the target to stay under resolved `www` (or reject symlinks entirely) before `git clone --bare`. Add a symlinked-bundle integration test asserting `/repo.bundle/info/refs` is 404.