docs: secure-coding rules for agents, and refresh stale AGENTS.md top-matter #16

Merged
sulthan merged 2 commits from docs/agent-security-rules into main 2026-08-06 20:07:35 +07:00
Owner

Two doc commits: a new secure-coding rules section, plus a fix for top-matter the rebrand left stale.

9156525 — secure-coding rules

AGENTS.md carried two security invariants (bearer auth, CORS) but nothing about the code an agent actually writes here. That is the gap worth closing: measured rates for AI-generated web/backend code are ~40% vulnerable (Pearce et al.), 45% failing security tests (Veracode 2025), and users with assistants shipped SQLi at 36% vs 7% for the control group (Perry et al., Stanford). The failure classes cluster on broken access control, injection, session/error handling and invented dependencies — all live surfaces in this repo.

Rules were extracted, not pasted. Every one names a guard that already exists in-tree, so the instruction is match this, not invent something:

Rule Existing anchor
parameterized SQL only; constants may concatenate store.go — all queries use ?
html/template only; no template.HTML on stored data web.go:85
client-supplied URLs pass the fetch gate poller.go:144 fetchableSeriesURL
cap remote bodies fetch.go:16 maxBodyBytes
subtle.ConstantTimeCompare, never == middleware.go:22, session.go:61
generic error out, detail to log, never log the token web.go:151
X-Forwarded-Proto for Secure; rightmost XFF for IP session.go:68,101
cookie flags; expiry checked before signature session.go:72-94, Verify
validate at handler boundary handlers.go:48 MaxBytesReader 64 KB, 400 on bad key/status/kind
site strings via el({text}), never {html} el() in both userscripts
fetch()/authHeaders() → API_BASE only existing authHeaders
localStorage = cache/queue, never credentials shared with site JS

