diff --git a/UnitTest1/unittest1.cpp b/UnitTest1/unittest1.cpp
index 6320f98577d96465125d97ce8be57e6e384be5a0..b4a9fcb541c163b4a773501b4c0ccce29a8d69e0 100644
--- a/UnitTest1/unittest1.cpp
+++ b/UnitTest1/unittest1.cpp
@@ -748,6 +748,13 @@ namespace UnitTest1
 
             Assert::AreEqual(ret, 0);
         }
+
+        TEST_METHOD(migration_stress)
+        {
+            int ret = migration_stress_test();
+
+            Assert::AreEqual(ret, 0);
+        }
         
         TEST_METHOD(stress)
         {
diff --git a/picoquic_t/picoquic_t.c b/picoquic_t/picoquic_t.c
index 602ad0662caad64421743bd3bcc41d769a085fd9..755ce65e1c66500827b597838648aa2764bf79c7 100644
--- a/picoquic_t/picoquic_t.c
+++ b/picoquic_t/picoquic_t.c
@@ -143,6 +143,7 @@ static const picoquic_test_def_t test_table[] = {
     { "stream_id_max", stream_id_max_test },
     { "padding_test", padding_test },
     { "packet_trace", packet_trace_test },
+    { "migration_stress", migration_stress_test },
     { "stress", stress_test },
     { "fuzz", fuzz_test },
     { "fuzz_initial", fuzz_initial_test}
diff --git a/picoquictest/picoquictest.h b/picoquictest/picoquictest.h
index 683d7820ec03732bce644b412b6dc4e657b7fba5..2c733990cb09a9bc4075488510b6a94d47fa1724 100644
--- a/picoquictest/picoquictest.h
+++ b/picoquictest/picoquictest.h
@@ -144,6 +144,7 @@ int stream_id_max_test();
 int stream_id_to_rank_test();
 int padding_test();
 int packet_trace_test();
+int migration_stress_test();
 
 #ifdef __cplusplus
 }
diff --git a/picoquictest/tls_api_test.c b/picoquictest/tls_api_test.c
index 5990b854f694153b00bd6b3402bbd36c03cac112..0488d13943fc3b14832c9674343a3bec067ff7d2 100644
--- a/picoquictest/tls_api_test.c
+++ b/picoquictest/tls_api_test.c
@@ -20,6 +20,7 @@
 */
 
 #include "picoquic_internal.h"
+#include "util.h"
 #include "tls_api.h"
 #include "picoquictest_internal.h"
 #ifdef _WINDOWS
@@ -3473,7 +3474,7 @@ int probe_api_test()
         memset(&t6[i].sin6_addr, i, 20);
     }
 
-    /* Set a test conection between client and server */
+    /* Set a test connection between client and server */
     int ret = tls_api_init_ctx(&test_ctx, PICOQUIC_INTERNAL_TEST_VERSION_1,
         PICOQUIC_TEST_SNI, PICOQUIC_TEST_ALPN, &simulated_time, NULL, 0, 0, 0);
 
@@ -3793,6 +3794,152 @@ int migration_test_loss()
     return migration_test_scenario(test_scenario_q_and_r, sizeof(test_scenario_q_and_r), loss_mask);
 }
 
