diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,8 @@
-## [_Unreleased_](https://github.com/freckle/aws-sns-verify/compare/v0.0.0.0...main)
+## [_Unreleased_](https://github.com/freckle/aws-sns-verify/compare/v0.0.0.2...main)
+
+## [v0.0.0.2](https://github.com/freckle/aws-sns-verify/compare/v0.0.0.2...v0.0.0.1)
+
+- Validate PEM has come from AWS before checking signature.
 
 ## [v0.0.0.1](https://github.com/freckle/aws-sns-verify/compare/v0.0.0.1...v0.0.0.0)
 
diff --git a/aws-sns-verify.cabal b/aws-sns-verify.cabal
--- a/aws-sns-verify.cabal
+++ b/aws-sns-verify.cabal
@@ -1,6 +1,6 @@
 cabal-version:      1.18
 name:               aws-sns-verify
-version:            0.0.0.1
+version:            0.0.0.2
 license:            MIT
 license-file:       LICENSE
 copyright:          2022 Freckle By Renaissance
@@ -28,11 +28,17 @@
     type:     git
     location: https://github.com/freckle/aws-sns-verify
 
+flag development
+    description: Configure of testing
+    default:     False
+    manual:      True
+
 library
     exposed-modules:
         Amazon.SNS.Verify
         Amazon.SNS.Verify.Payload
         Amazon.SNS.Verify.Validate
+        Amazon.SNS.Verify.ValidURI
 
     hs-source-dirs:     library
     other-modules:      Amazon.SNS.Verify.Prelude
@@ -59,7 +65,9 @@
         errors >=2.3.0,
         http-conduit >=2.3.2,
         memory >=0.14.18,
+        network-uri >=2.6.1.0,
         pem >=0.2.4,
+        regex-tdfa >=1.2.3.1,
         text >=1.2.3.1,
         x509 >=1.7.5,
         x509-validation >=1.6.11
@@ -71,6 +79,9 @@
     if impl(ghc >=9.2.2)
         ghc-options: -Wno-missing-kind-signatures
 
+    if flag(development)
+        cpp-options: -DDEVELOPMENT
+
 test-suite aws-sns-verify-test
     type:               exitcode-stdio-1.0
     main-is:            Main.hs
@@ -78,6 +89,7 @@
     other-modules:
         Amazon.SNS.Verify.TestPrelude
         Amazon.SNS.Verify.ValidateSpec
+        Amazon.SNS.Verify.ValidURISpec
         Amazon.SNS.VerifySpec
         Paths_aws_sns_verify
 
@@ -104,6 +116,7 @@
         base >=4.7 && <5,
         hspec >=2.5.5,
         http-types >=0.12.2,
+        regex-tdfa >=1.2.3.1,
         text >=1.2.3.1,
         wai >=3.2.1.2,
         warp >=3.2.25,
diff --git a/library/Amazon/SNS/Verify.hs b/library/Amazon/SNS/Verify.hs
--- a/library/Amazon/SNS/Verify.hs
+++ b/library/Amazon/SNS/Verify.hs
@@ -22,7 +22,7 @@
 -- The same as 'verifySNSMessage', but decodes the message as `JSON`.
 --
 verifySNSMessageJSON :: (FromJSON a, MonadIO m) => Value -> m a
-verifySNSMessageJSON = unTry id <=< verifySNSMessageJSONEither
+verifySNSMessageJSON = unTryIO id <=< verifySNSMessageJSONEither
 
 verifySNSMessageJSONEither
   :: (FromJSON a, MonadIO m)
@@ -47,7 +47,7 @@
 -- 3. And in the case of subscription events responded to.
 --
 verifySNSMessage :: MonadIO m => Value -> m Text
-verifySNSMessage = unTry id <=< verifySNSMessageEither
+verifySNSMessage = unTryIO id <=< verifySNSMessageEither
 
 verifySNSMessageEither
   :: MonadIO m => Value -> m (Either SNSNotificationValidationError Text)
