Core Rule Set: Ghost's ordinary requests pass by default (closes #357)
check / check (push) Waiting to run

Ghost 6.76.0's ordinary traffic, recorded in `testdata/ghost-requests.txt`,
passes at the default settings and while bodies are read. It covers public
pages, members' sign-up and sign-in, the admin, the editor saving and
publishing posts and pages with code blocks and HTML cards, tags, settings,
staff invitations, uploads, newsletter settings, and both APIs. The new
`ghost.conf`, the sixteenth change, lets through `filter`, the member
`search` and the embed `url` in the query, and plain text, addresses,
articles, code injection and passwords in JSON bodies. A `<script>` element
and a `javascript:` link stay refused in articles and code injection.
`README.md` lists Ghost; `SPEC.md` lists the change.

Model: opus-5-5
This commit is contained in:
sneak committed 2026-11-11 13:39:09 +00:00
1 parent 883969a9cd
commit 9cc13ad01f
8 files changed
+1447 -13

No files matched your search

+16 -5
View File
@@ -1,6 +1,6 @@
// Package coreruleset runs the OWASP Core Rule Set 4.25.0, through Coraza, on the
// method, the URL with its query and the headers of a request, and on its
// body while SWW_WAF_BODY_LIMIT is set, with the fifteen changes sww
// body while SWW_WAF_BODY_LIMIT is set, with the sixteen changes sww
// makes to it and the exclusions in SWW_CORE_RULE_SET_EXCLUSIONS_FILE, as
// "Attack detection" under "Settings" in SPEC.md describes them. It reads no
// response.
@@ -36,7 +36,8 @@ import (
// giteaExclusions for the third, wordpressExclusions for the fourth,
// drupalExclusions for the fifth, mediawikiExclusions for the sixth,
// mastodonExclusions for the seventh, vaultwardenExclusions for the eighth,
// nextcloudExclusions for the ninth, and forgejoExclusions for the tenth.
// nextcloudExclusions for the ninth, forgejoExclusions for the tenth, and
// ghostExclusions for the eleventh.
// Each rule sww adds has an id from 900000 to 900999, the ids the
// Core Rule Set keeps for the rules that set it up, which
// SWW_WAF_DISABLED_RULES and the exclusions file refuse, so that no
@@ -105,7 +106,10 @@ SecRule ARGUMENTS_LIMIT_REACHED "@eq 1" "id:900300,phase:2,pass,\
# So does the fourteenth.
%s
# And the fifteenth.
# So does the fifteenth.
%s
# And the sixteenth.
%s
# The sixth: only the rules for requests are loaded, and no response is
@@ -249,6 +253,13 @@ var nextcloudExclusions string
//go:embed forgejo.conf
var forgejoExclusions string
// ghostExclusions are the sixteenth change: the fields of Ghost's own
// requests that skip the rules that refused them there, as Coraza
// directives.
//
//go:embed ghost.conf
var ghostExclusions string
// cookiesNotRead are the cookies the Core Rule Set reads a request
// without, the rest of the fifth change. flash is Forgejo's name for
// gitea_flash.
@@ -363,7 +374,7 @@ type CoreRuleSet struct {
bodyLimit int64
}
// New returns the Core Rule Set with the fifteen changes, at params'
// New returns the Core Rule Set with the sixteen changes, at params'
// paranoia level, without the rules it switches off, reading request
// bodies up to params' limit, and with params' exclusions file loaded
// before the Core Rule Set's rules. An exclusions file is an error if it
@@ -393,7 +404,7 @@ func New(params Params) (*CoreRuleSet, error) {
text := fmt.Sprintf(directives, params.ParanoiaLevel, body, exclusions,
giteaExclusions, wordpressExclusions, drupalExclusions,
mediawikiExclusions, mastodonExclusions, vaultwardenExclusions,
nextcloudExclusions, forgejoExclusions)
nextcloudExclusions, forgejoExclusions, ghostExclusions)
if len(params.DisabledRules) > 0 {
ids := make([]string, len(params.DisabledRules))