diff --git a/Codec/Encryption/OpenPGP/Serialize.hs b/Codec/Encryption/OpenPGP/Serialize.hs
--- a/Codec/Encryption/OpenPGP/Serialize.hs
+++ b/Codec/Encryption/OpenPGP/Serialize.hs
@@ -1018,6 +1018,10 @@
         case lenOrPartial of
             Right len -> getLazyByteString len
             Left partialLen -> do
+                when
+                    (partialLen < 512)
+                    $ fail
+                        "First partial body length MUST be at least 512 octets (RFC9580 \xa74.2.1.4)."
                 chunk <- getLazyByteString partialLen
                 rest <- getRemainingPartialPayload
                 return (chunk <> rest)
diff --git a/Data/Conduit/OpenPGP/Decrypt.hs b/Data/Conduit/OpenPGP/Decrypt.hs
--- a/Data/Conduit/OpenPGP/Decrypt.hs
+++ b/Data/Conduit/OpenPGP/Decrypt.hs
@@ -771,6 +771,9 @@
                     -- RFC9580 Padding Packet (tag 21) can be ignored after decryption.
                     (PaddingPkt _) ->
                         return (SomeDecryptStreamState (ActiveDecryptState s), [])
+                    -- RFC9580 Marker Packet (tag 10): "MUST be ignored when encountered."
+                    (MarkerPkt _) ->
+                        return (SomeDecryptStreamState (ActiveDecryptState s), [])
                     (OtherPacketPkt t _)
                         | t < 40 ->
                             fail
diff --git a/hOpenPGP.cabal b/hOpenPGP.cabal
--- a/hOpenPGP.cabal
+++ b/hOpenPGP.cabal
@@ -1,6 +1,6 @@
 Cabal-version:       3.4
 Name:                hOpenPGP
-Version:             3.6.2
+Version:             3.6.3
 Synopsis:            native Haskell implementation of OpenPGP (RFC9580)
 Description:         native Haskell implementation of OpenPGP (RFC9580), with some backwards compatibility
 Homepage:            https://salsa.debian.org/clint/hOpenPGP
@@ -346,4 +346,4 @@
 source-repository this
   type:     git
   location: https://salsa.debian.org/clint/hOpenPGP.git
-  tag:      v3.6.2
+  tag:      v3.6.3
diff --git a/tests/Tests/Encryption.hs b/tests/Tests/Encryption.hs
--- a/tests/Tests/Encryption.hs
+++ b/tests/Tests/Encryption.hs
@@ -588,6 +588,9 @@
                    , testCase
                         "testDecrypt matches checked lenient trailing behavior"
                         testOptionsMatchesCheckedLenientTrailingSEIPDv2
+                   , testCase
+                        "outer-stream MarkerPkt is silently stripped (RFC 9580 §6)"
+                        testOuterStreamMarkerPktIsStripped
                    ]
             )
         , testGroup
@@ -1368,6 +1371,38 @@
         "options conduit should match checked lenient conduit with trailing data"
         checkedResult
         optionsResult
+
+testOuterStreamMarkerPktIsStripped :: Assertion
+testOuterStreamMarkerPktIsStripped = do
+    pt <- encryptedSEIPDv2Packets
+    let withMarker =
+            case pt of
+                (esk : seipd : rest) ->
+                    [esk, MarkerPkt "\x50\x47\x50", seipd] ++ rest
+                _ -> pt
+        passphrase = B.pack (map (fromIntegral . fromEnum) ("test" :: String))
+        cb = const (pure passphrase)
+    (outcome, decrypted) <-
+        catch
+            ( DC.runConduitRes $
+                CL.sourceList withMarker
+                    DC..| fuseBoth (testDecryptChecked cb) CL.consume
+            )
+            ( \e ->
+                assertFailure
+                    ("unexpected exception: " ++ show (e :: SomeException))
+                    >> fail "unreachable"
+            )
+    assertEqual
+        "MarkerPkt in outer stream should not disturb decrypt outcome"
+        DecryptClean
+        outcome
+    assertBool
+        "MarkerPkt must not appear in the decrypted packet stream"
+        (not (any isMarkerPkt decrypted))
+  where
+    isMarkerPkt (MarkerPkt _) = True
+    isMarkerPkt _ = False
 
 testRejectsNonEncryptedAfterESKPrelude :: Assertion
 testRejectsNonEncryptedAfterESKPrelude = do
diff --git a/tests/Tests/Serialization.hs b/tests/Tests/Serialization.hs
--- a/tests/Tests/Serialization.hs
+++ b/tests/Tests/Serialization.hs
@@ -63,6 +63,7 @@
     )
 import Codec.Encryption.OpenPGP.Serialize
     ( parsePkts
+    , parsePktsEither
     , parsePktsWithWireRep
     )
 import Codec.Encryption.OpenPGP.Signatures
@@ -441,6 +442,9 @@
             , testCase
                 "v6-secret fixture creates SigV6 with multiple hash algorithms"
                 testV6SecretFixtureMultiHashSignatures
+            , testCase
+                "first partial body length MUST be at least 512 octets (RFC 9580 \xa74.2.1.4)"
+                testFirstPartialBodyLengthMustBeAtLeast512
             ]
         ]
 
@@ -1316,3 +1320,24 @@
     mapM_
         testHash
         [SHA224, SHA256, SHA384, SHA512, SHA3_256, SHA3_512]
+
+{- | Regression test for RFC 9580 \xa74.2.1.4: "The first partial length MUST
+be at least 512 octets long."  A synthetic new-format body that begins with a
+partial-length octet encoding 256 bytes (@0xE8@, since @256 = 1 \<\< 8@ and
+@0xE0 .|. 8 = 0xE8@) followed by a final-length header must be rejected.
+-}
+testFirstPartialBodyLengthMustBeAtLeast512 :: Assertion
+testFirstPartialBodyLengthMustBeAtLeast512 = do
+    let encoded =
+            runPut $ do
+                putWord8 0xcb
+                putWord8 0xe8
+                putByteString (B.replicate 256 0)
+                putWord8 0x00
+    case parsePktsEither encoded of
+        Left _ -> pure ()
+        Right pkts ->
+            assertFailure
+                ( "first partial length < 512 must be rejected, but parsed: "
+                    ++ show pkts
+                )
