# The twelfth change: on Mastodon's paths, some fields skip the rules that # refused ordinary Mastodon requests there. They are the fields where Mastodon # sends a search, a name, a title, a file name, an address or free text. 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 # a 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. # # Gitea serves /api/v1/ too, and Drupal serves /admin/. So only Mastodon's own # resources under them count as Mastodon's paths. # # Four rules read a search, a name or free text as a command or a system file. # Each exclusion below for such a field removes these four, and only these: # 930120: .htaccess # 932120: powershell # 932250: ls -la # 932260: python3 # The API's searches and names, in the query: # q: /api/v2/search?q=python3, /api/v1/accounts/search?q=ls+-la # acct: /api/v1/accounts/lookup?acct=python3 # username, display_name, email, by_domain: the admin API's search of # accounts, /api/v1/admin/accounts?username=python3&display_name=powershell SecRule REQUEST_FILENAME "@rx ^/api/v[12]/(?:search|accounts|admin/accounts)(?:/|$)" \ "id:900950,phase:1,pass,nolog,\ ctl:ruleRemoveTargetById=930120;ARGS:/^(?:q|acct|username|display_name|email|by_domain)$/,\ ctl:ruleRemoveTargetById=932120;ARGS:/^(?:q|acct|username|display_name|email|by_domain)$/,\ ctl:ruleRemoveTargetById=932250;ARGS:/^(?:q|acct|username|display_name|email|by_domain)$/,\ ctl:ruleRemoveTargetById=932260;ARGS:/^(?:q|acct|username|display_name|email|by_domain)$/" # The API's titles, names and free text, in form data or JSON bodies: # spoiler_text, poll[options][]: posting, spoiler_text=python3+details # description: describing an uploaded file, description=Screenshot+of+ls+-la # display_name, note, fields_attributes[0][name], fields_attributes[0][value]: # editing a profile, note=python3+and+powershell # title: naming a list or a filter, title=python3+friends # keyword, keywords_attributes[][keyword]: a filter's words, keyword=powershell # name: featuring a hashtag, name=python3 # comment: a report, a note on an account or an IP block, comment=Knows+python3 # text: warning an account, text=Please+stop+posting+powershell+malware # private_comment, public_comment: blocking a domain SecRule REQUEST_FILENAME "@rx ^/api/v[12]/(?:statuses|media|accounts|lists|filters|featured_tags|reports|admin/(?:accounts|domain_blocks|ip_blocks))(?:/|$)" \ "id:900951,phase:1,pass,nolog,chain" SecRule &ARGS_GET:/^(?:spoiler_text|poll\[options\]\[\]|description|display_name|note|fields_attributes\[\d+\]\[(?:name|value)\]|title|keyword|keywords_attributes\[\d*\]\[keyword\]|name|comment|text|private_comment|public_comment|json\.(?:spoiler_text|title|poll\.options\.\d+))$/ "@eq 0" \ "ctl:ruleRemoveTargetById=930120;ARGS:/^(?:spoiler_text|poll\[options\]\[\]|description|display_name|note|fields_attributes\[\d+\]\[(?:name|value)\]|title|keyword|keywords_attributes\[\d*\]\[keyword\]|name|comment|text|private_comment|public_comment|json\.(?:spoiler_text|title|poll\.options\.\d+))$/,\ ctl:ruleRemoveTargetById=932120;ARGS:/^(?:spoiler_text|poll\[options\]\[\]|description|display_name|note|fields_attributes\[\d+\]\[(?:name|value)\]|title|keyword|keywords_attributes\[\d*\]\[keyword\]|name|comment|text|private_comment|public_comment|json\.(?:spoiler_text|title|poll\.options\.\d+))$/,\ ctl:ruleRemoveTargetById=932250;ARGS:/^(?:spoiler_text|poll\[options\]\[\]|description|display_name|note|fields_attributes\[\d+\]\[(?:name|value)\]|title|keyword|keywords_attributes\[\d*\]\[keyword\]|name|comment|text|private_comment|public_comment|json\.(?:spoiler_text|title|poll\.options\.\d+))$/,\ ctl:ruleRemoveTargetById=932260;ARGS:/^(?:spoiler_text|poll\[options\]\[\]|description|display_name|note|fields_attributes\[\d+\]\[(?:name|value)\]|title|keyword|keywords_attributes\[\d*\]\[keyword\]|name|comment|text|private_comment|public_comment|json\.(?:spoiler_text|title|poll\.options\.\d+))$/" # A post's text, in status, form data from an app or JSON from the web app. # Each of these rules refused posting "Today I learned: `ls -la ~/.config` # lists hidden files, and `python3 -m http.server` serves a folder", so they # skip status: the four rules, 932125, 932230 and 932235. SecRule REQUEST_FILENAME "@rx ^/api/v1/statuses(?:/|$)" \ "id:900952,phase:1,pass,nolog,chain" SecRule &ARGS_GET:/^(?:json\.)?status$/ "@eq 0" \ "ctl:ruleRemoveTargetById=930120;ARGS:/^(?:json\.)?status$/,\ ctl:ruleRemoveTargetById=932120;ARGS:/^(?:json\.)?status$/,\ ctl:ruleRemoveTargetById=932125;ARGS:/^(?:json\.)?status$/,\ ctl:ruleRemoveTargetById=932230;ARGS:/^(?:json\.)?status$/,\ ctl:ruleRemoveTargetById=932235;ARGS:/^(?:json\.)?status$/,\ ctl:ruleRemoveTargetById=932250;ARGS:/^(?:json\.)?status$/,\ ctl:ruleRemoveTargetById=932260;ARGS:/^(?:json\.)?status$/" # Uploaded files' names skip 932180, which refused uploading # "Example .htaccess.png" as a server's own file, for a post or as a profile's # picture. Coraza keeps these names without the field each came in. Mastodon # refuses a file of a type it does not allow. SecRule REQUEST_FILENAME "@rx ^/api/v[12]/media$|^/api/v1/accounts/update_credentials$" \ "id:900953,phase:1,pass,nolog,\ ctl:ruleRemoveTargetById=932180;FILES" # The admin pages' searches, in the query: # username, display_name, email: /admin/accounts?username=python3 # by_domain: /admin/instances?by_domain=python3 # shortcode: /admin/custom_emojis?shortcode=python3 # name: /admin/tags?name=python3 SecRule REQUEST_FILENAME "@rx ^/admin/(?:accounts|instances|custom_emojis|tags)$" \ "id:900954,phase:1,pass,nolog,\ ctl:ruleRemoveTargetById=930120;ARGS:/^(?:username|display_name|email|by_domain|shortcode|name)$/,\ ctl:ruleRemoveTargetById=932120;ARGS:/^(?:username|display_name|email|by_domain|shortcode|name)$/,\ ctl:ruleRemoveTargetById=932250;ARGS:/^(?:username|display_name|email|by_domain|shortcode|name)$/,\ ctl:ruleRemoveTargetById=932260;ARGS:/^(?:username|display_name|email|by_domain|shortcode|name)$/" # The admin pages' free text, in bodies: # domain_block[private_comment], domain_block[public_comment]: blocking a # domain, "Spam about powershell and .htaccess" # ip_block[comment]: blocking an address # rule[text], rule[hint]: a server rule, "No posting of powershell malware" # announcement[text]: an announcement # form_admin_settings[site_title], [site_short_description], # [site_extended_description]: the server's name and descriptions, # "Python3 social" SecRule REQUEST_FILENAME "@rx ^/admin/(?:domain_blocks|ip_blocks|rules|announcements|settings)(?:/|$)" \ "id:900955,phase:1,pass,nolog,chain" SecRule &ARGS_GET:/^(?:domain_block\[(?:private|public)_comment\]|ip_block\[comment\]|rule\[(?:text|hint)\]|announcement\[text\]|form_admin_settings\[site_(?:title|short_description|extended_description)\])$/ "@eq 0" \ "ctl:ruleRemoveTargetById=930120;ARGS:/^(?:domain_block\[(?:private|public)_comment\]|ip_block\[comment\]|rule\[(?:text|hint)\]|announcement\[text\]|form_admin_settings\[site_(?:title|short_description|extended_description)\])$/,\ ctl:ruleRemoveTargetById=932120;ARGS:/^(?:domain_block\[(?:private|public)_comment\]|ip_block\[comment\]|rule\[(?:text|hint)\]|announcement\[text\]|form_admin_settings\[site_(?:title|short_description|extended_description)\])$/,\ ctl:ruleRemoveTargetById=932250;ARGS:/^(?:domain_block\[(?:private|public)_comment\]|ip_block\[comment\]|rule\[(?:text|hint)\]|announcement\[text\]|form_admin_settings\[site_(?:title|short_description|extended_description)\])$/,\ ctl:ruleRemoveTargetById=932260;ARGS:/^(?:domain_block\[(?:private|public)_comment\]|ip_block\[comment\]|rule\[(?:text|hint)\]|announcement\[text\]|form_admin_settings\[site_(?:title|short_description|extended_description)\])$/" # The settings pages' names, words and addresses, and passwords, in bodies: # custom_filter[title], custom_filter[keywords_attributes][0][keyword]: a # filter, "python3 spam" and "ls -la" # doorkeeper_application[name], doorkeeper_application[website]: an # application, "https://example.org/powershell" # account_alias[acct], account_migration[acct]: moving an account # user[password], user[password_confirmation], user[current_password]: # signing in, signing up and changing the password SecRule REQUEST_FILENAME "@rx ^/(?:filters|settings/(?:applications|aliases|migration)|auth)(?:/|$)" \ "id:900956,phase:1,pass,nolog,chain" SecRule &ARGS_GET:/^(?:custom_filter\[(?:title|keywords_attributes\]\[\d+\]\[keyword)\]|doorkeeper_application\[(?:name|website)\]|account_(?:alias|migration)\[acct\]|user\[(?:password|password_confirmation|current_password)\])$/ "@eq 0" \ "ctl:ruleRemoveTargetById=930120;ARGS:/^(?:custom_filter\[(?:title|keywords_attributes\]\[\d+\]\[keyword)\]|doorkeeper_application\[(?:name|website)\]|account_(?:alias|migration)\[acct\]|user\[(?:password|password_confirmation|current_password)\])$/,\ ctl:ruleRemoveTargetById=932120;ARGS:/^(?:custom_filter\[(?:title|keywords_attributes\]\[\d+\]\[keyword)\]|doorkeeper_application\[(?:name|website)\]|account_(?:alias|migration)\[acct\]|user\[(?:password|password_confirmation|current_password)\])$/,\ ctl:ruleRemoveTargetById=932250;ARGS:/^(?:custom_filter\[(?:title|keywords_attributes\]\[\d+\]\[keyword)\]|doorkeeper_application\[(?:name|website)\]|account_(?:alias|migration)\[acct\]|user\[(?:password|password_confirmation|current_password)\])$/,\ ctl:ruleRemoveTargetById=932260;ARGS:/^(?:custom_filter\[(?:title|keywords_attributes\]\[\d+\]\[keyword)\]|doorkeeper_application\[(?:name|website)\]|account_(?:alias|migration)\[acct\]|user\[(?:password|password_confirmation|current_password)\])$/" # The web app's search page: /search?q=python3. SecRule REQUEST_FILENAME "@streq /search" \ "id:900957,phase:1,pass,nolog,\ ctl:ruleRemoveTargetById=930120;ARGS:q,\ ctl:ruleRemoveTargetById=932120;ARGS:q,\ ctl:ruleRemoveTargetById=932250;ARGS:q,\ ctl:ruleRemoveTargetById=932260;ARGS:q" # Deliveries from other servers to an inbox, in JSON. The fields of the object # delivered skip the four rules: # content, contentMap: a post, "

