Restrict /s/* to GET and HEAD — it currently answers POST, PUT and DELETE with 200 #169
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found by the independent review of #156, which settled the question empirically rather than by reading. Deliberately NOT milestoned 1.0.0 — see below.
internal/server/routes.goattaches the static handler withMount, which registers every method, andhttp.FileServerspecial-cases only HEAD (by omitting the body).TestStaticServesEveryMethod, added by that PR, pins the current behaviour:GET,HEAD,POST,PUTandDELETEon/s/js/app.jsall return 200, with POST/PUT/DELETE returning the asset bytes.Why it is not a 1.0 blocker:
http.FileServeris strictly read-only, so there is no state change and no write path — a POST response is byte-identical to the GET. Nothing is exploitable.Why it is still worth fixing:
Allow-header and method semantics are simply wrong for the route./ssits outside the four form route groups, soMaxBodySizenever applies to it. An attacker can send an arbitrarily large body to an asset path.net/httpcaps the drain and the handler never reads it, so the exposure is a held connection rather than memory — but it is the one place where the body-size middleware's coverage has a hole.Definition of done
GETandHEADinstead of viaMount, and other methods get405with an accurateAllow: GET, HEAD.TestStaticServesEveryMethodis INVERTED rather than deleted: it must assert 405 and theAllowheader for POST/PUT/DELETE, and 200 for GET/HEAD. The test is what stops this drifting back, so it should survive the change with its meaning flipped./s/*row in the README route table is updated — it currently readsany, which #156 made accurate on purpose. Both must change together or the README goes back to lying.Implementation requirements
next, PR based onnext, single commit, title ending(closes #N).TODO.md(see #112).make bootstrap(ormake assets) in a fresh clone before gating — third-party browser assets are fetched at build time and are not committed.make checkplus the Docker lint path with the cache defeated. All linting runs in Docker, never on the host.