Answers.Body: <p>Not sure I have the full picture yet, but as per the comments, the problem appears to be clear:</p>
  <blockquote>
  <p>I think I found the issue. Before, I was disabling the form first and then submitting it. That was working well, but not anymore. However, if I change the order in the JS execution, submitting first, and then disabling, things work as they used to.</p>
  </blockquote>
  <p>If you're disabling the form's input elements using the <code>disabled</code> attribute before sending it, an empty post body is expected. Disabled input elements aren't included in the submitted form, this is <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/disabled" rel="nofollow noreferrer">by design</a>. Not sure why it ever worked before, but in this case, submitting the form first and then disabling the inputs will solve the issue. Or just disable the submit button to prevent duplicate submissions and leave the rest of the inputs alone.</p>
  <p>Another possibility would be to submit the <code>FormData</code> object with a <code>fetch()</code> call – of course, this is only practical if you want to handle the response in JavaScript.</p>
  <hr />
  <p>For future readers:</p>
  <blockquote>
  <p>I don't remember seeing the long string of characters in the redirect
  input's value. Instead I thought it would be something like this
  <code>thank-you?from{fromName}</code> only.</p>
  </blockquote>
  <p>This is working as intended, the long string of characters is a hashed value. Craft <a href="https://github.com/craftcms/cms/blob/develop/src/helpers/Html.php#L88-L104" rel="nofollow noreferrer">hashes the redirect URL</a> to prevent tampering. See <a href="https://www.yiiframework.com/doc/api/2.0/yii-base-security#hashData()-detail" rel="nofollow noreferrer">Security::hashData</a> for details.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-11-05T22:08:58.873Z