diff --git a/library/Amazon/SNS/Verify/Prelude.hs b/library/Amazon/SNS/Verify/Prelude.hs
--- a/library/Amazon/SNS/Verify/Prelude.hs
+++ b/library/Amazon/SNS/Verify/Prelude.hs
@@ -5,6 +5,7 @@
 
 import Prelude as X
 
+import Control.Error (ExceptT, throwE)
 import Control.Exception as X (Exception)
 import qualified Control.Exception
 import Control.Monad as X (join, (<=<))
@@ -16,8 +17,11 @@
 throwIO :: (MonadIO m, Exception e) => e -> m a
 throwIO = liftIO . Control.Exception.throwIO
 
-unTry :: (MonadIO m, Exception e) => (a -> e) -> Either a b -> m b
-unTry e = either (throwIO . e) pure
+unTryIO :: (MonadIO m, Exception e) => (a -> e) -> Either a b -> m b
+unTryIO e = either (throwIO . e) pure
+
+unTryE :: (Monad m) => (a -> e) -> Either a b -> ExceptT e m b
+unTryE e = either (throwE . e) pure
 
 fromMaybeM :: Monad m => m a -> Maybe a -> m a
 fromMaybeM f = maybe f pure
diff --git a/library/Amazon/SNS/Verify/ValidURI.hs b/library/Amazon/SNS/Verify/ValidURI.hs
new file mode 100644
--- /dev/null
+++ b/library/Amazon/SNS/Verify/ValidURI.hs
@@ -0,0 +1,38 @@
+{-# LANGUAGE CPP #-}
+
+module Amazon.SNS.Verify.ValidURI
+  ( validScheme
+  , validRegPattern
+  , devRegPattern
+  , prodRegPattern
+  ) where
+
+import Amazon.SNS.Verify.Prelude
+
+validScheme :: String
+validScheme =
+#ifdef DEVELOPMENT
+  _devScheme
+#else
+  _prodScheme
+#endif
+
+_devScheme :: String
+_devScheme = "http:"
+
+_prodScheme :: String
+_prodScheme = "https:"
+
+validRegPattern :: String
+validRegPattern =
+#ifdef DEVELOPMENT
+  devRegPattern
+#else
+  prodRegPattern
+#endif
+
+devRegPattern :: String
+devRegPattern = "^localhost$"
+
+prodRegPattern :: String
+prodRegPattern = "^sns\\.[a-zA-Z0-9\\-]{3,}\\.amazonaws\\.com(\\.cn)?$"
diff --git a/library/Amazon/SNS/Verify/Validate.hs b/library/Amazon/SNS/Verify/Validate.hs
--- a/library/Amazon/SNS/Verify/Validate.hs
+++ b/library/Amazon/SNS/Verify/Validate.hs
@@ -8,6 +8,7 @@
 import Amazon.SNS.Verify.Prelude
 
 import Amazon.SNS.Verify.Payload
+import Amazon.SNS.Verify.ValidURI (validRegPattern, validScheme)
 import Control.Error (ExceptT, catMaybes, headMay, runExceptT, throwE)
 import Control.Monad (when)
 import Data.ByteArray.Encoding (Base(Base64), convertFromBase)
@@ -27,6 +28,8 @@
   (SignatureFailure, SignatureVerification(..), verifySignature)
 import Network.HTTP.Simple
   (getResponseBody, getResponseStatusCode, httpLbs, parseRequest_)
+import Network.URI (parseURI, uriAuthority, uriRegName, uriScheme)
+import Text.Regex.TDFA ((=~))
 
 data ValidSNSMessage
   = SNSMessage Text
@@ -46,7 +49,7 @@
   => SNSPayload
   -> m (Either SNSNotificationValidationError ValidSNSMessage)
 validateSnsMessage payload@SNSPayload {..} = runExceptT $ do
-  signature <- unTry BadSignature $ convertFromBase Base64 $ encodeUtf8
+  signature <- unTryE BadSignature $ convertFromBase Base64 $ encodeUtf8
     snsSignature
   signedCert <- retrieveCertificate payload
   let
@@ -67,12 +70,24 @@
   => SNSPayload
   -> ExceptT SNSNotificationValidationError m SignedCertificate
 retrieveCertificate SNSPayload {..} = do
-  response <- httpLbs $ parseRequest_ $ T.unpack snsSigningCertURL
-  pems <- unTry BadPem $ pemParseLBS $ getResponseBody response
+  certUrlStr <- unTryE id $ validateCertUrl snsSigningCertURL
+  response <- httpLbs $ parseRequest_ certUrlStr
+  pems <- unTryE BadPem $ pemParseLBS $ getResponseBody response
   cert <-
     fromMaybeM (throwE $ BadPem "Empty List") $ pemContent <$> headMay pems
-  unTry BadCert $ decodeSignedCertificate cert
+  unTryE BadCert $ decodeSignedCertificate cert
 
+validateCertUrl :: Text -> Either SNSNotificationValidationError String
+validateCertUrl certUrl = do
+  uri <- fromMaybeM (Left $ BadUri certUrlStr) $ parseURI certUrlStr
+  if uriScheme uri
+      == validScheme
+      && maybe "" uriRegName (uriAuthority uri)
+      =~ validRegPattern
+    then Right certUrlStr
+    else Left $ BadUri certUrlStr
+  where certUrlStr = T.unpack certUrl
+
 unsignedSignature :: SNSPayload -> ByteString
 unsignedSignature SNSPayload {..} =
   encodeUtf8 $ mconcat $ (<> "\n") <$> catMaybes
@@ -110,16 +125,17 @@
   SNSSubscribe SNSSubscription {..} -> do
     response <- httpLbs $ parseRequest_ $ T.unpack snsSubscribeURL
     when (getResponseStatusCode response >= 300) $ do
-      throwE $ BadSubscription ()
+      throwE BadSubscription
     throwE SubscribeMessageResponded
   SNSUnsubscribe{} -> throwE UnsubscribeMessage
 
 data SNSNotificationValidationError
   = BadPem String
+  | BadUri String
   | BadSignature String
   | BadCert String
   | BadJSONParse String
-  | BadSubscription ()
+  | BadSubscription
   | InvalidPayload SignatureFailure
   | MissingMessageTypeHeader
   | UnsubscribeMessage
diff --git a/tests/Amazon/SNS/Verify/TestPrelude.hs b/tests/Amazon/SNS/Verify/TestPrelude.hs
--- a/tests/Amazon/SNS/Verify/TestPrelude.hs
+++ b/tests/Amazon/SNS/Verify/TestPrelude.hs
@@ -18,11 +18,9 @@
   (setReady, whenReady) <- initReadyState
   race_ (whenReady action)
     $ runSettings (setBeforeMainLoop setReady . setPort 3000 $ defaultSettings)
-    $ \_req send -> send $ responseFile
-        ok200
-        [("Content-Type", "text/plain")]
-        "./tests/cert.pem"
-        Nothing
+    $ \req send -> if rawPathInfo req == "/404"
+        then send $ responseLBS notFound404 [] ""
+        else send $ responseFile ok200 [] "./tests/cert.pem" Nothing
  where
   initReadyState = do
     ready <- newEmptyMVar
diff --git a/tests/Amazon/SNS/Verify/ValidURISpec.hs b/tests/Amazon/SNS/Verify/ValidURISpec.hs
new file mode 100644
--- /dev/null
+++ b/tests/Amazon/SNS/Verify/ValidURISpec.hs
@@ -0,0 +1,22 @@
+{-# LANGUAGE NoOverloadedStrings #-}
+
+module Amazon.SNS.Verify.ValidURISpec
+  ( spec
+  ) where
+
+import Amazon.SNS.Verify.TestPrelude
+
+import Amazon.SNS.Verify.ValidURI
+import Text.Regex.TDFA ((=~))
+
+spec :: Spec
+spec = around_ useCertServer $ do
+  describe "verifySNSMessage" $ do
+    it "validates a prod schema" $ do
+      "sns.us-east-2.amazonaws.com" `shouldSatisfy` (=~ prodRegPattern)
+
+    it "validates a prod schema" $ do
+      "sns.us-west-1b.amazonaws.com" `shouldSatisfy` (=~ prodRegPattern)
+
+    it "validates a prod schema" $ do
+      "www.google.com" `shouldNotSatisfy` (=~ prodRegPattern)
diff --git a/tests/Amazon/SNS/Verify/ValidateSpec.hs b/tests/Amazon/SNS/Verify/ValidateSpec.hs
--- a/tests/Amazon/SNS/Verify/ValidateSpec.hs
+++ b/tests/Amazon/SNS/Verify/ValidateSpec.hs
@@ -62,7 +62,7 @@
           , snsSignatureVersion = "1"
           , snsSignature =
             "Dg24trcOUiLjclt5JwyJS0JEOnEEbi6P30XS6KBxMCwzZ08a04UwjaFTW9Ae8xurhBS5YESz1fY28vTwvEmxh/20WmB3bWIDOMp9v5RI8XSZOvpMm+hdQJ43VqGhEDyAvRU6iCDLihDlZNc/sBCwl9X0H4kh/8vIElRif9gFBbYI94ZHGgqEV+Zc3gVKo9Udrl/MxNvMVadsO/+/oPVUeWibQr3xfGK95oc/ocuNAgi0MOxZmLVnibHu36KOTSvy2qSLonnRRFcbaauYZJ4js7oTq+1ujXNO72oPLaeG3pVJ2grqMc5z8tKQxFnSTE3es7wQarU/CLrbO8j0isbnWw=="
-          , snsSigningCertURL = "https://freckle.com/404.pem"
+          , snsSigningCertURL = "http://localhost:3000/404"
           , snsTypePayload = Notification $ SNSNotification
             { snsSubject =
               Just
@@ -70,6 +70,26 @@
             }
           }
       go `shouldReturn` Left (BadPem "Empty List")
+
+    it "fails to validate an unexpected url" $ do
+      let
+        go = validateSnsMessage $ SNSPayload
+          { snsMessage = "Some message"
+          , snsMessageId = "corrupt"
+          , snsTimestamp = "2022-05-18T14:52:26.952Z"
+          , snsTopicArn = "arn:aws:sns:us-west-2:123456789012:MyTopic"
+          , snsType = "Notification"
+          , snsSignatureVersion = "1"
+          , snsSignature =
+            "Dg24trcOUiLjclt5JwyJS0JEOnEEbi6P30XS6KBxMCwzZ08a04UwjaFTW9Ae8xurhBS5YESz1fY28vTwvEmxh/20WmB3bWIDOMp9v5RI8XSZOvpMm+hdQJ43VqGhEDyAvRU6iCDLihDlZNc/sBCwl9X0H4kh/8vIElRif9gFBbYI94ZHGgqEV+Zc3gVKo9Udrl/MxNvMVadsO/+/oPVUeWibQr3xfGK95oc/ocuNAgi0MOxZmLVnibHu36KOTSvy2qSLonnRRFcbaauYZJ4js7oTq+1ujXNO72oPLaeG3pVJ2grqMc5z8tKQxFnSTE3es7wQarU/CLrbO8j0isbnWw=="
+          , snsSigningCertURL = "http://attacker.com/evil.pem"
+          , snsTypePayload = Notification $ SNSNotification
+            { snsSubject =
+              Just
+                "SynthesisTaskNotification { TaskId: 680a1f1b-f3ae-4474-aa8f-3b6dfe52e656, Status: COMPLETED }"
+            }
+          }
+      go `shouldReturn` Left (BadUri "http://attacker.com/evil.pem")
 
     it "successfully validates an SNS subscription" $ do
       -- pendingWith "need valid subscription payload"
