diff --git a/CHANGES b/CHANGES
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,47 @@
+Version 0.14.0.0 released 12 Aug 2021
+
+  * PDF export: fix vulnerability.  Augustin Laville pointed
+    out that it is possible to leak content from files on the
+    file system in PDF export.  This can be done by simply including
+
+        \include{/path/to/file}
+
+    in the markdown; the raw tex is passed through to the
+    LaTeX intermediary when producing a PDF.  In many cases
+    this will lead to a LaTeX syntax error, but there are ways of
+    injecting TeX includes into a verbatim environment.
+    The solution is to cause latex to use a local texmf.cnf
+    file when exporting PDF. The texmf.cnf file can specify
+    openout_any = p and openin_any = p, which prevents access
+    to hidden files and files outside the current tree.
+
+  * Made SessionKey a newtype (API change).  This avoids orphan
+    instance warnings.  Removed unused orphan `instance FromReqURI [String]`.
+
+  * Remove deprecated `defaultCleanupHandler`.
+
+  * Handle Underline element in converting inlines to strings.
+
+  * Allow compilation with pandoc 2.12 and 2.13 (#670, sterni).
+    pandoc 2.13 introduced the following breakages for gitit.
+
+  * Allow building with pandoc-2.14 (#673, Jens Petersen).
+
+  * Disable registration bug fixes (#669, zaxtax).
+    Display correct html, fix precedence bug.
+
+  * Add documentation and comment on disabling registration to
+    default config (Rob Zinkov).
+
+  * Add option for disabling registration (Rob Zinkov).
+
+  * Depend on filestore >= 0.6.5 (with embedded data).
+
+  * Relax version bounds in gitit.cabal to fix build from hackage
+    (#665, sternenseemann).
+
+  * Allow building with hoauth-1.14 (Jens Petersen).
+
 Version 0.13.0.0 released 03 June 2020
 
   * Allow building with GHC 8.8
diff --git a/data/default.conf b/data/default.conf
--- a/data/default.conf
+++ b/data/default.conf
@@ -191,6 +191,9 @@
 # specifies the public and private keys for the reCAPTCHA service.
 # To get these, you need to create an account at http://recaptcha.net.
 
+disable-registration: no
+# if "yes", disables registering new users on the wiki
+
 access-question:
 access-question-answers:
 # specifies a question that users must answer when they attempt to create
diff --git a/gitit.cabal b/gitit.cabal
--- a/gitit.cabal
+++ b/gitit.cabal
@@ -1,6 +1,6 @@
 cabal-version:       2.0
 name:                gitit
-version:             0.13.0.0
+version:             0.14.0.0
 build-type:          Simple
 synopsis:            Wiki using happstack, git or darcs, and pandoc.
 description:         Gitit is a wiki backed by a git, darcs, or mercurial
@@ -122,7 +122,7 @@
                      Network.Gitit.Compat.Except,
                      Paths_gitit
   autogen-modules:   Paths_gitit
-  build-depends:     base >= 4.9 && < 5,
+  build-depends:     base >= 4.9 && < 4.15,
                      syb,
                      filepath,
                      safe,
@@ -135,9 +135,10 @@
                      directory,
                      mtl,
                      old-time,
-                     pandoc >= 2.9 && < 2.10,
-                     pandoc-types >= 1.20 && < 1.21,
-                     skylighting >= 0.8.2.3 && < 0.9,
+                     temporary,
+                     pandoc >= 2.9 && < 2.15,
+                     pandoc-types >= 1.20 && < 1.23,
+                     skylighting >= 0.8.2.3 && < 0.12,
                      bytestring,
                      text,
                      random,
@@ -148,10 +149,10 @@
                      old-locale,
                      time,
                      recaptcha >= 0.1,
-                     filestore >= 0.6.4 && < 0.7,
+                     filestore >= 0.6.5 && < 0.7,
                      zlib >= 0.5 && < 0.7,
                      url >= 2.1,
-                     happstack-server >= 7.5 && < 7.7,
+                     happstack-server >= 7.5 && < 7.8,
                      base64-bytestring >= 0.1,
                      xml >= 1.3.5,
                      hslogger >= 1,
@@ -164,11 +165,11 @@
                      json >= 0.4 && < 0.11,
                      uri-bytestring >= 0.2.3.3,
                      split,
-                     hoauth2 >= 1.3.0 && < 1.12,
+                     hoauth2 >= 1.3.0 && < 1.17,
                      xml-conduit >= 1.5 && < 1.10,
                      http-conduit >= 2.1.6 && < 2.4,
                      http-client-tls >= 0.2.2 && < 0.4,
-                     aeson >= 0.7 && < 1.5,
+                     aeson >= 0.7 && < 1.6,
                      uuid >= 1.3 && < 1.4,
                      network-uri >= 2.6,
                      network >= 2.6 && < 3.2,
@@ -186,7 +187,7 @@
 Executable           gitit
   hs-source-dirs:    .
   main-is:           gitit.hs
-  build-depends:     base >=3 && < 5,
+  build-depends:     base >= 4.9 && < 5,
                      gitit,
                      mtl,
                      hslogger,
diff --git a/src/Network/Gitit/Authentication.hs b/src/Network/Gitit/Authentication.hs
--- a/src/Network/Gitit/Authentication.hs
+++ b/src/Network/Gitit/Authentication.hs
@@ -44,7 +44,7 @@
 import System.Log.Logger (logM, Priority(..))
 import Data.Char (isAlphaNum, isAlpha)
 import qualified Data.Map as M
-import Text.Pandoc.Shared (substitute)
+import Data.List (stripPrefix)
 import Data.Maybe (isJust, fromJust, isNothing, fromMaybe)
 import Network.URL (exportURL, add_param, importURL)
 import Network.BSD (getHostName)
@@ -54,6 +54,16 @@
 import Data.ByteString.UTF8 (toString)
 import Network.Gitit.Rpxnow as R
 
+-- | Replace each occurrence of one sublist in a list with another.
+--   Vendored in from pandoc 2.11.4 as 2.12 removed this function.
+substitute :: (Eq a) => [a] -> [a] -> [a] -> [a]
+substitute _ _ [] = []
+substitute [] _ xs = xs
+substitute target' replacement lst@(x:xs) =
+    case stripPrefix target' lst of
+      Just lst' -> replacement ++ substitute target' replacement lst'
+      Nothing   -> x : substitute target' replacement xs
+
 data ValidationType = Register
                     | ResetPassword
                     deriving (Show,Read)
@@ -350,16 +360,18 @@
       , textfield "destination" ! [thestyle "display: none;", value dest]
       , submit "login" "Login" ! [intAttr "tabindex" 3]
       ] +++
-    p << [ stringToHtml "If you do not have an account, "
-         , anchor ! [href $ base' ++ "/_register?" ++
-           urlEncodeVars [("destination", encodeString dest)]] << "click here to get one."
-         ] +++
-    if null (mailCommand cfg)
+    (if disableRegistration cfg
        then noHtml
+       else p << [ stringToHtml "If you do not have an account, "
+                 , anchor ! [href $ base' ++ "/_register?" ++
+                     urlEncodeVars [("destination", encodeString dest)]] << "click here to get one."
+                 ]) +++
+    (if null (mailCommand cfg)
+       then noHtml
        else p << [ stringToHtml "If you forgot your password, "
                  , anchor ! [href $ base' ++ "/_resetPassword"] <<
                      "click here to get a new one."
-                 ]
+                 ])
 
 loginUserForm :: Handler
 loginUserForm = withData $ \params -> do
@@ -410,11 +422,18 @@
                     pgTitle = "Register for an account"
                     }
 
-formAuthHandlers :: [Handler]
-formAuthHandlers =
+regAuthHandlers :: [Handler]
+regAuthHandlers =
   [ dir "_register"  $ method GET >> registerUserForm
   , dir "_register"  $ method POST >> withData registerUser
-  , dir "_login"     $ method GET  >> loginUserForm
+  ]
+
+formAuthHandlers :: Bool -> [Handler]
+formAuthHandlers disableReg =
+  (if disableReg
+    then []
+    else regAuthHandlers) ++
+  [ dir "_login"     $ method GET  >> loginUserForm
   , dir "_login"     $ method POST >> withData loginUser
   , dir "_logout"    $ method GET  >> withData logoutUser
   , dir "_resetPassword"   $ method GET  >> withData resetPasswordRequestForm
diff --git a/src/Network/Gitit/Authentication/Github.hs b/src/Network/Gitit/Authentication/Github.hs
--- a/src/Network/Gitit/Authentication/Github.hs
+++ b/src/Network/Gitit/Authentication/Github.hs
@@ -17,7 +17,6 @@
 import qualified URI.ByteString as URI
 import Network.HTTP.Conduit
 import Network.OAuth.OAuth2
-import Network.OAuth.OAuth2.TokenRequest as OA
 import Control.Monad (liftM, mplus, mzero)
 import Data.Maybe
 import Data.Aeson
diff --git a/src/Network/Gitit/Config.hs b/src/Network/Gitit/Config.hs
--- a/src/Network/Gitit/Config.hs
+++ b/src/Network/Gitit/Config.hs
@@ -110,6 +110,7 @@
       cfNoDelete <- get cp "DEFAULT" "no-delete"
       cfDefaultSummary <- get cp "DEFAULT" "default-summary"
       cfDeleteSummary <- get cp "DEFAULT" "delete-summary"
+      cfDisableRegistration <- get cp "DEFAULT" "disable-registration"
       cfAccessQuestion <- get cp "DEFAULT" "access-question"
       cfAccessQuestionAnswers <- get cp "DEFAULT" "access-question-answers"
       cfUseRecaptcha <- get cp "DEFAULT" "use-recaptcha"
@@ -181,7 +182,7 @@
                                        _         -> ForModify
 
         , authHandler          = case authMethod of
-                                      "form"     -> msum formAuthHandlers
+                                      "form"     -> msum $ formAuthHandlers cfDisableRegistration
                                       "github"   -> msum $ githubAuthHandlers ghConfig
                                       "http"     -> msum httpAuthHandlers
                                       "rpx"      -> msum rpxAuthHandlers
@@ -209,6 +210,7 @@
         , noDelete             = splitCommaList cfNoDelete
         , defaultSummary       = cfDefaultSummary
         , deleteSummary        = cfDeleteSummary
+        , disableRegistration  = cfDisableRegistration
         , accessQuestion       = if null cfAccessQuestion
                                     then Nothing
                                     else Just (cfAccessQuestion, splitCommaList cfAccessQuestionAnswers)
diff --git a/src/Network/Gitit/ContentTransformer.hs b/src/Network/Gitit/ContentTransformer.hs
--- a/src/Network/Gitit/ContentTransformer.hs
+++ b/src/Network/Gitit/ContentTransformer.hs
@@ -744,6 +744,9 @@
                Superscript xs          -> mconcat $ map go xs
                Subscript xs            -> mconcat $ map go xs
                SmallCaps xs            -> mconcat $ map go xs
+#if MIN_VERSION_pandoc(2,10,0)
+               Underline xs            -> mconcat $ map go xs
+#endif
                Quoted DoubleQuote xs   -> "\"" <> mconcat (map go xs) <> "\""
                Quoted SingleQuote xs   -> "'" <> mconcat (map go xs) <> "'"
                Cite _ xs               -> mconcat $ map go xs
diff --git a/src/Network/Gitit/Export.hs b/src/Network/Gitit/Export.hs
--- a/src/Network/Gitit/Export.hs
+++ b/src/Network/Gitit/Export.hs
@@ -41,6 +41,7 @@
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Lazy as L
 import System.FilePath ((</>), takeDirectory)
+import System.Environment (setEnv)
 import System.Directory (doesFileExist)
 import Text.HTML.SanitizeXSS
 import Data.ByteString.Lazy (fromStrict)
@@ -49,6 +50,7 @@
 import Data.Text.Encoding (encodeUtf8)
 import Data.List (isPrefixOf)
 import Skylighting (styleToCss, pygments)
+import System.IO.Temp (withSystemTempDirectory)
 import Paths_gitit (getDataFileName)
 
 defaultRespOptions :: WriterOptions
@@ -213,9 +215,15 @@
                else return Nothing
   pdf' <- case cached of
             Just (_modtime, bs) -> return $ Right $ L.fromChunks [bs]
-            Nothing -> do
+            Nothing -> liftIO $
+                withSystemTempDirectory "gitit" $ \tmpdir -> do
               let toc = tableOfContents cfg
-              res <- liftIO $ runIO $ do
+              -- ensure that LaTeX \include commands can't include
+              -- files outside the working directory, e.g. /etc/passwd:
+              writeFile (tmpdir </> "texmf.cnf")
+                "openout_any = p\nopenin_any = p\n"
+              setEnv "TEXMFCNF" (tmpdir ++ ":")
+              res <- runIO $ do
                 setUserDataDir $ pandocUserData cfg
                 setInputFiles [baseUrl cfg]
                 let templ = if useBeamer then "beamer" else "latex"
diff --git a/src/Network/Gitit/Feed.hs b/src/Network/Gitit/Feed.hs
--- a/src/Network/Gitit/Feed.hs
+++ b/src/Network/Gitit/Feed.hs
@@ -46,7 +46,6 @@
 import Text.XML.Light as XML (showContent, Content(..), Element(..), blank_element, QName(..), blank_name, CData(..), blank_cdata)
 import Text.XML as Text.XML (renderText, Document(..), Element(..),
                              Prologue(..), def, fromXMLElement)
-import qualified Data.XML.Types as XMLTypes
 import Data.Version (showVersion)
 import Paths_gitit (version)
 
diff --git a/src/Network/Gitit/Plugins.hs b/src/Network/Gitit/Plugins.hs
--- a/src/Network/Gitit/Plugins.hs
+++ b/src/Network/Gitit/Plugins.hs
@@ -38,28 +38,27 @@
   runGhc (Just libdir) $ do
     dflags <- getSessionDynFlags
     setSessionDynFlags dflags
-    defaultCleanupHandler dflags $ do
-      -- initDynFlags
-      unless ("Network.Gitit.Plugin." `isPrefixOf` pluginName)
-        $ do
-            addTarget =<< guessTarget pluginName Nothing
-            r <- load LoadAllTargets
-            case r of
-              Failed -> error $ "Error loading plugin: " ++ pluginName
-              Succeeded -> return ()
-      let modName =
-            if "Network.Gitit.Plugin" `isPrefixOf` pluginName
-               then pluginName
-               else if "Network/Gitit/Plugin/" `isInfixOf` pluginName
-                       then "Network.Gitit.Plugin." ++ takeBaseName pluginName
-                       else takeBaseName pluginName
-      pr <- parseImportDecl "import Prelude"
-      i <- parseImportDecl "import Network.Gitit.Interface"
-      m <- parseImportDecl ("import " ++ modName)
-      setContext [IIDecl m, IIDecl  i, IIDecl pr]
-      value <- compileExpr (modName ++ ".plugin :: Plugin")
-      let value' = (unsafeCoerce value) :: Plugin
-      return value'
+    -- initDynFlags
+    unless ("Network.Gitit.Plugin." `isPrefixOf` pluginName)
+      $ do
+          addTarget =<< guessTarget pluginName Nothing
+          r <- load LoadAllTargets
+          case r of
+            Failed -> error $ "Error loading plugin: " ++ pluginName
+            Succeeded -> return ()
+    let modName =
+          if "Network.Gitit.Plugin" `isPrefixOf` pluginName
+             then pluginName
+             else if "Network/Gitit/Plugin/" `isInfixOf` pluginName
+                     then "Network.Gitit.Plugin." ++ takeBaseName pluginName
+                     else takeBaseName pluginName
+    pr <- parseImportDecl "import Prelude"
+    i <- parseImportDecl "import Network.Gitit.Interface"
+    m <- parseImportDecl ("import " ++ modName)
+    setContext [IIDecl m, IIDecl  i, IIDecl pr]
+    value <- compileExpr (modName ++ ".plugin :: Plugin")
+    let value' = (unsafeCoerce value) :: Plugin
+    return value'
 
 #else
 
diff --git a/src/Network/Gitit/State.hs b/src/Network/Gitit/State.hs
--- a/src/Network/Gitit/State.hs
+++ b/src/Network/Gitit/State.hs
@@ -120,7 +120,7 @@
 
 newSession :: MonadIO m => SessionData -> m SessionKey
 newSession u = do
-  key <- liftIO $ randomRIO (0, 1000000000)
+  key <- liftIO $ SessionKey <$> randomRIO (0, 1000000000)
   setSession key u
   return key
 
diff --git a/src/Network/Gitit/Types.hs b/src/Network/Gitit/Types.hs
--- a/src/Network/Gitit/Types.hs
+++ b/src/Network/Gitit/Types.hs
@@ -28,7 +28,7 @@
                            , AuthenticationLevel(..)
                            , Config(..)
                            , Page(..)
-                           , SessionKey
+                           , SessionKey(..)
                            -- we do not export SessionData constructors, in case we need to extend  SessionData with other data in the future
                            , SessionData
                            , SessionGithubData
@@ -169,6 +169,8 @@
   -- be given the prompt and must give
   -- one of the answers to register.
   accessQuestion       :: Maybe (String, [String]),
+  -- | Disable Registration?
+  disableRegistration  :: Bool,
   -- | Use ReCAPTCHA for user registration.
   useRecaptcha         :: Bool,
   recaptchaPublicKey   :: String,
@@ -227,7 +229,8 @@
   , pageMeta        :: [(String, String)]
 } deriving (Read, Show)
 
-type SessionKey = Integer
+newtype SessionKey = SessionKey Integer
+  deriving (Read, Show, Eq, Ord)
 
 data SessionData = SessionData {
   sessionUser :: Maybe String,
@@ -245,7 +248,7 @@
 sessionDataGithubStateUrl :: String -> String -> SessionData
 sessionDataGithubStateUrl githubState destination = SessionData Nothing (Just $ SessionGithubData githubState destination)
 
-data Sessions a = Sessions {unsession::M.Map SessionKey a}
+data Sessions a = Sessions {unsession :: M.Map SessionKey a}
   deriving (Read,Show,Eq)
 
 -- Password salt hashedPassword
@@ -370,13 +373,10 @@
                      , pRedirect     :: Maybe Bool
                      }  deriving Show
 
-instance FromReqURI [String] where
-  fromReqURI s = case fromReqURI s of
-                      Just (s' :: String) ->
-                                   case reads s' of
-                                        ((xs,""):_) -> xs
-                                        _           -> Nothing
-                      Nothing             -> Nothing
+instance FromReqURI SessionKey where
+ fromReqURI s = case fromReqURI s of
+                       Just i -> Just $ SessionKey i
+                       Nothing -> Nothing
 
 instance FromData Params where
      fromData = do
diff --git a/src/Network/Gitit/Util.hs b/src/Network/Gitit/Util.hs
--- a/src/Network/Gitit/Util.hs
+++ b/src/Network/Gitit/Util.hs
@@ -36,7 +36,6 @@
 import Control.Monad.Trans (liftIO)
 import Data.Char (toLower, isAscii)
 import Data.Text (Text)
-import qualified Data.Text as T
 import Network.Gitit.Types
 import qualified Control.Exception as E
 import qualified Text.Pandoc.UTF8 as UTF8
@@ -45,7 +44,11 @@
 
 -- | Read file as UTF-8 string.  Encode filename as UTF-8.
 readFileUTF8 :: FilePath -> IO Text
+#if MIN_VERSION_pandoc(2,12,0)
+readFileUTF8 = UTF8.readFile
+#else
 readFileUTF8 = fmap T.pack . UTF8.readFile
+#endif
 
 -- | Perform a function a directory and return to working directory.
 inDir :: FilePath -> IO a -> IO a
