# The thirteenth change: on Vaultwarden's paths, some fields skip the rules that # refused ordinary Vaultwarden requests there. They are the fields where # Vaultwarden receives a name, a password hint or an email address in plain # text, and the names of uploaded files. 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. # # The apps encrypt the names, notes, addresses and file names of vault items, # folders, collections and sends before they send them. These values pass # without exclusions. # # Four rules read a name or a hint as a command or a system file: # 930120: .htaccess # 932120: powershell # 932250: ls -la # 932260: python3 # Names and password hints, in JSON bodies, skip the four rules: # name: signing up, editing the account's profile, and creating or renaming # an organization or a group, "python3 .htaccess team" # name: naming a security key at /api/two-factor/webauthn, "python3 key" # masterPasswordHint: signing up or changing the master password, # "the .htaccess one, not powershell" # invitation_org_name, smtp_from_name: saving the admin page's settings, # "ls -la and .htaccess vault" # Drupal serves /admin/config too, but sends no JSON there. SecRule REQUEST_FILENAME "@rx ^/identity/accounts/|^/api/(?:accounts|emergency-access|organizations)(?:/|$)|^/api/two-factor/webauthn$|^/admin/config$" \ "id:900150,phase:1,pass,nolog,chain" SecRule &ARGS_GET:/^json\.(?:name|masterpasswordhint|invitation_org_name|smtp_from_name)$/ "@eq 0" \ "ctl:ruleRemoveTargetById=930120;ARGS:/^json\.(?:name|masterpasswordhint|invitation_org_name|smtp_from_name)$/,\ ctl:ruleRemoveTargetById=932120;ARGS:/^json\.(?:name|masterpasswordhint|invitation_org_name|smtp_from_name)$/,\ ctl:ruleRemoveTargetById=932250;ARGS:/^json\.(?:name|masterpasswordhint|invitation_org_name|smtp_from_name)$/,\ ctl:ruleRemoveTargetById=932260;ARGS:/^json\.(?:name|masterpasswordhint|invitation_org_name|smtp_from_name)$/" # Email addresses, in bodies, skip 930120, 932120 and 932260, which refused # these addresses: # 930120: jane.profile@example.com # 932120: powershell@example.com # 932260: python3.dev@example.com # These fields hold an address: # username: signing in at /identity/connect/token, in form data # email: signing up, asking for the password hint, inviting an emergency # contact, and inviting a user from the admin page # email: setting up sign-in codes by email, and asking for one when signing # in, under /api/two-factor/ # email: signing in with another device, at /api/auth-requests # email: sending the admin page's test email, at /admin/test/smtp # salt fields, such as masterPasswordUnlock.salt: signing up and changing # the master password, which send the address as the salt # accountUnlockData.masterPasswordUnlockData.email: rotating the account's # encryption key # newEmail: changing the account's address # billingEmail: creating or editing an organization # emails: inviting members to an organization # smtp_from, smtp_username, org_creation_users: saving the admin page's # settings # An address holds no spaces, so it keeps 932250, which needs ls -la. SecRule REQUEST_FILENAME "@rx ^/identity/(?:connect/token$|accounts/)|^/api/(?:accounts|emergency-access|organizations|auth-requests)(?:/|$)|^/api/two-factor/|^/admin/(?:config|invite|test/smtp)$" \ "id:900151,phase:1,pass,nolog,chain" SecRule &ARGS_GET:/^(?:username|json\.(?:email|newemail|billingemail|emails\.\d+|smtp_from|smtp_username|org_creation_users|(?:[a-z]+\.)+salt|accountunlockdata\.masterpasswordunlockdata\.email))$/ "@eq 0" \ "ctl:ruleRemoveTargetById=930120;ARGS:/^(?:username|json\.(?:email|newemail|billingemail|emails\.\d+|smtp_from|smtp_username|org_creation_users|(?:[a-z]+\.)+salt|accountunlockdata\.masterpasswordunlockdata\.email))$/,\ ctl:ruleRemoveTargetById=932120;ARGS:/^(?:username|json\.(?:email|newemail|billingemail|emails\.\d+|smtp_from|smtp_username|org_creation_users|(?:[a-z]+\.)+salt|accountunlockdata\.masterpasswordunlockdata\.email))$/,\ ctl:ruleRemoveTargetById=932260;ARGS:/^(?:username|json\.(?:email|newemail|billingemail|emails\.\d+|smtp_from|smtp_username|org_creation_users|(?:[a-z]+\.)+salt|accountunlockdata\.masterpasswordunlockdata\.email))$/" # The data breach report sends an address in the query, which skips the same # three rules: /api/hibp/breach?username=jane.profile%40example.com. SecRule REQUEST_FILENAME "@rx ^/api/hibp/breach$" \ "id:900152,phase:1,pass,nolog,\ ctl:ruleRemoveTargetById=930120;ARGS:username,\ ctl:ruleRemoveTargetById=932120;ARGS:username,\ ctl:ruleRemoveTargetById=932260;ARGS:username" # An uploaded attachment or file send is named by its encrypted name, such as # "2.4Hw+ulOz7BLrP+NSaLKhGw==|9nlpuuYHog6rpJrR...". 920120 refused the "=" in # it, so the names of uploaded files skip 920120 on these paths: # /api/ciphers//attachment/, and the older uploads to # /api/ciphers//attachment, /api/ciphers//attachment-admin and # /api/ciphers//attachment//share # /api/sends//file/ SecRule REQUEST_FILENAME "@rx ^/api/ciphers/[0-9a-f-]{36}/attachment(?:-admin|/[0-9a-f]+(?:/share)?)?$|^/api/sends/[0-9a-f-]{36}/file/[0-9a-f]+$" \ "id:900153,phase:1,pass,nolog,\ ctl:ruleRemoveTargetById=920120;FILES"