diff --git a/lib/codemirror.js b/lib/codemirror.js
index 1a70cd68deb23ddc7e50772618edb6a87e289a24..911d0aa21c1fb4b3e750935fe440834be19d44b9 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -2225,6 +2225,11 @@
     // will be the case when there is a lot of text in the textarea,
     // in which case reading its value would be expensive.
     if (!cm.state.focused || hasSelection(input) || isReadOnly(cm) || cm.options.disableInput) return false;
+    // See paste handler for more on the fakedLastChar kludge
+    if (cm.state.pasteIncoming && cm.state.fakedLastChar) {
+      input.value = input.value.substring(0, input.value.length - 1);
+      cm.state.fakedLastChar = false;
+    }
     var text = input.value;
     // If nothing changed, bail.
     if (text == prevInput && !cm.somethingSelected()) return false;
@@ -2424,6 +2429,16 @@
       fastPoll(cm);
     });
     on(d.input, "paste", function() {
+      // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206
+      // Add a char to the end of textarea before paste occur so that
+      // selection doesn't span to the end of textarea.
+      if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleDown < 200)) {
+        var start = d.input.selectionStart, end = d.input.selectionEnd;
+        d.input.value += "$";
+        d.input.selectionStart = start;
+        d.input.selectionEnd = end;
+        cm.state.fakedLastChar = true;
+      }
       cm.state.pasteIncoming = true;
       fastPoll(cm);
     });