notes on python3, powershell, ...

" # summary, summaryMap: a post's content warning, or a profile's text # name: a profile's name, "Alice powershell" # attachment: a picture's description, or a profile's fields # oneOf, anyOf: a poll's options, "python3" SecRule REQUEST_FILENAME "@rx ^/(?:inbox|users/[^/]+/inbox|ap/users/[0-9]+/inbox)$" \ "id:900958,phase:1,pass,nolog,chain" SecRule &ARGS_GET:/^json\.object\./ "@eq 0" \ "ctl:ruleRemoveTargetById=930120;ARGS:/^json\.object\.(?:content|contentmap\.[^.]+|summary|summarymap\.[^.]+|name|attachment\.\d+\.(?:name|value)|(?:oneof|anyof)\.\d+\.name)$/,\ ctl:ruleRemoveTargetById=932120;ARGS:/^json\.object\.(?:content|contentmap\.[^.]+|summary|summarymap\.[^.]+|name|attachment\.\d+\.(?:name|value)|(?:oneof|anyof)\.\d+\.name)$/,\ ctl:ruleRemoveTargetById=932250;ARGS:/^json\.object\.(?:content|contentmap\.[^.]+|summary|summarymap\.[^.]+|name|attachment\.\d+\.(?:name|value)|(?:oneof|anyof)\.\d+\.name)$/,\ ctl:ruleRemoveTargetById=932260;ARGS:/^json\.object\.(?:content|contentmap\.[^.]+|summary|summarymap\.[^.]+|name|attachment\.\d+\.(?:name|value)|(?:oneof|anyof)\.\d+\.name)$/" # Another server fetching an account or a post asks for ActivityPub's type with # its profile, which 920600 refused as a malformed Accept header: # Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams" SecRule REQUEST_FILENAME "@rx ^/(?:ap/)?users/|^/actor$" \ "id:900959,phase:1,pass,nolog,\ ctl:ruleRemoveTargetById=920600;REQUEST_HEADERS:Accept"