diff --git a/i2p2www/spec/proposals/164-streaming.rst b/i2p2www/spec/proposals/164-streaming.rst
index 4b13eb77bdeaa55a6ed2211890c6210f68a46104..574b182a57d4235686bc0709135455d55424a388 100644
--- a/i2p2www/spec/proposals/164-streaming.rst
+++ b/i2p2www/spec/proposals/164-streaming.rst
@@ -5,9 +5,10 @@ Streaming Updates
     :author: zzz
     :created: 2023-01-24
     :thread: http://zzz.i2p/topics/3541
-    :lastupdated: 2023-01-24
-    :status: Open
+    :lastupdated: 2023-10-23
+    :status: Closed
     :target: 0.9.58
+    :implementedin: 0.9.58
 
 .. contents::
 
@@ -16,45 +17,104 @@ Streaming Updates
 Overview
 ========
 
+Java I2P and i2pd routers older than API 0.9.58 (released March 2023)
+are vulnerable to a streaming SYN packet replay attack.
+This is a protocol design issue, not an implementation bug.
 
+SYN packets are signed, but the signature of the initial SYN packet sent from Alice to Bob
+is not bound to Bob's identity, so Bob may store and replay that packet,
+sending it to some victim Charlie. Charlie will think that the packet came from
+Alice and respond to her. In most cases, this is harmless, but
+the SYN packet may contain initial data (such as a GET or POST) that
+Charlie will process immediately.
 
-Motivation
-==========
 
 
 
 Design
 ======
 
+The fix is for Alice to include Bob's destination hash in the signed SYN data.
+Bob verifies on reception that that hash matches his hash.
+
+Any potential attack victim Charlie
+checks this data and rejects the SYN if it does not match his hash.
+
+By using the NACKs option field in the SYN to store the hash,
+the change is backward-compatible, because NACKs are not expected to be included
+in the SYN packet and are currently ignored.
+
+All options are covered by the signature, as usual, so Bob may not
+rewrite the hash.
+
+If Alice and Charlie are API 0.9.58 or newer, any replay attempt by Bob will be rejected.
+
 
 
 Specification
 =============
 
-Update [STREAMING]_ as follows:
+Update [STREAMING]_ to add the following section:
 
+Replay prevention
+-----------------
 
+To prevent Bob from using a replay attack by storing a valid signed SYNCHRONIZE packet
+received from Alice and later sending it to a victim Charlie,
+Alice must include Bob's destination hash in the SYNCHRONIZE packet as follows:
 
-Security Analysis
-=================
+.. raw:: html
 
+  {% highlight lang='dataspec' %}
+Set NACK count field to 8
+    Set the NACKs field to Bob's 32-byte destination hash
 
+{% endhighlight %}
 
-Notes
-=====
+Upon reception of a SYNCHRONIZE, if the NACK count field is 8,
+Bob must interpret the NACKs field as a 32-byte destination hash,
+and must verify that it matches his destination hash.
+He must also verify the signature of the packet as usual,
+as that covers the entire packet including the NACK count and NACKs fields.
+If the NACK count is 8 and the NACKs field does not match,
+Bob must drop the packet.
 
+This is required for versions 0.9.58 and higher.
+This is backward-compatible with older versions,
+because NACKs are not expected in a SYNCHRONIZE packet.
+Destinations do not and cannot know what version the other end is running.
+
+No change is necessary for the SYNCHRONIZE ACK packet sent from Bob to Alice;
+do not include NACKs in that packet.
+
+
+Security Analysis
+=================
+
+This issue has been present in the streaming protocol since it was created in 2004.
+It was discovered internally by I2P developers.
+We have no evidence that the issue was ever been exploited.
+Actual chance of exploitation success may vary widely depending
+on the application-layer protocol and service.
+Peer-to-peer applications are probably more likely to be affected
+than client/server applications.
 
 
 Compatibility
 ===============
 
-No issues, all implementations ignore.
+No issues. All known implementations currently ignore the NACKs field in the SYN packet.
+And even if they did not ignore it, and attempted to interpret it
+as NACKs for 8 different messages, those messages would not be outstanding
+during the SYNCHRONIZE handshake and the NACKs would not make any sense.
+
 
 
 Migration
 =========
 
-Implementations may add support at any time, no coordination needed.
+Implementations may add support at any time, no coordination is needed.
+Java I2P and i2pd routers implemented this in API 0.9.58 (released March 2023).
 
 
 
diff --git a/i2p2www/spec/streaming.rst b/i2p2www/spec/streaming.rst
index 681679a91d3713c6ff418820b3637d090c6bf468..3dd9b1f23065c011f049909b0ad82e75f1246ba1 100644
--- a/i2p2www/spec/streaming.rst
+++ b/i2p2www/spec/streaming.rst
@@ -3,8 +3,8 @@ Streaming Protocol Specification
 ================================
 .. meta::
     :category: Protocols
-    :lastupdated: 2023-01
-    :accuratefor: 0.9.57
+    :lastupdated: 2023-10
+    :accuratefor: 0.9.59
 
 .. contents::
 
@@ -34,6 +34,8 @@ Java I2P version in which they were implemented.
 ==============  ================================================================
 Router Version  Streaming Features
 ==============  ================================================================
+   0.9.58       Bob's hash in NACKs field of SYN packet
+
    0.9.39       OFFLINE_SIGNATURE option
 
    0.9.36       I2CP protocol number enforced
@@ -114,11 +116,15 @@ Framing is provided by the lower layers - I2CP and I2NP.
                 below.
 
   NACK count :: 1 byte `Integer`
-                The number of 4-byte NACKs in the next field
+                The number of 4-byte NACKs in the next field,
+                or 8 when used together with SYNCHRONIZE for replay prevention
+                as of 0.9.58; see below.
 
   NACKs :: $nc * 4 byte `Integer`s
            Sequence numbers less than ackThrough that are not yet received. Two
            NACKs of a packet is a request for a 'fast retransmit' of that packet.
+           Also used together with SYNCHRONIZE for replay prevention
+           as of 0.9.58; see below.
 
   resendDelay :: 1 byte `Integer`
                  How long is the creator of this packet going to wait before
@@ -243,6 +249,39 @@ in the option.
   If more option fields are defined in the future, they must be accounted for.
 
 
+
+Replay prevention
+-----------------
+
+To prevent Bob from using a replay attack by storing a valid signed SYNCHRONIZE packet
+received from Alice and later sending it to a victim Charlie,
+Alice must include Bob's destination hash in the SYNCHRONIZE packet as follows:
+
+.. raw:: html
+
+  {% highlight lang='dataspec' %}
+Set NACK count field to 8
+Set the NACKs field to Bob's 32-byte destination hash
+
+{% endhighlight %}
+
+Upon reception of a SYNCHRONIZE, if the NACK count field is 8,
+Bob must interpret the NACKs field as a 32-byte destination hash,
+and must verify that it matches his destination hash.
+He must also verify the signature of the packet as usual,
+as that covers the entire packet including the NACK count and NACKs fields.
+If the NACK count is 8 and the NACKs field does not match,
+Bob must drop the packet.
+
+This is required for versions 0.9.58 and higher.
+This is backward-compatible with older versions,
+because NACKs are not expected in a SYNCHRONIZE packet.
+Destinations do not and cannot know what version the other end is running.
+
+No change is necessary for the SYNCHRONIZE ACK packet sent from Bob to Alice;
+do not include NACKs in that packet.
+
+
 References
 ==========