diff --git a/bin/browserid b/bin/browserid
index 253f0a481873bf842ed175261d5c710186b15681..dc6c99cadcae41015424d6b2c4ba3e43388091c6 100755
--- a/bin/browserid
+++ b/bin/browserid
@@ -91,6 +91,10 @@ app.use(express.logger({
   }
 }));
 
+// limit all content bodies to 10kb, at which point we'll forcefully
+// close down the connection.
+app.use(express.limit("10kb"));
+
 var statsd_config = config.get('statsd');
 if (statsd_config && statsd_config.enabled) {
   logger_statsd = require("connect-logger-statsd");
diff --git a/resources/static/pages/manage_account.js b/resources/static/pages/manage_account.js
index 0aa3a655f9ec8f5614dbf16a19b0d263cc30347d..896099c622d8dbe95e66712f6e64ad8089522125 100644
--- a/resources/static/pages/manage_account.js
+++ b/resources/static/pages/manage_account.js
@@ -239,6 +239,10 @@ BrowserID.manageAccount = (function() {
       tooltip.showTooltip("#tooltipNewRequired");
       complete(false);
     }
+    else if(newPassword.length < 8 || 80 < newPassword.length) {
+      tooltip.showTooltip("tooltipPasswordLength");
+      complete(false);
+    }
     else {
       user.changePassword(oldPassword, newPassword, function(status) {
         if(status) {
diff --git a/resources/static/shared/validation.js b/resources/static/shared/validation.js
index 515fba9f04fd396d71093af432289f8f113b72be..b31ba379580992b93a97e7a3ff98fb24e1c4be00 100644
--- a/resources/static/shared/validation.js
+++ b/resources/static/shared/validation.js
@@ -90,10 +90,10 @@ BrowserID.Validation = (function() {
   }
 
   function passwordLength(password) {
-    var valid = password && (password.length >= 8);
+    var valid = password && (password.length >= 8 && password.length <= 80);
 
     if(!valid) {
-      tooltip.showTooltip("#password_too_short");
+      tooltip.showTooltip("#password_length");
     }
 
     return valid;
diff --git a/resources/static/test/qunit/pages/manage_account_unit_test.js b/resources/static/test/qunit/pages/manage_account_unit_test.js
index b28d68a765841751dfd53b9b540b850ea54d7c00..50c679253ce5452f2a9778ea726c946c79f54f01 100644
--- a/resources/static/test/qunit/pages/manage_account_unit_test.js
+++ b/resources/static/test/qunit/pages/manage_account_unit_test.js
@@ -192,6 +192,37 @@
     });
   });
 
+  asyncTest("changePassword with too short of a password, expect tooltip", function() {
+    bid.manageAccount(mocks, function() {
+      $("#old_password").val("oldpassword");
+      $("#new_password").val("pass");
+
+      bid.manageAccount.changePassword(function(status) {
+        equal(status, false, "on too short of a password, status is false");
+        equal(tooltip.shown, true, "tooltip is visible");
+        start();
+      });
+    });
+  });
+
+  asyncTest("changePassword with too long of a password, expect tooltip", function() {
+    bid.manageAccount(mocks, function() {
+      $("#old_password").val("oldpassword");
+      var tooLong = "";
+      for(var i = 0; i < 81; i++) {
+        tooLong += (i % 10);
+      }
+      $("#new_password").val(tooLong);
+
+      bid.manageAccount.changePassword(function(status) {
+        equal(status, false, "on too short of a password, status is false");
+        equal(tooltip.shown, true, "tooltip is visible");
+        start();
+      });
+    });
+  });
+
+
   asyncTest("changePassword with incorrect old password, expect tooltip", function() {
     bid.manageAccount(mocks, function() {
       xhr.useResult("incorrectPassword");
diff --git a/resources/static/test/qunit/shared/validation_unit_test.js b/resources/static/test/qunit/shared/validation_unit_test.js
index ac2e4fe1fc95ccc7aeff9f8e01f615cefaef4f00..971473410b94e77bbea120dc8b996550d796afb7 100644
--- a/resources/static/test/qunit/shared/validation_unit_test.js
+++ b/resources/static/test/qunit/shared/validation_unit_test.js
@@ -242,6 +242,17 @@
     equal(tooltipShown, true, "too short password shows tooltip");
   });
 
+  test("passwordAndValidationPassword with too long password", function() {
+    var tooLong = "";
+    for(var i = 0; i < 81; i++) {
+      tooLong += (i % 10);
+    }
+    var valid = validation.passwordAndValidationPassword(tooLong, tooLong);
+
+    equal(valid, false, "too short password is invalid");
+    equal(tooltipShown, true, "too short password shows tooltip");
+  });
+
   test("passwordAndValidationPassword with empty validation password", function() {
     var valid = validation.passwordAndValidationPassword("password", "");
 
diff --git a/resources/views/index.ejs b/resources/views/index.ejs
index 9d9aea739112578bb45d68478ad9551920e336e3..3ff5034233c11fb15dc2be95087f24345a3f5349 100644
--- a/resources/views/index.ejs
+++ b/resources/views/index.ejs
@@ -32,13 +32,14 @@
             </div>
 
             <form id="edit_password_form" class="showedit">
-              <input type="password" id="old_password" name="old_password" placeholder="old password"/>
-              <input type="password" id="new_password" name="new_password" placeholder="new password"/>
+              <input type="password" id="old_password" name="old_password" placeholder="old password" maxlength="80"/>
+              <input type="password" id="new_password" name="new_password" placeholder="new password" maxlength="80"/>
               <button id="changePassword">done</button>
 
-              <div class="tooltip" for="old_password" id="tooltipOldRequired">Old password is required</div>
-              <div class="tooltip" for="old_password" id="tooltipInvalidPassword">Incorrect old password, password not updated</div>
-              <div class="tooltip" for="new_password" id="tooltipNewRequired">New password is required</div>
+              <div class="tooltip" for="old_password" id="tooltipOldRequired">Old password is required.</div>
+              <div class="tooltip" for="old_password" id="tooltipInvalidPassword">Incorrect old password, password not updated.</div>
+              <div class="tooltip" for="new_password" id="tooltipNewRequired">New password is required.</div>
+              <div class="tooltip" for="new_password" id="tooltipPasswordLength">Password must be between 8 and 80 characters long.</div>
             </form>
           </section>
 
diff --git a/resources/views/verify_email_address.ejs b/resources/views/verify_email_address.ejs
index 235e7873d27f84a8b40f5f974fa47c4c6a796460..181c6a4f02993ff4d4a38904a916cf49ce5a5922 100644
--- a/resources/views/verify_email_address.ejs
+++ b/resources/views/verify_email_address.ejs
@@ -23,8 +23,8 @@
                       Password is required.
                     </div>
 
-                    <div class="tooltip" id="password_too_short" for="password">
-                      Password must be at least 8 characters long.
+                    <div class="tooltip" id="password_length" for="password">
+                      Password must be between 8 and 80 characters long.
                     </div>
                 </li>
                 <li>
diff --git a/tests/post-limiting-test.js b/tests/post-limiting-test.js
new file mode 100755
index 0000000000000000000000000000000000000000..70b86b71ca4dd34be3ff3e9bdb30e4554f016180
--- /dev/null
+++ b/tests/post-limiting-test.js
@@ -0,0 +1,116 @@
+#!/usr/bin/env node
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla BrowserID.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+require('./lib/test_env.js');
+
+const assert =
+require('assert'),
+vows = require('vows'),
+start_stop = require('./lib/start-stop.js'),
+wsapi = require('./lib/wsapi.js'),
+config = require('../lib/configuration.js'),
+http = require('http');
+secrets = require('../lib/secrets.js');
+
+var suite = vows.describe('post-limiting');
+
+// disable vows (often flakey?) async error behavior
+suite.options.error = false;
+
+start_stop.addStartupBatches(suite);
+
+// test posting more than 10kb
+suite.addBatch({
+  "posting more than 10kb": {
+    topic: function(assertion)  {
+      var cb = this.callback;
+      var req = http.request({
+        host: '127.0.0.1',
+        port: 10002,
+        path: '/wsapi/authenticate_user',
+        headers: {
+          'Content-Type': 'application/x-www-form-urlencoded'
+        },
+        method: "POST"
+      }, function (res) {
+        cb(res);
+      }).on('error', function (e) {
+        cb(undefined, e);
+      });
+      req.write(secrets.weakGenerate(1024 * 10 + 1));
+      req.end();
+    },
+    "fails": function (r, err) {
+      assert.ok(/socket hang up/.test(err.toString()));
+    }
+  }
+});
+
+// test posting more than 10kb with content-length header
+suite.addBatch({
+  "posting more than 10kb with content-length": {
+    topic: function(assertion)  {
+      var cb = this.callback;
+      var req = http.request({
+        host: '127.0.0.1',
+        port: 10002,
+        path: '/wsapi/authenticate_user',
+        headers: {
+          'Content-Type': 'application/x-www-form-urlencoded',
+          'Content-Length': 1024 * 10 + 1
+        },
+        method: "POST"
+      }, function (res) {
+        cb(res);
+      }).on('error', function (e) {
+        cb(undefined, e);
+      });
+      req.write(secrets.weakGenerate(1024 * 10 + 1));
+      req.end();
+    },
+    "fails": function (r, err) {
+      assert.strictEqual(413, r.statusCode);
+    }
+  }
+});
+
+
+start_stop.addShutdownBatches(suite);
+
+// run or export the suite.
+if (process.argv[1] === __filename) suite.run();
+else suite.export(module);