Answers.Text: thank you for the clarifications. The problem was indeed the attempt to submit the form after disabling the fields. Strange that Firefox was letting that pass through. Really, really appreciate the help. Wish I could change the title of this post.
Answers.UserDisplayName: mauricio
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-11-08T10:17:25.370Z
Answers.Text: @mauricio Glad I could help! You can change the title of the question, there should be a small `Edit` link at the bottom of your question. Not sure if that requires a particular privilege though, as far as I know it shouldn't for your own question.
Answers.UserDisplayName: MoritzLost
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-11-09T14:31:59.883Z
Answers.Text: awesome, this was a lack of attention! I didn't realize that one can also edit the question title. Thank you so much!
Answers.UserDisplayName: mauricio
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-11-05T15:08:18.373Z
Answers.LastActivityDate: 2021-11-05T15:08:18.373Z
Answers.UserDisplayName: MoritzLost
Body: <p>I have a site with Pixel &amp; Tonic's contact form. This site is built using Nitro. The contact form has a 'post' submit, and a page redirect to a thank you page if the form is sent properly. There's not Ajax involved.</p>
  <p>The form was working well. I'm not sure if this is just a mere coincidence, but I upgraded today to the latest CraftCMS version (3.17.19) and, my default browser, Firefox, was updated too. Afterwards I noticed the problem. The form's version is 2.2.7.</p>
  <p>I have inline JS validation before sending. This part is working. And when the inputs are valid, there's an attempt to submit the form.</p>
  <p>Examining the network traffic, I see that the Request parameters in the post call, are empty (Firefox reports it as <code>No payload for this request</code>). I was expecting to see the submitted data.</p>
  <p>Also I noticed something a bit puzzling. The form has this code:</p>
  <pre class="lang-PHP prettyprint-override"><code>{{ csrfInput() }}
  {{ redirectInput('thank-you?from={fromName}') }}
  </code></pre>
  <p>Which in the frontend, are rendered like this:</p>
  <pre class="lang-HTML prettyprint-override"><code>&lt;input type=&quot;hidden&quot; name=&quot;CRAFT_CSRF_TOKEN&quot; value=&quot;UWOm80Y6Hu-ADjHBk2qH8Ds8C3MHSxut0scjX4O6skpfvZkNDtu7ySpoebWma8RJF5JLXUlCotOkyETtdhWK1BAGGjth2yploNIRzC-paXQyZslvGa5l65dG8dcBv_MNb_uBvUvwe2LzzdZHvnEtwZnHujgJHdkJ2uBEC8fX4JMWpgGYfBzsFnjoNZ4aFddqnz4i2SNtA2-A2ErBfvV-RjZTQx4YjYFZxsgKZDupMACKXTvnjCWXMRirSegj7lOXjqCT-aQYli9tB7tk9iIfBQhQ98QEYDOH9Fh7kN4kxL9Ua1MYbiVD9L6SWzjtjdACDdP9YX6O7J1WWxqHk138eSOlfW4tcMO1kP8l3UItueN1YCMMUelPUZCwJPlKkV4XBlL9VimZVt-gJ5S2Nd7FO1zN4tgokh5bkpTlFokzd-zxs-xyWFCXSpWPE1Osvo7LT8pU4Bty23Qwulv6dmWCPctCE6UHX3pLsetumVCiGzZZAgdrVtvGMoj4QSVimkF5pDRIlrln-HxL2SCgYKVl_faV9a6dIeIeGTbTF7d7Uko=&quot;&gt;
  &lt;input type=&quot;hidden&quot; name=&quot;redirect&quot; value=&quot;86f9c378e703b2be657e4a742b9ff62ab3909e6c2ebb2cc64ad7a6ed7495dfc3thank-you?from={fromName}&quot;&gt;
  </code></pre>
  <p>I don't remember seeing the long string of characters in the redirect input's value. Instead, I thought it would be something like this <code>thank-you?from{fromName}</code> only.</p>
  <p>I wonder if the update is the reason behind this problem. Thanks so much for your help.</p>
  <p><strong>EDIT</strong>
  When I disable the JS validation, the contact form works well. However, when it is enabled, the sent post request is empty. I'm pasting below the validation script. What I find strange is that right before doing a <code>form.submit()</code>, I'm logging the FormData parameters, and all the entered information is logged(!).</p>
  <pre class="lang-js prettyprint-override"><code>&lt;script&gt;
      (function() {
          // form elements
          const form = document.querySelector(&quot;.contactForm&quot;);
          const form_button = form.querySelector(&quot;.outsetSend&quot;);
          const fieldset = form.querySelector('fieldset');
          
          // Adds listener to the form
          formListener = ()=&gt;{
              form.addEventListener(&quot;submit&quot;, e =&gt; {
                  e.preventDefault();
                  let formData = new FormData(form);
                  // Validates form, returns false when there's no errors
                  if ( !formErrors(formData) ) {
                      // logs the data the form validated 
                      for(var pair of formData.entries()) {
                         console.log(pair[0]+ ': '+ pair[1]);
                      }
                      // shows spinner and disables fields and buttons
                      hyper.formSending();
                      // sends form 
                      form.submit();
                  }
                  return false;
              });
          };
          
          // adds listener to required fields so that error messages hide when field is on focus
          requiredFieldsListener = ()=&gt;{
              // figures which fields are required
              let required = form.querySelectorAll(&quot;[required]&quot;);
              // Adds listener to each entry
              for (let i = 0; i &lt; required.length; ++i) {
                 required[i].addEventListener('focus', e =&gt;{
                     let parent = e.target.closest(&quot;.outsetField&quot;);
                     parent.classList.remove('validationError');
                     // removes text content
                     let errorArea = parent.querySelector('.outsetField-error');
                     errorArea.textContent = '';
                 } );
              }
          };
  
          // Validates form
          // Checks for errors in the contact form submission
          // returns false when there's no errors
          formErrors = (formData)=&gt;{
              let error = false;
              let errorArray = new Array();
              let toValidate = new Array();
  
              // checks if there's a honeypot field AND if it is filled
              if (formData.get('myInterest') !== null &amp;&amp; formData.get('myInterest')  != ''){
                  // honeyF violation, we should abort here
                  // console.log ('HoneyPot Error')
                  finalMessage();
                  return true;
              }
              
              // figures which fields are required
              let required = form.querySelectorAll(&quot;[required]&quot;);
              // creates an array with required fields, Each entry is an object
              for (let i = 0; i &lt; required.length; ++i) {
                  toValidate.push({
                      id: required[i].getAttribute(&quot;id&quot;),
                      type: required[i].getAttribute(&quot;type&quot;),
                      value: required[i].value,
                      placeholder: required[i].getAttribute(&quot;placeholder&quot;),
                      name: required[i].name,
                  });
              }
  
              // Figures which required fields are invalid
              for (const element of toValidate) {
                  if (element.type == &quot;text&quot; &amp;&amp; element.value.length == 0) {
                      // Checks none of the text fields, including email, is empty
                      error = true;
                      // adds new error message to object 
                      element.errorMessage = &quot;Please enter &quot; + element.placeholder;
                      errorArray.push(element);
                  }  else if (element.type == &quot;text&quot; &amp;&amp; element.name == 'fromEmail' &amp;&amp; element.value.length &gt; 0) {
                      // specific to the email field validation
                      const re =
                      /^(([^&lt;&gt;()[\]\\.,;:\s@\&quot;]+(\.[^&lt;&gt;()[\]\\.,;:\s@\&quot;]+)*)|(\&quot;.+\&quot;))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
                      let emailValid = re.test(element.value);
                      if (!emailValid) {
                          error = true;
                          element.errorMessage = &quot;Please review &quot; + element.placeholder;
                          errorArray.push(element);
                      }
                  }
              }
              if (error == true) {
                  // displays errors
                  insertErrors(errorArray);
              }
              console.log('VALIDATION FAILED?=',error);
              return error;
          };
  
          // Receives error array and displays error messages associated with validation of input
          insertErrors = (errorArray) =&gt; {
              for (const element of errorArray) {
                  const el = document.querySelector(&quot;#&quot; + element.id);
                  const parentEl = el.parentElement;
                  const errorEl = parentEl.querySelector(&quot;.outsetField-error&quot;);
                  parentEl.classList.add(&quot;validationError&quot;);
                  errorEl.innerHTML = element.errorMessage;
              }
          };        
  
          /* {# Shows failure message when the error is not due to direct user input #}
           {# for instance, the hidden honeypot field has been filled. Or there's missing key inputs #} */
          finalMessage = () =&gt; {
              hyper.failureMessage();
          };
  
          // Initiates the form and listeners for the required fields
          formListener();
          requiredFieldsListener();
          
    })();  
  &lt;/script&gt;
  </code></pre>
  
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-11-05T09:00:18.203Z
Comments.Text: The long string of characters is normal, Craft [hashes the redirect URL](https://github.com/craftcms/cms/blob/develop/src/helpers/Html.php#L88-L104) to prevent tampering. Since Firefox shows an empty request body, it's likely an error with either the form HTML or the JS validation, can you post the full code for those?
Comments.UserDisplayName: MoritzLost
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-11-05T12:36:19.040Z
Comments.Text: Thank you so much for your answer. I spent many hours yesterday trying to figure out what was wrong with the form. It's nice to hear that the long strings are expected.
  When you asked to see the JS validation, i decided to turn it off and test submitting the form without it. To my surprise it worked! So I'm not sure how, and when, the validation, that was working starting acting out. Before posting more I'm going to review it and try to figure it out what is going on. The validation code is quite long. If I get stuck I'll be posting it here. Thank you so much.
Comments.UserDisplayName: mauricio
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-11-05T13:36:05.247Z
Comments.Text: You're welcome! If you post the validation code I'll see if I spot any errors, sometimes it's easier with a fresh pair of eyes :)
Comments.UserDisplayName: MoritzLost
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-11-05T14:16:51.263Z
Comments.Text: @MoritzLost Thanks so much for taking the time to look at this. I have reviewed the JS routine several times and cannot find what's going on. So I pasted the script in the original post above. Thank you so much for looking at it.
Comments.UserDisplayName: mauricio
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-11-05T14:27:18.343Z
Comments.Text: @MoritzLost I think I found the issue. Before, I was disabling the form first and then submitting it. That was working well, but not anymore. However, if I change the order in the JS execution, submitting first, and then disabling, things work as they used to. Besides updating CraftCMS, the other only change in my setup was an update to Firefox Developer Edition. Perhaps this latest Firefox version handles things differently when a form is disabled?
Comments.UserDisplayName: mauricio
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-11-05T14:55:22.823Z
Comments.Text: Just looking through it … what's the `hyper` variable? Some external library? What does `hyper.formSending();` do?
Comments.UserDisplayName: MoritzLost
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2021-11-05T22:07:31.410Z
Comments.Text: @MoritzLost, thank you so much for taking the time to look through things. I've learned quite a bit. Not sure why Firefox was letting me send the form after the fields had been disabled. But thank you for clarifying. And also thank you for the explanation on the hashing.
  Regarding the hyper variable, I'm using hyperscript (https://github.com/hyperhype/hyperscript) for the UX interactions. I'm liking it quite a bit, but it takes a little bit getting used to the syntax.
Comments.UserDisplayName: mauricio
Tags: <plugin-contactform>
Title: Contact form not working since Firefox version update
ThreadText: # Contact form not working since Firefox version update
  
  (Asked by: username_0 on 2021-11-05)
  
  I have a site with Pixel & Tonic's contact form. This site is built using Nitro. The contact form has a 'post' submit, and a page redirect to a thank you page if the form is sent properly. There's not Ajax involved.
  
  The form was working well. I'm not sure if this is just a mere coincidence, but I upgraded today to the latest CraftCMS version (3.17.19) and, my default browser, Firefox, was updated too. Afterwards I noticed the problem. The form's version is 2.2.7.
  
  I have inline JS validation before sending. This part is working. And when the inputs are valid, there's an attempt to submit the form.
  
  Examining the network traffic, I see that the Request parameters in the post call, are empty (Firefox reports it as `No payload for this request`). I was expecting to see the submitted data.
  
  Also I noticed something a bit puzzling. The form has this code:
  
  ```PHP
  {{ csrfInput() }}
  {{ redirectInput('thank-you?from={fromName}') }}
  
  ```
  
  Which in the frontend, are rendered like this:
  
  ```HTML
  <input type="hidden" name="CRAFT_CSRF_TOKEN" value="UWOm80Y6Hu-ADjHBk2qH8Ds8C3MHSxut0scjX4O6skpfvZkNDtu7ySpoebWma8RJF5JLXUlCotOkyETtdhWK1BAGGjth2yploNIRzC-paXQyZslvGa5l65dG8dcBv_MNb_uBvUvwe2LzzdZHvnEtwZnHujgJHdkJ2uBEC8fX4JMWpgGYfBzsFnjoNZ4aFddqnz4i2SNtA2-A2ErBfvV-RjZTQx4YjYFZxsgKZDupMACKXTvnjCWXMRirSegj7lOXjqCT-aQYli9tB7tk9iIfBQhQ98QEYDOH9Fh7kN4kxL9Ua1MYbiVD9L6SWzjtjdACDdP9YX6O7J1WWxqHk138eSOlfW4tcMO1kP8l3UItueN1YCMMUelPUZCwJPlKkV4XBlL9VimZVt-gJ5S2Nd7FO1zN4tgokh5bkpTlFokzd-zxs-xyWFCXSpWPE1Osvo7LT8pU4Bty23Qwulv6dmWCPctCE6UHX3pLsetumVCiGzZZAgdrVtvGMoj4QSVimkF5pDRIlrln-HxL2SCgYKVl_faV9a6dIeIeGTbTF7d7Uko=">
  <input type="hidden" name="redirect" value="86f9c378e703b2be657e4a742b9ff62ab3909e6c2ebb2cc64ad7a6ed7495dfc3thank-you?from={fromName}">
  
  ```
  
  I don't remember seeing the long string of characters in the redirect input's value. Instead, I thought it would be something like this `thank-you?from{fromName}` only.
  
  I wonder if the update is the reason behind this problem. Thanks so much for your help.
  
  **EDIT**
  When I disable the JS validation, the contact form works well. However, when it is enabled, the sent post request is empty. I'm pasting below the validation script. What I find strange is that right before doing a `form.submit()`, I'm logging the FormData parameters, and all the entered information is logged(!).
  
  ```js
  <script>
      (function() {
          // form elements
          const form = document.querySelector(".contactForm");
          const form_button = form.querySelector(".outsetSend");
          const fieldset = form.querySelector('fieldset');
          
          // Adds listener to the form
          formListener = ()=>{
              form.addEventListener("submit", e => {
                  e.preventDefault();
                  let formData = new FormData(form);
                  // Validates form, returns false when there's no errors
                  if ( !formErrors(formData) ) {
                      // logs the data the form validated 
                      for(var pair of formData.entries()) {
                         console.log(pair[0]+ ': '+ pair[1]);
                      }
                      // shows spinner and disables fields and buttons
                      hyper.formSending();
                      // sends form 
                      form.submit();
                  }
                  return false;
              });
          };
          
          // adds listener to required fields so that error messages hide when field is on focus
          requiredFieldsListener = ()=>{
              // figures which fields are required
              let required = form.querySelectorAll("[required]");
              // Adds listener to each entry
              for (let i = 0; i < required.length; ++i) {
                 required[i].addEventListener('focus', e =>{
                     let parent = e.target.closest(".outsetField");
                     parent.classList.remove('validationError');
                     // removes text content
                     let errorArea = parent.querySelector('.outsetField-error');
                     errorArea.textContent = '';
                 } );
              }
          };
  
          // Validates form
          // Checks for errors in the contact form submission
          // returns false when there's no errors
          formErrors = (formData)=>{
              let error = false;
              let errorArray = new Array();
              let toValidate = new Array();
  
              // checks if there's a honeypot field AND if it is filled
              if (formData.get('myInterest') !== null && formData.get('myInterest')  != ''){
                  // honeyF violation, we should abort here
                  // console.log ('HoneyPot Error')
                  finalMessage();
                  return true;
              }
              
              // figures which fields are required
              let required = form.querySelectorAll("[required]");
              // creates an array with required fields, Each entry is an object
              for (let i = 0; i < required.length; ++i) {
                  toValidate.push({
                      id: required[i].getAttribute("id"),
                      type: required[i].getAttribute("type"),
                      value: required[i].value,
                      placeholder: required[i].getAttribute("placeholder"),
                      name: required[i].name,
                  });
              }
  
              // Figures which required fields are invalid
              for (const element of toValidate) {
                  if (element.type == "text" && element.value.length == 0) {
                      // Checks none of the text fields, including email, is empty
                      error = true;
                      // adds new error message to object 
                      element.errorMessage = "Please enter " + element.placeholder;
                      errorArray.push(element);
                  }  else if (element.type == "text" && element.name == 'fromEmail' && element.value.length > 0) {
                      // specific to the email field validation
                      const re =
                      /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
                      let emailValid = re.test(element.value);
                      if (!emailValid) {
                          error = true;
                          element.errorMessage = "Please review " + element.placeholder;
                          errorArray.push(element);
                      }
                  }
              }
              if (error == true) {
                  // displays errors
                  insertErrors(errorArray);
              }
              console.log('VALIDATION FAILED?=',error);
              return error;
          };
  
          // Receives error array and displays error messages associated with validation of input
          insertErrors = (errorArray) => {
              for (const element of errorArray) {
                  const el = document.querySelector("#" + element.id);
                  const parentEl = el.parentElement;
                  const errorEl = parentEl.querySelector(".outsetField-error");
                  parentEl.classList.add("validationError");
                  errorEl.innerHTML = element.errorMessage;
              }
          };        
  
          /* {# Shows failure message when the error is not due to direct user input #}
           {# for instance, the hidden honeypot field has been filled. Or there's missing key inputs #} */
          finalMessage = () => {
              hyper.failureMessage();
          };
  
          // Initiates the form and listeners for the required fields
          formListener();
          requiredFieldsListener();
          
    })();  
  </script>
  
  ```
  
  **Tags:** plugin-contactform
  
  > **Comments:**
  > **username_1**: The long string of characters is normal, Craft [hashes the redirect URL](https://github.com/craftcms/cms/blob/develop/src/helpers/Html.php#L88-L104) to prevent tampering. Since Firefox shows an empty request body, it's likely an error with either the form HTML or the JS validation, can you post the full code for those?  
  > **username_0**: Thank you so much for your answer. I spent many hours yesterday trying to figure out what was wrong with the form. It's nice to hear that the long strings are expected. When you asked to see the JS validation, i decided to turn it off and test submitting the form without it. To my surprise it worked! So I'm not sure how, and when, the validation, that was working starting acting out. Before posting more I'm going to review it and try to figure it out what is going on. The validation code is quite long. If I get stuck I'll be posting it here. Thank you so much.  
  > **username_1**: You're welcome! If you post the validation code I'll see if I spot any errors, sometimes it's easier with a fresh pair of eyes :)  
  > **username_0**: @username_1 Thanks so much for taking the time to look at this. I have reviewed the JS routine several times and cannot find what's going on. So I pasted the script in the original post above. Thank you so much for looking at it.  
  > **username_0**: @username_1 I think I found the issue. Before, I was disabling the form first and then submitting it. That was working well, but not anymore. However, if I change the order in the JS execution, submitting first, and then disabling, things work as they used to. Besides updating CraftCMS, the other only change in my setup was an update to Firefox Developer Edition. Perhaps this latest Firefox version handles things differently when a form is disabled?  
  > **username_1**: Just looking through it … what's the `hyper` variable? Some external library? What does `hyper.formSending();` do?  
  > **username_0**: @username_1, thank you so much for taking the time to look through things. I've learned quite a bit. Not sure why Firefox was letting me send the form after the fields had been disabled. But thank you for clarifying. And also thank you for the explanation on the hashing. Regarding the hyper variable, I'm using hyperscript (https://github.com/hyperhype/hyperscript) for the UX interactions. I'm liking it quite a bit, but it takes a little bit getting used to the syntax.  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2021-11-05. Score: 2 | Accepted answer
  
  Not sure I have the full picture yet, but as per the comments, the problem appears to be clear:
  
  > I think I found the issue. Before, I was disabling the form first and then submitting it. That was working well, but not anymore. However, if I change the order in the JS execution, submitting first, and then disabling, things work as they used to.
  
  If you're disabling the form's input elements using the `disabled` attribute before sending it, an empty post body is expected. Disabled input elements aren't included in the submitted form, this is [by design](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/disabled). Not sure why it ever worked before, but in this case, submitting the form first and then disabling the inputs will solve the issue. Or just disable the submit button to prevent duplicate submissions and leave the rest of the inputs alone.
  
  Another possibility would be to submit the `FormData` object with a `fetch()` call – of course, this is only practical if you want to handle the response in JavaScript.
  
  ---
  
  For future readers:
  
  > I don't remember seeing the long string of characters in the redirect
  > input's value. Instead I thought it would be something like this
  > `thank-you?from{fromName}` only.
  
  This is working as intended, the long string of characters is a hashed value. Craft [hashes the redirect URL](https://github.com/craftcms/cms/blob/develop/src/helpers/Html.php#L88-L104) to prevent tampering. See [Security::hashData](https://www.yiiframework.com/doc/api/2.0/yii-base-security#hashData()-detail) for details.
  
  > **Comments:**
  > **username_0**: thank you for the clarifications. The problem was indeed the attempt to submit the form after disabling the fields. Strange that Firefox was letting that pass through. Really, really appreciate the help. Wish I could change the title of this post.  
  > **username_1**: @username_0 Glad I could help! You can change the title of the question, there should be a small `Edit` link at the bottom of your question. Not sure if that requires a particular privilege though, as far as I know it shouldn't for your own question.  
  > **username_0**: awesome, this was a lack of attention! I didn't realize that one can also edit the question title. Thank you so much!  
  
  ---
  
  