diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,14 @@
+# ChangeLog for yesod-core
+
+## 1.6.7
+
+* If no matches are found, `selectRep` chooses first representation regardless
+    of the presence or absence of a `Content-Type` header in the request
+    [#1540](https://github.com/yesodweb/yesod/pull/1540)
+* Sets the `X-XSS-Protection` header to `1; mode=block` [#1550](https://github.com/yesodweb/yesod/pull/1550)
+* Add `PrimMonad` instances for `HandlerFor` and `WidgetFor` [from
+  StackOverflow](https://stackoverflow.com/q/52692508/369198)
+
 ## 1.6.6
 
 * `defaultErrorHandler` handles text/plain requests [#1522](https://github.com/yesodweb/yesod/pull/1520)
diff --git a/Yesod/Core/Class/Yesod.hs b/Yesod/Core/Class/Yesod.hs
--- a/Yesod/Core/Class/Yesod.hs
+++ b/Yesod/Core/Class/Yesod.hs
@@ -337,12 +337,14 @@
 defaultShouldLogIO _ level = return $ level >= LevelInfo
 
 -- | Default implementation of 'yesodMiddleware'. Adds the response header
--- \"Vary: Accept, Accept-Language\" and performs authorization checks.
+-- \"Vary: Accept, Accept-Language\", \"X-XSS-Protection: 1; mode=block\", and
+-- performs authorization checks.
 --
 -- Since 1.2.0
 defaultYesodMiddleware :: Yesod site => HandlerFor site res -> HandlerFor site res
 defaultYesodMiddleware handler = do
     addHeader "Vary" "Accept, Accept-Language"
+    addHeader "X-XSS-Protection" "1; mode=block"
     authorizationCheck
     handler
 
diff --git a/Yesod/Core/Handler.hs b/Yesod/Core/Handler.hs
--- a/Yesod/Core/Handler.hs
+++ b/Yesod/Core/Handler.hs
@@ -1289,15 +1289,9 @@
         [] ->
             case reps of
                 [] -> sendResponseStatus H.status500 ("No reps provided to selectRep" :: Text)
-                rep:_ ->
-                  if null cts
-                    then returnRep rep
-                    else sendResponseStatus H.status406 explainUnaccepted
+                rep:_ -> returnRep rep
         rep:_ -> returnRep rep
   where
-    explainUnaccepted :: Text
-    explainUnaccepted = "no match found for accept header"
-
     returnRep (ProvidedRep ct mcontent) = fmap (TypedContent ct) mcontent
 
     reps = appEndo (Writer.execWriter w) []
diff --git a/Yesod/Core/Json.hs b/Yesod/Core/Json.hs
--- a/Yesod/Core/Json.hs
+++ b/Yesod/Core/Json.hs
@@ -133,8 +133,10 @@
         J.Error s -> invalidArgs [pack s]
         J.Success a -> return a
 
--- | Same as 'requireJsonBody', but ensures that the mime type
--- indicates JSON content.
+-- | Same as 'requireJsonBody', but ensures that the MIME type
+-- indicates JSON content. Requiring a JSON content-type helps secure your site against
+-- CSRF attacks (browsers will perform POST requests for form and text/plain content-types
+-- without doing a CORS check, and those content-types can easily contain valid JSON).
 requireCheckJsonBody :: (MonadHandler m, J.FromJSON a) => m a
 requireCheckJsonBody = do
     ra <- parseCheckJsonBody
diff --git a/Yesod/Core/Types.hs b/Yesod/Core/Types.hs
--- a/Yesod/Core/Types.hs
+++ b/Yesod/Core/Types.hs
@@ -17,6 +17,7 @@
 import           Control.Monad.IO.Class             (MonadIO (liftIO))
 import           Control.Monad.Logger               (LogLevel, LogSource,
                                                      MonadLogger (..))
+import           Control.Monad.Primitive            (PrimMonad (..))
 import           Control.Monad.Trans.Resource       (MonadResource (..), InternalState, runInternalState, MonadThrow (..), ResourceT)
 import           Data.ByteString                    (ByteString)
 import qualified Data.ByteString.Lazy               as L
@@ -417,6 +418,10 @@
         unWidgetFor (f a) wd
 instance MonadIO (WidgetFor site) where
     liftIO = WidgetFor . const
+-- | @since 1.6.7
+instance PrimMonad (WidgetFor site) where
+    type PrimState (WidgetFor site) = PrimState IO
+    primitive = liftIO . primitive
 -- | @since 1.4.38
 instance MonadUnliftIO (WidgetFor site) where
   {-# INLINE askUnliftIO #-}
@@ -448,6 +453,10 @@
     HandlerFor x >>= f = HandlerFor $ \r -> x r >>= \x' -> unHandlerFor (f x') r
 instance MonadIO (HandlerFor site) where
     liftIO = HandlerFor . const
+-- | @since 1.6.7
+instance PrimMonad (HandlerFor site) where
+    type PrimState (HandlerFor site) = PrimState IO
+    primitive = liftIO . primitive
 instance MonadReader (HandlerData site site) (HandlerFor site) where
     ask = HandlerFor return
     local f (HandlerFor g) = HandlerFor $ g . f
diff --git a/test/YesodCoreTest/ErrorHandling.hs b/test/YesodCoreTest/ErrorHandling.hs
--- a/test/YesodCoreTest/ErrorHandling.hs
+++ b/test/YesodCoreTest/ErrorHandling.hs
@@ -40,6 +40,11 @@
 /file-bad-name FileBadNameR GET
 
 /good-builder GoodBuilderR GET
+
+/auth-not-accepted AuthNotAcceptedR GET
+/auth-not-adequate AuthNotAdequateR GET
+/args-not-valid ArgsNotValidR POST
+/only-plain-text OnlyPlainTextR GET
 |]
 
 overrideStatus :: Status
@@ -119,6 +124,18 @@
 getErrorR 10 = setMessage undefined
 getErrorR x = error $ "getErrorR: " ++ show x
 
+getAuthNotAcceptedR :: Handler TypedContent
+getAuthNotAcceptedR = notAuthenticated
+
+getAuthNotAdequateR :: Handler TypedContent
+getAuthNotAdequateR = permissionDenied "That doesn't belong to you. "
+
+postArgsNotValidR :: Handler TypedContent
+postArgsNotValidR = invalidArgs ["Doesn't matter.", "Don't want it."]
+
+getOnlyPlainTextR :: Handler TypedContent
+getOnlyPlainTextR = selectRep $ provideRepType "text/plain" $ return ("Only plain text." :: Text)
+
 errorHandlingTest :: Spec
 errorHandlingTest = describe "Test.ErrorHandling" $ do
       it "says not found" caseNotFound
@@ -132,6 +149,11 @@
       it "file with bad name" caseFileBadName
       it "builder includes content-length" caseGoodBuilder
       forM_ [1..10] $ \i -> it ("error case " ++ show i) (caseError i)
+      it "accept DVI file, invalid args -> 400" caseDviInvalidArgs
+      it "accept audio, not authenticated -> 401" caseAudioNotAuthenticated
+      it "accept CSS, permission denied -> 403" caseCssPermissionDenied
+      it "accept image, non-existent path -> 404" caseImageNotFound
+      it "accept video, bad method -> 405" caseVideoBadMethod
 
 runner :: Session a -> IO a
 runner f = toWaiApp App >>= runSession f
@@ -222,3 +244,50 @@
     ReaderT $ \r -> StateT $ \s -> runStateT (runReaderT (assertStatus 500 res) r) s `E.catch` \e -> do
         liftIO $ print res
         E.throwIO (e :: E.SomeException)
+
+caseDviInvalidArgs :: IO ()
+caseDviInvalidArgs = runner $ do
+    res <- request defaultRequest
+            { pathInfo = ["args-not-valid"]
+            , requestMethod = "POST"
+            , requestHeaders =
+                ("accept", "application/x-dvi") : requestHeaders defaultRequest
+            }
+    assertStatus 400 res
+
+caseAudioNotAuthenticated :: IO ()
+caseAudioNotAuthenticated = runner $ do
+    res <- request defaultRequest
+            { pathInfo = ["auth-not-accepted"]
+            , requestHeaders =
+                ("accept", "audio/mpeg") : requestHeaders defaultRequest
+            }
+    assertStatus 401 res
+
+caseCssPermissionDenied :: IO ()
+caseCssPermissionDenied = runner $ do
+    res <- request defaultRequest
+            { pathInfo = ["auth-not-adequate"]
+            , requestHeaders =
+                ("accept", "text/css") : requestHeaders defaultRequest
+            }
+    assertStatus 403 res
+
+caseImageNotFound :: IO ()
+caseImageNotFound = runner $ do
+    res <- request defaultRequest
+            { pathInfo = ["not_a_path"]
+            , requestHeaders =
+                ("accept", "image/jpeg") : requestHeaders defaultRequest
+            }
+    assertStatus 404 res
+
+caseVideoBadMethod :: IO ()
+caseVideoBadMethod = runner $ do
+    res <- request defaultRequest
+            { pathInfo = ["good-builder"]
+            , requestMethod = "DELETE"
+            , requestHeaders =
+                ("accept", "video/webm") : requestHeaders defaultRequest
+            }
+    assertStatus 405 res
diff --git a/test/YesodCoreTest/Header.hs b/test/YesodCoreTest/Header.hs
--- a/test/YesodCoreTest/Header.hs
+++ b/test/YesodCoreTest/Header.hs
@@ -69,9 +69,16 @@
     assertHeader "michael" "snoyman" res
     assertHeader "yesod" "book" res
 
+xssHeaderTest :: IO ()
+xssHeaderTest = do
+  runner $ do
+    res <- request defaultRequest {pathInfo = decodePathSegments "/header1"}
+    assertHeader "X-XSS-Protection" "1; mode=block" res
+
 headerTest :: Spec
 headerTest =
   describe "Test.Header" $ do
     it "addHeader" addHeaderTest
     it "multiple header" multipleHeaderTest
     it "persist headers" header3Test
+    it "has X-XSS-Protection: 1; mode=block" xssHeaderTest
diff --git a/test/YesodCoreTest/Reps.hs b/test/YesodCoreTest/Reps.hs
--- a/test/YesodCoreTest/Reps.hs
+++ b/test/YesodCoreTest/Reps.hs
@@ -85,7 +85,6 @@
     test "text/html" "HTML"
     test specialHtml "HTMLSPECIAL"
     testRequest 200 (acceptRequest "application/json") { pathInfo = ["json"] } "{\"message\":\"Invalid Login\"}"
-    testRequest 406 (acceptRequest "text/foo") "no match found for accept header"
     test "text/*" "HTML"
     test "*/*" "HTML"
   describe "routeAttrs" $ do
diff --git a/yesod-core.cabal b/yesod-core.cabal
--- a/yesod-core.cabal
+++ b/yesod-core.cabal
@@ -1,5 +1,5 @@
 name:            yesod-core
-version:         1.6.6
+version:         1.6.7
 license:         MIT
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
@@ -42,6 +42,7 @@
                    , mtl
                    , parsec                >= 2        && < 3.2
                    , path-pieces           >= 0.1.2    && < 0.3
+                   , primitive             >= 0.6
                    , random                >= 1.0.0.2  && < 1.2
                    , resourcet             >= 1.2
                    , rio
