check / check (push) Failing after 25m20s
Each app's fixes are one .conf file and one entry in apps. They apply only while Inspect has set the app's transaction variable, such as tx.app_gitea. SWW_APPS names each hostname's apps. A hostname gets only its apps' fixes; while SWW_APPS is unset, every hostname gets every app's fixes. A hostname in SWW_APPS that is not a DNS name, such as *.example.com, stops the start. Unset, SWW_APPS is logged at start as null; set empty, as "". Model: opus-5-5
207 lines
10 KiB
Plaintext
207 lines
10 KiB
Plaintext
# WordPress's fixes: on WordPress's paths, some fields skip the rules that refused
|
|
# ordinary WordPress requests there. Each exclusion runs with the request, before
|
|
# the rules it switches off, so this file is loaded before the Core Rule Set's
|
|
# rules. Each comment names a request the rule refused. An exclusion on a field
|
|
# of a body applies only when the query has no parameter of that name, so it
|
|
# matters only while SWW_WAF_BODY_LIMIT is set.
|
|
|
|
# Unless SWW_APPS lists wordpress for the request's hostname, every rule below is
|
|
# skipped. Inspect sets tx.app_wordpress when it does.
|
|
# The skip reaches only phase 1, so a rule of a later phase must check
|
|
# tx.app_wordpress itself.
|
|
SecRule &TX:app_wordpress "@eq 0" \
|
|
"id:900690,phase:1,pass,nolog,skipAfter:END_WORDPRESS"
|
|
|
|
# WordPress takes a call to its REST API at any of four addresses:
|
|
# /wp-json/wp/v2/posts/1
|
|
# /index.php/wp-json/wp/v2/posts/1
|
|
# /index.php?rest_route=/wp/v2/posts/1
|
|
# /?rest_route=/wp/v2/posts/1
|
|
# These two rules put the route, here /wp/v2/posts/1, in tx.rest_route for the
|
|
# exclusions below. A call that names a route in both its path and its query
|
|
# gets none of them, since WordPress follows the query.
|
|
SecRule &ARGS_GET:rest_route "@eq 0" "id:900705,phase:1,pass,nolog,chain"
|
|
SecRule REQUEST_FILENAME "@rx ^/(?:index\.php/)?wp-json(/.*)$" \
|
|
"capture,setvar:tx.rest_route=%{tx.1}"
|
|
SecRule REQUEST_FILENAME "@rx ^/(?:index\.php)?$" "id:900706,phase:1,pass,nolog,chain"
|
|
SecRule ARGS_GET:rest_route "@rx ^(/.*)$" "capture,setvar:tx.rest_route=%{tx.1}"
|
|
|
|
# The block editor saves a post with POST and the header X-HTTP-Method-Override:
|
|
# PUT, which the Core Rule Set refused (920450). So does saving a user's editor
|
|
# preferences.
|
|
SecRule TX:rest_route "@beginsWith /" \
|
|
"id:900700,phase:1,pass,nolog,\
|
|
ctl:ruleRemoveTargetById=920450;REQUEST_HEADERS_NAMES:X-HTTP-Method-Override"
|
|
|
|
# The block editor and the site editor send HTML in the JSON field content, which
|
|
# skips these rules when saving or autosaving a post, a page, a template or a
|
|
# template part:
|
|
# 930120: cat /etc/hosts
|
|
# 932230: a code block with a shell pipeline and an SQL query
|
|
# 932250: the same code block
|
|
# 934100: console.log('ok')
|
|
# 941100: <iframe src="..." onload="...">
|
|
# 941110: <script>
|
|
# 941120: onload=
|
|
# 941160: <img src=
|
|
# 941180: <!-- wp:paragraph -->, the comment that starts every block
|
|
# 941390: console.log(
|
|
# 942190: how to select a table from the catalog
|
|
# 942270: how to select a table from the catalog
|
|
SecRule TX:rest_route \
|
|
"@rx ^/wp/v2/(?:(?:posts|pages)(?:/[0-9]+(?:/autosaves)?)?|template(?:s|-parts)(?:/[^/]+//[^/]+(?:/autosaves)?)?)$" \
|
|
"id:900701,phase:1,pass,nolog,chain"
|
|
SecRule &ARGS_GET:json.content "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=930120;ARGS:json.content,\
|
|
ctl:ruleRemoveTargetById=932230;ARGS:json.content,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:json.content,\
|
|
ctl:ruleRemoveTargetById=934100;ARGS:json.content,\
|
|
ctl:ruleRemoveTargetById=941100;ARGS:json.content,\
|
|
ctl:ruleRemoveTargetById=941110;ARGS:json.content,\
|
|
ctl:ruleRemoveTargetById=941120;ARGS:json.content,\
|
|
ctl:ruleRemoveTargetById=941160;ARGS:json.content,\
|
|
ctl:ruleRemoveTargetById=941180;ARGS:json.content,\
|
|
ctl:ruleRemoveTargetById=941390;ARGS:json.content,\
|
|
ctl:ruleRemoveTargetById=942190;ARGS:json.content,\
|
|
ctl:ruleRemoveTargetById=942270;ARGS:json.content"
|
|
|
|
# A reply to a comment from the list of comments, in content:
|
|
# 932125: ls -la, in the reply's text
|
|
# 932230: ls -la, in the reply's text
|
|
# 932250: ls -la, in the reply's text
|
|
SecRule REQUEST_FILENAME "@streq /wp-admin/admin-ajax.php" \
|
|
"id:900702,phase:1,pass,nolog,chain"
|
|
SecRule &ARGS_GET:content "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=932125;ARGS:content,\
|
|
ctl:ruleRemoveTargetById=932230;ARGS:content,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:content"
|
|
|
|
# Saving a plugin's or a theme's file from its file editor sends the file in
|
|
# newcontent, which skips these rules, each of which refused saving the plugin
|
|
# Hello Dolly's hello.php. Some of them refused only the whole file:
|
|
# 932140: if ( 'en_' !== substr(
|
|
# 932235: the whole file
|
|
# 933100: the whole file
|
|
# 933160: if ( 'en_' !== substr(
|
|
# 933210: $lyrics = explode(
|
|
# 941100: <style type='text/css'>
|
|
# 941160: <style type='text/css'>
|
|
# 941190: the whole file
|
|
# 942151: if ( 'en_' !== substr(
|
|
# 942540: Dolly'll never go away again";
|
|
SecRule REQUEST_FILENAME "@streq /wp-admin/admin-ajax.php" \
|
|
"id:900703,phase:1,pass,nolog,chain"
|
|
SecRule &ARGS_GET:newcontent "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=932140;ARGS:newcontent,\
|
|
ctl:ruleRemoveTargetById=932235;ARGS:newcontent,\
|
|
ctl:ruleRemoveTargetById=933100;ARGS:newcontent,\
|
|
ctl:ruleRemoveTargetById=933160;ARGS:newcontent,\
|
|
ctl:ruleRemoveTargetById=933210;ARGS:newcontent,\
|
|
ctl:ruleRemoveTargetById=941100;ARGS:newcontent,\
|
|
ctl:ruleRemoveTargetById=941160;ARGS:newcontent,\
|
|
ctl:ruleRemoveTargetById=941190;ARGS:newcontent,\
|
|
ctl:ruleRemoveTargetById=942151;ARGS:newcontent,\
|
|
ctl:ruleRemoveTargetById=942540;ARGS:newcontent"
|
|
|
|
# Signing in, in pwd, where a password holds any characters:
|
|
# 930120: a password ending in /etc/hosts
|
|
SecRule REQUEST_FILENAME "@streq /wp-login.php" \
|
|
"id:900704,phase:1,pass,nolog,chain"
|
|
SecRule &ARGS_GET:pwd "@eq 0" "ctl:ruleRemoveTargetById=930120;ARGS:pwd"
|
|
|
|
# Saving through the REST API, the JSON fields title, excerpt and name skip these
|
|
# rules. WordPress writes a slug such as htaccess or ls-la, so slug skips only
|
|
# 932120 and 932260:
|
|
# 930120: .htaccess
|
|
# 932120: powershell
|
|
# 932250: ls -la
|
|
# 932260: python3
|
|
SecRule TX:rest_route "@beginsWith /wp/v2/" "id:900712,phase:1,pass,nolog,chain"
|
|
SecRule &ARGS_GET:/^json\.(?:title|excerpt|slug|name)$/ "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=930120;ARGS:/^json\.(?:title|excerpt|name)$/,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:/^json\.(?:title|excerpt|slug|name)$/,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:/^json\.(?:title|excerpt|name)$/,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:/^json\.(?:title|excerpt|slug|name)$/"
|
|
|
|
# A comment's author gives the address of their site in url, which skips these
|
|
# rules there:
|
|
# 930120: http://blog.example/.htaccess
|
|
# 932120: http://blog.example/powershell-basics/
|
|
SecRule REQUEST_FILENAME "@streq /wp-comments-post.php" \
|
|
"id:900713,phase:1,pass,nolog,chain"
|
|
SecRule &ARGS_GET:url "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=930120;ARGS:url,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:url"
|
|
|
|
# The block editor's link previews and embeds send an address in url, which
|
|
# skips these rules there:
|
|
# 930120: http://blog.example/.htaccess
|
|
# 932120: http://blog.example/powershell-basics/
|
|
SecRule TX:rest_route "@rx ^/(?:wp-block-editor/v1/url-details|oembed/1\.0/proxy)$" \
|
|
"id:900714,phase:1,pass,nolog,\
|
|
ctl:ruleRemoveTargetById=930120;ARGS:url,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:url"
|
|
|
|
# The plugin and theme file editors name the file open in file, which skips
|
|
# these rules there:
|
|
# 930120: akismet/views/config.php
|
|
# 932120: install-script.sh
|
|
# 932160: bin/install.sh
|
|
# 932260: docker-compose.yml
|
|
# 941180: document.write.js
|
|
SecRule REQUEST_FILENAME "@rx ^/wp-admin/(?:plugin|theme)-editor\.php$" \
|
|
"id:900709,phase:1,pass,nolog,\
|
|
ctl:ruleRemoveTargetById=930120;ARGS:file,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:file,\
|
|
ctl:ruleRemoveTargetById=932160;ARGS:file,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:file,\
|
|
ctl:ruleRemoveTargetById=941180;ARGS:file"
|
|
|
|
# Searches, the names of tags, categories, plugins, themes and plugins' settings
|
|
# pages, and addresses can hold any word. In the fields of the next three rules,
|
|
# each request skips the rules that refused such words:
|
|
# 930120: .htaccess
|
|
# 932120: powershell
|
|
# 932250: ls -la
|
|
# 932260: python3
|
|
# An address repeats the search it came from, so only the addresses of the first
|
|
# group also skip:
|
|
# 932235: python3, in the address of a page of results
|
|
|
|
# All of wp-admin, and signing in. A plugin's settings page is named in page.
|
|
# The site editor names a template in p and postId, and a plugin to install is
|
|
# named in slug. WordPress writes these three as slugs, such as htaccess or
|
|
# ls-la, so they skip only 932120 and 932260. Names are matched in lower case,
|
|
# so postId is written postid.
|
|
SecRule REQUEST_FILENAME "@rx ^/(?:wp-admin/|wp-login\.php$)" \
|
|
"id:900707,phase:1,pass,nolog,\
|
|
ctl:ruleRemoveTargetById=930120;ARGS:/^(?:s|search|q|term|tag|category_name|plugin|checked\[\]|theme|stylesheet|page|url|return|redirect_to|wp_http_referer|_wp_http_referer)$/,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:/^(?:s|search|q|term|tag|category_name|plugin|checked\[\]|theme|stylesheet|page|p|postid|slug|url|return|redirect_to|wp_http_referer|_wp_http_referer)$/,\
|
|
ctl:ruleRemoveTargetById=932235;ARGS:/^(?:url|return|redirect_to|wp_http_referer|_wp_http_referer)$/,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:s|search|q|term|tag|category_name|plugin|checked\[\]|theme|stylesheet|page|url|return|redirect_to|wp_http_referer|_wp_http_referer)$/,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:s|search|q|term|tag|category_name|plugin|checked\[\]|theme|stylesheet|page|p|postid|slug|url|return|redirect_to|wp_http_referer|_wp_http_referer)$/"
|
|
|
|
# Every route of WordPress's own REST API, and the embed address each post links
|
|
# to.
|
|
SecRule TX:rest_route "@rx ^/(?:wp/v2/|oembed/1\.0/embed$)" \
|
|
"id:900708,phase:1,pass,nolog,\
|
|
ctl:ruleRemoveTargetById=930120;ARGS:/^(?:search|term|slug|url)$/,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:/^(?:search|term|slug|url)$/,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:search|term|slug|url)$/,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:search|term|slug|url)$/"
|
|
|
|
# The site's own pages, and the later pages of a search.
|
|
SecRule REQUEST_FILENAME "@rx ^/(?:(?:index\.php/)?page/[0-9]+/?|index\.php)?$" \
|
|
"id:900710,phase:1,pass,nolog,\
|
|
ctl:ruleRemoveTargetById=930120;ARGS:/^(?:s|tag)$/,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:/^(?:s|tag)$/,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:s|tag)$/,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:s|tag)$/"
|
|
|
|
# The media list sends its own address in _wp_http_referer, which ends in &ps and
|
|
# so skips 932340 there.
|
|
SecRule REQUEST_FILENAME "@streq /wp-admin/upload.php" \
|
|
"id:900711,phase:1,pass,nolog,ctl:ruleRemoveTargetById=932340;ARGS:_wp_http_referer"
|
|
|
|
SecMarker END_WORDPRESS
|