Plus a dependency rule (stdlib first; verify a package exists before adding — ~20% of LLM-proposed packages don't resolve, which is the slopsquatting vector) and a review gate marking auth/CORS/session/crypto/fetch-gate as security-critical.

Deliberately excluded: container signing, k8s admission control, IaC scanning, PII/HIPAA/PCI, C/C++ memory safety. Per OpenSSF's guide for AI assistant instructions, irrelevant rules make a model generate code compensating for attacks that cannot happen. None of those apply to a single-user Go + SQLite + userscript stack.

Sources: OWASP AISVS 1.0 Appendix C, OWASP Top 10 / ASVS v5, OpenSSF Security-Focused Guide for AI Code Assistant Instructions (2025-08-01).

5d4d890 — stale top-matter

The rebrand rewrote root AGENTS.md as a compression pass and switched Bromite -> Violentmonkey, but left the project described as a manga-only tracker over two sites. Six sites, two libraries and two userscripts now exist.

Root AGENTS.md:

  • What this is names both scripts with their site lists, the kind column, and the <site>:<series_id> key shape.
  • Origins constraint generalised past Asura/Demonic.
  • Records that kagane and novelfull are reliably Cloudflare-challenged and browser-polled over CDP. Without it that bullet list reads as contradicting the code, since the paragraph above asserts blocking is "not universal — and not reliably reproducible".
  • Diagram says two userscripts.

backend/AGENTS.md — two instances of the same defect, found while verifying the above:

  • Store key list gained novelfull|lightnovelworld and the kind column.
  • NOVEL_USERSCRIPT_PATH documented — it shipped in main.go:150 undocumented.

The dated Cloudflare paragraph is left verbatim: it is a timestamped observation ("Verified 2026-07-26"), so rewriting it would falsify a record rather than update it. userscript/AGENTS.md is untouched; it already documents both novel adapters and the LIBRARY/STORE_PREFIX split.

Verification

Docs-only, no code touched. Every code reference above was read at 4229c17 before being cited — the fetch gate, body cap, constant-time compares, cookie flags, handler validation, el() helper and both route registrations. No invented line numbers.

Not addressed here

The API_TOKEN literal is committed in plaintext in both userscripts and in their @downloadURL/@updateURL lines. The new rules say not to propagate it, but the actual remedy is rotation plus build-time substitution, since the value is already in git history. Separate change; flagging it so it does not get lost.

Two doc commits: a new secure-coding rules section, plus a fix for top-matter the rebrand left stale. ## `9156525` — secure-coding rules `AGENTS.md` carried two security invariants (bearer auth, CORS) but nothing about the code an agent actually writes here. That is the gap worth closing: measured rates for AI-generated web/backend code are ~40% vulnerable (Pearce et al.), 45% failing security tests (Veracode 2025), and users *with* assistants shipped SQLi at 36% vs 7% for the control group (Perry et al., Stanford). The failure classes cluster on broken access control, injection, session/error handling and invented dependencies — all live surfaces in this repo. Rules were **extracted, not pasted**. Every one names a guard that already exists in-tree, so the instruction is *match this*, not *invent something*: | Rule | Existing anchor | | --- | --- | | parameterized SQL only; constants may concatenate | `store.go` — all queries use `?` | | `html/template` only; no `template.HTML` on stored data | `web.go:85` | | client-supplied URLs pass the fetch gate | `poller.go:144 fetchableSeriesURL` | | cap remote bodies | `fetch.go:16 maxBodyBytes` | | `subtle.ConstantTimeCompare`, never `==` | `middleware.go:22`, `session.go:61` | | generic error out, detail to log, never log the token | `web.go:151` | | `X-Forwarded-Proto` for Secure; **rightmost** XFF for IP | `session.go:68,101` | | cookie flags; expiry checked before signature | `session.go:72-94`, `Verify` | | validate at handler boundary | `handlers.go:48` `MaxBytesReader` 64 KB, 400 on bad key/status/kind | | site strings via `el({text})`, never `{html}` | `el()` in both userscripts | | `fetch()`/`authHeaders()` → `API_BASE` only | existing `authHeaders` | | `localStorage` = cache/queue, never credentials | shared with site JS | Plus a dependency rule (stdlib first; verify a package exists before adding — ~20% of LLM-proposed packages don't resolve, which is the slopsquatting vector) and a review gate marking auth/CORS/session/crypto/fetch-gate as security-critical. Deliberately **excluded**: container signing, k8s admission control, IaC scanning, PII/HIPAA/PCI, C/C++ memory safety. Per OpenSSF's guide for AI assistant instructions, irrelevant rules make a model generate code compensating for attacks that cannot happen. None of those apply to a single-user Go + SQLite + userscript stack. Sources: OWASP AISVS 1.0 Appendix C, OWASP Top 10 / ASVS v5, OpenSSF *Security-Focused Guide for AI Code Assistant Instructions* (2025-08-01). ## `5d4d890` — stale top-matter The rebrand rewrote root `AGENTS.md` as a compression pass and switched Bromite -> Violentmonkey, but left the project described as a manga-only tracker over two sites. Six sites, two libraries and two userscripts now exist. Root `AGENTS.md`: - *What this is* names both scripts with their site lists, the `kind` column, and the `<site>:<series_id>` key shape. - Origins constraint generalised past Asura/Demonic. - Records that **kagane and novelfull are reliably Cloudflare-challenged** and browser-polled over CDP. Without it that bullet list reads as contradicting the code, since the paragraph above asserts blocking is "not universal — and not reliably reproducible". - Diagram says two userscripts. `backend/AGENTS.md` — two instances of the same defect, found while verifying the above: - Store key list gained `novelfull|lightnovelworld` and the `kind` column. - **`NOVEL_USERSCRIPT_PATH` documented** — it shipped in `main.go:150` undocumented. The dated Cloudflare paragraph is left verbatim: it is a timestamped observation ("Verified 2026-07-26"), so rewriting it would falsify a record rather than update it. `userscript/AGENTS.md` is untouched; it already documents both novel adapters and the `LIBRARY`/`STORE_PREFIX` split. ## Verification Docs-only, no code touched. Every code reference above was read at `4229c17` before being cited — the fetch gate, body cap, constant-time compares, cookie flags, handler validation, `el()` helper and both route registrations. No invented line numbers. ## Not addressed here The `API_TOKEN` literal is committed in plaintext in both userscripts and in their `@downloadURL`/`@updateURL` lines. The new rules say not to propagate it, but the actual remedy is rotation plus build-time substitution, since the value is already in git history. Separate change; flagging it so it does not get lost.
sulthan added 2 commits 2026-08-06 20:05:41 +07:00
Repo had two security invariants (bearer auth, CORS) but no guidance for
code an agent writes. Studies put AI-generated web/backend code at ~40%
vulnerable, concentrated in broken access control, injection, session and
error handling — the exact surfaces here.

Rules are extracted, not pasted from a generic checklist: each one names a
guard that already exists in-tree (fetchableSeriesURL, maxBodyBytes,
ConstantTimeCompare, MaxBytesReader, el({text})), so the instruction is
match-this rather than invent-something. Per OpenSSF guidance, irrelevant
rules make a model generate code compensating for attacks that cannot
happen, so container signing, IaC, PII and memory-safety items are left out.
The rebrand (4229c17) rewrote root AGENTS.md as a compression pass and
switched Bromite->Violentmonkey, but the description still called the
project a manga-only tracker over two sites. Six sites, two libraries and
two userscripts now exist.

Root AGENTS.md:
- 'What this is' names both scripts and their sites, the kind column, and
  the <site>:<series_id> key shape.
- Origins constraint generalised past Asura/Demonic.
- Records that kagane and novelfull are reliably Cloudflare-challenged and
  browser-polled, which is the standing exception to the 'blocking is
  IP-reputation-based and not reproducible' note directly above it.
- Diagram says two userscripts.

backend/AGENTS.md:
- Store key list gained novelfull|lightnovelworld and the kind column.
- NOVEL_USERSCRIPT_PATH documented; it shipped in main.go:150 undocumented.

Child userscript/AGENTS.md already covered the novel adapters, so it is
untouched.
sulthan merged commit b9f9aea82c into main 2026-08-06 20:07:35 +07:00
Sign in to join this conversation.