+/* Migration stress test. 
+ * This simulates an attack, during which a man on the side injects fake migration
+ * packets from false addresses. One of the addresses is maintained so that packets sent
+ * to it are natted back to the client.
+ *
+ * The goal of the attack is to verify that the connection resists.
+ */
+
+int migration_stress_test()
+{
+    int nb_trials = 0;
+    const int max_trials = 10000;
+    int nb_inactive = 0;
+    struct sockaddr_in hack_address;
+    struct sockaddr_in hack_address_random;
+    uint64_t loss_mask_data = 0;
+    uint64_t simulated_time = 0;
+    uint64_t next_time = 0;
+    uint64_t loss_mask = 0;
+    uint64_t last_inject_time = 0;
+    uint64_t random_context = 0xBABAC001;
+    picoquic_test_tls_api_ctx_t* test_ctx = NULL;
+    int ret = tls_api_init_ctx(&test_ctx, PICOQUIC_INTERNAL_TEST_VERSION_1,
+        PICOQUIC_TEST_SNI, PICOQUIC_TEST_ALPN, &simulated_time, NULL, 0, 0, 0);
+
+    memcpy(&hack_address, &test_ctx->client_addr, sizeof(struct sockaddr_in));
+    memcpy(&hack_address_random, &test_ctx->client_addr, sizeof(struct sockaddr_in));
+
+    hack_address.sin_port += 1023;
+    
+
+    if (ret == 0 && test_ctx == NULL) {
+        ret = PICOQUIC_ERROR_MEMORY;
+    }
+
+    if (ret == 0) {
+        ret = tls_api_connection_loop(test_ctx, &loss_mask, 0, &simulated_time);
+    }
+
+    /* Prepare to send data */
+    if (ret == 0) {
+        ret = test_api_init_send_recv_scenario(test_ctx, test_scenario_very_long, sizeof(test_scenario_very_long));
+    }
+
+    /* Rewrite the sending loop, so we can add injection of packet copies */
+
+    while (ret == 0 && nb_trials < max_trials && nb_inactive < 256 && TEST_CLIENT_READY && TEST_SERVER_READY) {
+        int was_active = 0;
+
+        nb_trials++;
+
+        ret = tls_api_one_sim_round(test_ctx, &simulated_time, 0, &was_active);
+
+        if (ret < 0)
+        {
+            break;
+        }
+
+        if (was_active) {
+            nb_inactive = 0;
+        }
+        else {
+            nb_inactive++;
+        }
+
+        if (test_ctx->test_finished) {
+            if (picoquic_is_cnx_backlog_empty(test_ctx->cnx_client) && picoquic_is_cnx_backlog_empty(test_ctx->cnx_server)) {
+                break;
+            }
+        }
+
+        /* Packet injection at the server */
+        if (test_ctx->c_to_s_link->last_packet != NULL) {
+            uint64_t server_arrival = test_ctx->c_to_s_link->last_packet->arrival_time;
+
+            if (server_arrival > last_inject_time) {
+                /* 50% chance of packet injection, 25% chances of reusing test address */
+                uint64_t rand100 = picoquic_test_uniform_random(&random_context, 100);
+                last_inject_time = server_arrival;
+                if (rand100 < 50) {
+                    struct sockaddr * bad_address;
+                    if (rand100 < 25) {
+                        bad_address = (struct sockaddr *)&hack_address;
+                    }
+                    else {
+                        hack_address_random.sin_port = (uint16_t)picoquic_test_uniform_random(&random_context, 0x10000);
+                        bad_address = (struct sockaddr *)&hack_address_random;
+                    }
+                    ret = picoquic_incoming_packet(test_ctx->qserver,
+                        test_ctx->c_to_s_link->last_packet->bytes,
+                        (uint32_t)test_ctx->c_to_s_link->last_packet->length,
+                        bad_address,
+                        (struct sockaddr*)&test_ctx->c_to_s_link->last_packet->addr_to, 0,
+                        simulated_time);
+                }
+            }
+        }
+
+        /* Packet reinjection at the client if using the special address */
+        if (test_ctx->s_to_c_link->last_packet != NULL &&
+            picoquic_compare_addr((struct sockaddr *)&hack_address, (struct sockaddr *)&test_ctx->s_to_c_link->last_packet->addr_to) == 0)
+        {
+            picoquic_store_addr(&test_ctx->s_to_c_link->last_packet->addr_to, (struct sockaddr *)&test_ctx->client_addr);
+        }
+    }
+
+    if (ret == 0) {
+        ret = tls_api_attempt_to_close(test_ctx, &simulated_time);
+    }
+
+    if (ret == 0) {
+        if (test_ctx->server_callback.error_detected) {
+            ret = -1;
+        }
+        else if (test_ctx->client_callback.error_detected) {
+            ret = -1;
+        }
+        else {
+            for (size_t i = 0; ret == 0 && i < test_ctx->nb_test_streams; i++) {
+                if (test_ctx->test_stream[i].q_recv_nb != test_ctx->test_stream[i].q_len) {
+                    ret = -1;
+                }
+                else if (test_ctx->test_stream[i].r_recv_nb != test_ctx->test_stream[i].r_len) {
+                    ret = -1;
+                }
+                else if (test_ctx->test_stream[i].q_received == 0 || test_ctx->test_stream[i].r_received == 0) {
+                    ret = -1;
+                }
+            }
+        }
+        if (ret != 0)
+        {
+            DBG_PRINTF("Test scenario verification returns %d\n", ret);
+        }
+    }
+
+    if (test_ctx != NULL) {
+        tls_api_delete_ctx(test_ctx);
+        test_ctx = NULL;
+    }
+
+    return ret;
+}
+
+
+
 /* Connection ID renewal test.
  */