diff --git a/Cargo.lock b/Cargo.lock
index 89c50507..13bd1d47 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2550,8 +2550,6 @@ dependencies = [
 [[package]]
 name = "time"
 version = "0.3.46"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9da98b7d9b7dad93488a84b8248efc35352b0b2657397d4167e7ad67e5d535e5"
 dependencies = [
  "deranged",
  "itoa",
diff --git a/Cargo.toml b/Cargo.toml
index 527e0dbb..d122e5b9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -89,3 +89,6 @@ tinyvec = "1.2.0"
 url = "2"
 xml5ever = "0.18.0"
 yeslogic-fontconfig-sys = "6.0.0"
+
+[patch.crates-io]
+time = { path="vendor/time-0.3.46" }
diff --git a/vendor/time-0.3.46/src/parsing/combinator/rfc/rfc2822.rs b/vendor/time-0.3.46/src/parsing/combinator/rfc/rfc2822.rs
index 41a359da..32a47c52 100644
--- a/vendor/time-0.3.46/src/parsing/combinator/rfc/rfc2822.rs
+++ b/vendor/time-0.3.46/src/parsing/combinator/rfc/rfc2822.rs
@@ -6,6 +6,8 @@ use crate::parsing::ParsedItem;
 use crate::parsing::combinator::rfc::rfc2234::wsp;
 use crate::parsing::combinator::{ascii_char, one_or_more, zero_or_more};
 
+const DEPTH_LIMIT: u8 = 32;
+
 /// Consume the `fws` rule.
 // The full rule is equivalent to /\r\n[ \t]+|[ \t]+(?:\r\n[ \t]+)*/
 #[inline]
@@ -25,15 +27,24 @@ pub(crate) fn fws(mut input: &[u8]) -> Option<ParsedItem<'_, ()>> {
 // The full rule is equivalent to any combination of `fws` and `comment` so long as it is not empty.
 #[inline]
 pub(crate) fn cfws(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
-    one_or_more(|input| fws(input).or_else(|| comment(input)))(input)
+    one_or_more(|input| fws(input).or_else(|| comment(input, 1)))(input)
 }
 
 /// Consume the `comment` rule.
 #[inline]
-fn comment(mut input: &[u8]) -> Option<ParsedItem<'_, ()>> {
+fn comment(mut input: &[u8], depth: u8) -> Option<ParsedItem<'_, ()>> {
+    // Avoid stack exhaustion DoS by limiting recursion depth. This will cause highly-nested
+    // comments to fail parsing, but comments *at all* are incredibly rare in practice.
+    //
+    // The error from this will not be descriptive, but the rarity and near-certain maliciousness of
+    // such inputs makes this an acceptable trade-off.
+    if depth == DEPTH_LIMIT {
+        return None;
+    }
+
     input = ascii_char::<b'('>(input)?.into_inner();
     input = zero_or_more(fws)(input).into_inner();
-    while let Some(rest) = ccontent(input) {
+    while let Some(rest) = ccontent(input, depth + 1) {
         input = rest.into_inner();
         input = zero_or_more(fws)(input).into_inner();
     }
@@ -44,10 +55,10 @@ fn comment(mut input: &[u8]) -> Option<ParsedItem<'_, ()>> {
 
 /// Consume the `ccontent` rule.
 #[inline]
-fn ccontent(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
+fn ccontent(input: &[u8], depth: u8) -> Option<ParsedItem<'_, ()>> {
     ctext(input)
         .or_else(|| quoted_pair(input))
-        .or_else(|| comment(input))
+        .or_else(|| comment(input, depth))
 }
 
 /// Consume the `ctext` rule.
