You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The chapter catch-all route (config/routes.rb:206, get ':id' => 'chapter#show', as: :chapter) matches every root-level path that no other route claims, and sends all of it — including scanner junk — into the controller and a database query. Adding a slug-format constraint would 404 the overwhelming majority of that traffic at the router, with zero effect on real chapter pages.
Evidence (2026-09-16, canonical log archive)
In one day, ChapterController served 4,218 requests — 7× more than any other controller. 91% were 404s:
The history (found via git archaeology): the catch-all dates to c322c5af (2014, "add local chapter page"), where it was a deliberate product choice — chapter pages at codebar.io/london rather than codebar.io/chapters/london. The URL design is still right; the unconstrained implementation predates the era of mass scanner traffic.
Chapter slugs are generated with name.parameterize (app/models/chapter.rb:78), which produces only lowercase letters, digits, and hyphens, so this constraint matches every real slug and nothing else. Paths containing dots, uppercase letters, or other characters — most of the probe traffic — would 404 at the router without touching ChapterController or the database.
Notes
This is complementary to PR feat: block scanner junk at the nginx edge #2884 (nginx edge block), which filters the observed probe classes before nginx routing. The constraint is structural: it also covers whatever the edge list misses, such as any path with a dot or uppercase character.
The remaining junk that still matches the constraint (e.g. /backup, /rclone) continues to 404 in-app as today; the edge block handles the known ones.
Testing: add a routing spec asserting the constraint (real slugs route; dotted/uppercase paths do not match). The nginx CI smoke matrix from feat: block scanner junk at the nginx edge #2884 is unaffected.
Full 2026-09-16 breakdown
4,218 canonical ChapterController#show requests vs 618 for the next controller (EventsController)
The chapter catch-all route (
config/routes.rb:206,get ':id' => 'chapter#show', as: :chapter) matches every root-level path that no other route claims, and sends all of it — including scanner junk — into the controller and a database query. Adding a slug-format constraint would 404 the overwhelming majority of that traffic at the router, with zero effect on real chapter pages.Evidence (2026-09-16, canonical log archive)
In one day,
ChapterControllerserved 4,218 requests — 7× more than any other controller. 91% were 404s:/key.pem,/id_rsa,/rclone.conf,/docker-compose.yml,/secrets.env/__vite_rsc_findSourceMapURL/z9x8c7v6b5-debug-trigger-codebar.io/shanghai,/nairobi,/brighton,/osloThe history (found via git archaeology): the catch-all dates to
c322c5af(2014, "add local chapter page"), where it was a deliberate product choice — chapter pages atcodebar.io/londonrather thancodebar.io/chapters/london. The URL design is still right; the unconstrained implementation predates the era of mass scanner traffic.Proposed change
Chapter slugs are generated with
name.parameterize(app/models/chapter.rb:78), which produces only lowercase letters, digits, and hyphens, so this constraint matches every real slug and nothing else. Paths containing dots, uppercase letters, or other characters — most of the probe traffic — would 404 at the router without touchingChapterControlleror the database.Notes
/backup,/rclone) continues to 404 in-app as today; the edge block handles the known ones.Full 2026-09-16 breakdown
ChapterController#showrequests vs 618 for the next controller (EventsController).envvariants, service-account JSONs, WordPress paths)/__vite_rsc_findSourceMapURLprobes (known Vite RSC source-map disclosure CVE scan)/z9x8c7v6b5-debug-trigger-codebar.iotargeted probes/shanghai147,/nairobi143,/brighton17,/oslo11 — all 200s