diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml
index 4d8d4947daa5ca627c146779e91769e4b104dc5d..1721a9b9c33336865a5f90427810639c8c06de82 100644
--- a/.gitlab/pipeline/zombienet/polkadot.yml
+++ b/.gitlab/pipeline/zombienet/polkadot.yml
@@ -112,14 +112,6 @@ zombienet-polkadot-functional-0004-parachains-disputes-garbage-candidate:
       --local-dir="${LOCAL_DIR}/functional"
       --test="0004-parachains-garbage-candidate.zndsl"
 
-.zombienet-polkadot-functional-0005-parachains-disputes-past-session:
-  extends:
-    - .zombienet-polkadot-common
-  script:
-    - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh
-      --local-dir="${LOCAL_DIR}/functional"
-      --test="0005-parachains-disputes-past-session.zndsl"
-
 zombienet-polkadot-functional-0006-parachains-max-tranche0:
   extends:
     - .zombienet-polkadot-common
@@ -188,7 +180,7 @@ zombienet-polkadot-functional-0015-coretime-shared-core:
   extends:
     - .zombienet-polkadot-common
   before_script:
-    - !reference [ .zombienet-polkadot-common, before_script ]
+    - !reference [.zombienet-polkadot-common, before_script]
     - cp --remove-destination ${LOCAL_DIR}/assign-core.js ${LOCAL_DIR}/functional
   script:
     - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh
@@ -207,7 +199,7 @@ zombienet-polkadot-functional-0018-shared-core-idle-parachain:
   extends:
     - .zombienet-polkadot-common
   before_script:
-    - !reference [ .zombienet-polkadot-common, before_script ]
+    - !reference [.zombienet-polkadot-common, before_script]
     - cp --remove-destination ${LOCAL_DIR}/assign-core.js ${LOCAL_DIR}/functional
   script:
     - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh
@@ -218,7 +210,7 @@ zombienet-polkadot-functional-0019-coretime-collation-fetching-fairness:
   extends:
     - .zombienet-polkadot-common
   before_script:
-    - !reference [ .zombienet-polkadot-common, before_script ]
+    - !reference [.zombienet-polkadot-common, before_script]
     - cp --remove-destination ${LOCAL_DIR}/assign-core.js ${LOCAL_DIR}/functional
   script:
     - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh
@@ -354,7 +346,7 @@ zombienet-polkadot-malus-0001-dispute-valid:
     - job: build-polkadot-zombienet-tests
       artifacts: true
   before_script:
-    - !reference [ ".zombienet-polkadot-common", "before_script" ]
+    - !reference [".zombienet-polkadot-common", "before_script"]
     - export POLKADOT_IMAGE="${ZOMBIENET_INTEGRATION_TEST_IMAGE}"
   script:
     # we want to use `--no-capture` in zombienet tests.
@@ -369,7 +361,7 @@ zombienet-polkadot-elastic-scaling-slot-based-3cores:
     - job: build-polkadot-zombienet-tests
       artifacts: true
   before_script:
-    - !reference [ ".zombienet-polkadot-common", "before_script" ]
+    - !reference [".zombienet-polkadot-common", "before_script"]
     - export POLKADOT_IMAGE="${ZOMBIENET_INTEGRATION_TEST_IMAGE}"
     - export CUMULUS_IMAGE="docker.io/paritypr/test-parachain:${PIPELINE_IMAGE_TAG}"
     - export X_INFRA_INSTANCE=spot # use spot by default
@@ -386,7 +378,7 @@ zombienet-polkadot-elastic-scaling-slot-based-12cores:
     - job: build-polkadot-zombienet-tests
       artifacts: true
   before_script:
-    - !reference [ ".zombienet-polkadot-common", "before_script" ]
+    - !reference [".zombienet-polkadot-common", "before_script"]
     - export POLKADOT_IMAGE="${ZOMBIENET_INTEGRATION_TEST_IMAGE}"
     - export CUMULUS_IMAGE="docker.io/paritypr/test-parachain:${PIPELINE_IMAGE_TAG}"
     - export X_INFRA_INSTANCE=spot # use spot by default
@@ -403,7 +395,7 @@ zombienet-polkadot-elastic-scaling-doesnt-break-parachains:
     - job: build-polkadot-zombienet-tests
       artifacts: true
   before_script:
-    - !reference [ ".zombienet-polkadot-common", "before_script" ]
+    - !reference [".zombienet-polkadot-common", "before_script"]
     - export POLKADOT_IMAGE="${ZOMBIENET_INTEGRATION_TEST_IMAGE}"
     - export X_INFRA_INSTANCE=spot # use spot by default
   variables:
@@ -421,7 +413,7 @@ zombienet-polkadot-elastic-scaling-basic-3cores:
     - job: build-polkadot-zombienet-tests
       artifacts: true
   before_script:
-    - !reference [ ".zombienet-polkadot-common", "before_script" ]
+    - !reference [".zombienet-polkadot-common", "before_script"]
     - export POLKADOT_IMAGE="${ZOMBIENET_INTEGRATION_TEST_IMAGE}"
     - export CUMULUS_IMAGE="${COL_IMAGE}"
     - export X_INFRA_INSTANCE=spot # use spot by default
@@ -438,7 +430,7 @@ zombienet-polkadot-functional-sync-backing:
     - job: build-polkadot-zombienet-tests
       artifacts: true
   before_script:
-    - !reference [ ".zombienet-polkadot-common", "before_script" ]
+    - !reference [".zombienet-polkadot-common", "before_script"]
     - export POLKADOT_IMAGE="${ZOMBIENET_INTEGRATION_TEST_IMAGE}"
     # Hardcoded to an old polkadot-parachain image, pre async backing.
     - export CUMULUS_IMAGE="docker.io/paritypr/polkadot-parachain-debug:master-99623e62"
@@ -456,7 +448,7 @@ zombienet-polkadot-functional-async-backing-6-seconds-rate:
     - job: build-polkadot-zombienet-tests
       artifacts: true
   before_script:
-    - !reference [ ".zombienet-polkadot-common", "before_script" ]
+    - !reference [".zombienet-polkadot-common", "before_script"]
     - export POLKADOT_IMAGE="${ZOMBIENET_INTEGRATION_TEST_IMAGE}"
     - export X_INFRA_INSTANCE=spot # use spot by default
   script:
@@ -472,7 +464,7 @@ zombienet-polkadot-functional-duplicate-collations:
     - job: build-polkadot-zombienet-tests
       artifacts: true
   before_script:
-    - !reference [ ".zombienet-polkadot-common", "before_script" ]
+    - !reference [".zombienet-polkadot-common", "before_script"]
     - export POLKADOT_IMAGE="${ZOMBIENET_INTEGRATION_TEST_IMAGE}"
     - export X_INFRA_INSTANCE=spot # use spot by default
   script:
@@ -480,3 +472,19 @@ zombienet-polkadot-functional-duplicate-collations:
     - unset NEXTEST_FAILURE_OUTPUT
     - unset NEXTEST_SUCCESS_OUTPUT
     - cargo nextest run --archive-file ./artifacts/polkadot-zombienet-tests.tar.zst --no-capture -- functional::duplicate_collations::duplicate_collations_test
+
+zombienet-polkadot-disputes-slashing:
+  extends:
+    - .zombienet-polkadot-common
+  needs:
+    - job: build-polkadot-zombienet-tests
+      artifacts: true
+  before_script:
+    - !reference [".zombienet-polkadot-common", "before_script"]
+    - export POLKADOT_IMAGE="${ZOMBIENET_INTEGRATION_TEST_IMAGE}"
+    - export X_INFRA_INSTANCE=spot # use spot by default
+  script:
+    # we want to use `--no-capture` in zombienet tests.
+    - unset NEXTEST_FAILURE_OUTPUT
+    - unset NEXTEST_SUCCESS_OUTPUT
+    - cargo nextest run --archive-file ./artifacts/polkadot-zombienet-tests.tar.zst --no-capture -- disabling::slashing
diff --git a/Cargo.lock b/Cargo.lock
index 25e7e194aeb4eb235f4d8faf5b3b3bcf882771da..971acf57678fc2b3a3b3ccde7803dd4486db7984 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -8707,7 +8707,7 @@ dependencies = [
  "httpdate",
  "itoa",
  "pin-project-lite",
- "socket2 0.5.7",
+ "socket2 0.4.9",
  "tokio",
  "tower-service",
  "tracing",
@@ -16408,7 +16408,7 @@ checksum = "4e69bf016dc406eff7d53a7d3f7cf1c2e72c82b9088aac1118591e36dd2cd3e9"
 dependencies = [
  "bitcoin_hashes 0.13.0",
  "rand",
- "rand_core 0.6.4",
+ "rand_core 0.5.1",
  "serde",
  "unicode-normalization",
 ]
@@ -19870,6 +19870,7 @@ dependencies = [
  "subxt",
  "subxt-signer",
  "tokio",
+ "tokio-util",
  "zombienet-sdk",
 ]
 
@@ -20664,7 +20665,7 @@ checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302"
 dependencies = [
  "bytes",
  "heck 0.5.0",
- "itertools 0.13.0",
+ "itertools 0.12.1",
  "log",
  "multimap",
  "once_cell",
@@ -20710,7 +20711,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac"
 dependencies = [
  "anyhow",
- "itertools 0.13.0",
+ "itertools 0.12.1",
  "proc-macro2 1.0.86",
  "quote 1.0.37",
  "syn 2.0.87",
@@ -26369,6 +26370,53 @@ dependencies = [
  "zeroize",
 ]
 
+[[package]]
+name = "sp-core"
+version = "35.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4532774405a712a366a98080cbb4daa28c38ddff0ec595902ad6ee6a78a809f8"
+dependencies = [
+ "array-bytes",
+ "bitflags 1.3.2",
+ "blake2 0.10.6",
+ "bounded-collections",
+ "bs58",
+ "dyn-clonable",
+ "ed25519-zebra 4.0.3",
+ "futures",
+ "hash-db",
+ "hash256-std-hasher",
+ "impl-serde 0.5.0",
+ "itertools 0.11.0",
+ "k256",
+ "libsecp256k1",
+ "log",
+ "merlin",
+ "parity-bip39",
+ "parity-scale-codec",
+ "parking_lot 0.12.3",
+ "paste",
+ "primitive-types 0.13.1",
+ "rand",
+ "scale-info",
+ "schnorrkel 0.11.4",
+ "secp256k1 0.28.2",
+ "secrecy 0.8.0",
+ "serde",
+ "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sp-externalities 0.30.0",
+ "sp-runtime-interface 29.0.0",
+ "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sp-storage 22.0.0",
+ "ss58-registry",
+ "substrate-bip39 0.6.0",
+ "thiserror",
+ "tracing",
+ "w3f-bls",
+ "zeroize",
+]
+
 [[package]]
 name = "sp-core-fuzz"
 version = "0.0.0"
@@ -26590,6 +26638,17 @@ dependencies = [
  "sp-storage 21.0.0",
 ]
 
+[[package]]
+name = "sp-externalities"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30cbf059dce180a8bf8b6c8b08b6290fa3d1c7f069a60f1df038ab5dd5fc0ba6"
+dependencies = [
+ "environmental",
+ "parity-scale-codec",
+ "sp-storage 22.0.0",
+]
+
 [[package]]
 name = "sp-genesis-builder"
 version = "0.8.0"
@@ -27192,6 +27251,26 @@ dependencies = [
  "static_assertions",
 ]
 
+[[package]]
+name = "sp-runtime-interface"
+version = "29.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51e83d940449837a8b2a01b4d877dd22d896fd14d3d3ade875787982da994a33"
+dependencies = [
+ "bytes",
+ "impl-trait-for-tuples",
+ "parity-scale-codec",
+ "polkavm-derive 0.9.1",
+ "primitive-types 0.13.1",
+ "sp-externalities 0.30.0",
+ "sp-runtime-interface-proc-macro 18.0.0",
+ "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sp-storage 22.0.0",
+ "sp-tracing 17.0.1",
+ "sp-wasm-interface 21.0.1",
+ "static_assertions",
+]
+
 [[package]]
 name = "sp-runtime-interface-proc-macro"
 version = "11.0.0"
@@ -27522,6 +27601,19 @@ dependencies = [
  "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "sp-storage"
+version = "22.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee3b70ca340e41cde9d2e069d354508a6e37a6573d66f7cc38f11549002f64ec"
+dependencies = [
+ "impl-serde 0.5.0",
+ "parity-scale-codec",
+ "ref-cast",
+ "serde",
+ "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "sp-test-primitives"
 version = "2.0.0"
@@ -32191,9 +32283,9 @@ dependencies = [
 
 [[package]]
 name = "zombienet-configuration"
-version = "0.2.20"
+version = "0.2.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ced2fca1322821431f03d06dcf2ea74d3a7369760b6c587b372de6eada3ce43"
+checksum = "03caa9f916aedb12e8443521c87604fe54fbde163a58018780108d86761310dc"
 dependencies = [
  "anyhow",
  "lazy_static",
@@ -32205,15 +32297,16 @@ dependencies = [
  "thiserror",
  "tokio",
  "toml 0.8.19",
+ "tracing",
  "url",
  "zombienet-support",
 ]
 
 [[package]]
 name = "zombienet-orchestrator"
-version = "0.2.20"
+version = "0.2.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86ecd17133c3129547b6472591b5e58d4aee1fc63c965a3418fd56d33a8a4e82"
+checksum = "8330f46e4584a306ed567702307a697b8a2771681233548263f5bc3f639fcdec"
 dependencies = [
  "anyhow",
  "async-trait",
@@ -32229,7 +32322,7 @@ dependencies = [
  "serde",
  "serde_json",
  "sha2 0.10.8",
- "sp-core 34.0.0",
+ "sp-core 35.0.0",
  "subxt",
  "subxt-signer",
  "thiserror",
@@ -32244,9 +32337,9 @@ dependencies = [
 
 [[package]]
 name = "zombienet-prom-metrics-parser"
-version = "0.2.20"
+version = "0.2.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23702db0819a050c8a0130a769b105695137020a64207b4597aa021f06924552"
+checksum = "8a52a796a1521cf6420cc6384eac9ef25a146d453b568969774af643f3ecdc97"
 dependencies = [
  "pest",
  "pest_derive",
@@ -32255,9 +32348,9 @@ dependencies = [
 
 [[package]]
 name = "zombienet-provider"
-version = "0.2.20"
+version = "0.2.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83e903843c62cd811e7730ccc618dcd14444d20e8aadfcd7d7561c7b47d8f984"
+checksum = "7121ed12016baf318afdcaa96e59d134a3299f40ad5cb67fa6e8ae561db97d26"
 dependencies = [
  "anyhow",
  "async-trait",
@@ -32286,9 +32379,9 @@ dependencies = [
 
 [[package]]
 name = "zombienet-sdk"
-version = "0.2.20"
+version = "0.2.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e457b12c8fdc7003c12dd56855da09812ac11dd232e4ec01acccb2899fe05e44"
+checksum = "732a89935216d4cde1e538075af2f9e0e974e49895004694ab113c7040725ae5"
 dependencies = [
  "async-trait",
  "futures",
@@ -32304,9 +32397,9 @@ dependencies = [
 
 [[package]]
 name = "zombienet-support"
-version = "0.2.20"
+version = "0.2.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43547d65b19a92cf0ee44380239d82ef345e7d26f7b04b9e0ecf48496af6346b"
+checksum = "1f0c215aa994335125b75f9ad7c227a4ae6c281c074a6e6a42800f2fdfa59c8b"
 dependencies = [
  "anyhow",
  "async-trait",
diff --git a/polkadot/zombienet-sdk-tests/Cargo.toml b/polkadot/zombienet-sdk-tests/Cargo.toml
index ba7517ddce6631df2b56f3c9632c3ec7f55c5b6f..69a1d0375aabcc9d3eae49a48091ed9c06767b1b 100644
--- a/polkadot/zombienet-sdk-tests/Cargo.toml
+++ b/polkadot/zombienet-sdk-tests/Cargo.toml
@@ -18,6 +18,7 @@ serde_json = { workspace = true }
 subxt = { workspace = true, features = ["substrate-compat"] }
 subxt-signer = { workspace = true }
 tokio = { workspace = true, features = ["rt-multi-thread"] }
+tokio-util = { workspace = true, features = ["time"] }
 zombienet-sdk = { workspace = true }
 
 [features]
diff --git a/polkadot/zombienet-sdk-tests/tests/disabling/mod.rs b/polkadot/zombienet-sdk-tests/tests/disabling/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..c1806e451bf65135f234c08e10d18636f4b9b1ff
--- /dev/null
+++ b/polkadot/zombienet-sdk-tests/tests/disabling/mod.rs
@@ -0,0 +1,4 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+mod slashing;
diff --git a/polkadot/zombienet-sdk-tests/tests/disabling/slashing.rs b/polkadot/zombienet-sdk-tests/tests/disabling/slashing.rs
new file mode 100644
index 0000000000000000000000000000000000000000..2983ace629c6dfed340bcd0463fc22db8f96c273
--- /dev/null
+++ b/polkadot/zombienet-sdk-tests/tests/disabling/slashing.rs
@@ -0,0 +1,171 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+//! Test past-session slashing when a malicious validator backs an invalid
+//! candidate and a dispute concluding in a future session. We achieve that by
+//! making some of the honest nodes go offline.
+
+use anyhow::anyhow;
+
+use crate::helpers::{assert_blocks_are_being_finalized, assert_para_throughput};
+use polkadot_primitives::{BlockNumber, CandidateHash, DisputeState, Id as ParaId, SessionIndex};
+use serde_json::json;
+use subxt::{OnlineClient, PolkadotConfig};
+use tokio::time::Duration;
+use tokio_util::time::FutureExt;
+use zombienet_sdk::NetworkConfigBuilder;
+
+#[tokio::test(flavor = "multi_thread")]
+async fn dispute_past_session_slashing() -> Result<(), anyhow::Error> {
+	let _ = env_logger::try_init_from_env(
+		env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
+	);
+
+	let images = zombienet_sdk::environment::get_images_from_env();
+
+	let config = NetworkConfigBuilder::new()
+		.with_relaychain(|r| {
+			r.with_chain("westend-local")
+				.with_default_command("polkadot")
+				.with_default_image(images.polkadot.as_str())
+				.with_default_args(vec![
+					"--no-hardware-benchmarks".into(),
+					"-lparachain=debug,runtime=debug".into(),
+				])
+				.with_genesis_overrides(json!({
+					"patch": {
+						"configuration": {
+							"config": {
+								"scheduler_params": {
+									"group_rotation_frequency": 3,
+									"max_validators_per_core": 1,
+								},
+								"needed_approvals": 2
+							}
+						}
+					}
+				}))
+				.with_node(|node| node.with_name("honest-validator-0"))
+				.with_node(|node| node.with_name("honest-validator-1"))
+				.with_node(|node| node.with_name("honest-flaky-validator-0"))
+				.with_node(|node| {
+					node.with_name("malicious-backer")
+						.with_image(
+							std::env::var("MALUS_IMAGE")
+								.unwrap_or("docker.io/paritypr/malus".to_string())
+								.as_str(),
+						)
+						.with_command("malus")
+						.with_subcommand("suggest-garbage-candidate")
+						.with_args(vec![
+							"--no-hardware-benchmarks".into(),
+							"--insecure-validator-i-know-what-i-do".into(),
+							"-lMALUS=trace,parachain=debug".into(),
+						])
+				})
+		})
+		.with_parachain(|p| {
+			p.with_id(1337)
+				.with_default_command("polkadot-parachain")
+				.with_default_image(images.cumulus.as_str())
+				.with_default_args(vec!["-lparachain=debug".into()])
+				.with_collator(|n| n.with_name("collator-1337"))
+		})
+		.build()
+		.map_err(|e| {
+			let errs = e.into_iter().map(|e| e.to_string()).collect::<Vec<_>>().join(" ");
+			anyhow!("config errs: {errs}")
+		})?;
+
+	let spawn_fn = zombienet_sdk::environment::get_spawn_fn();
+	let network = spawn_fn(config).await?;
+
+	let malus = network.get_node("malicious-backer")?;
+	malus.pause().await?;
+
+	let honest = network.get_node("honest-validator-0")?;
+	let relay_client: OnlineClient<PolkadotConfig> = honest.wait_client().await?;
+
+	// Wait for some para blocks being produced
+	assert_para_throughput(&relay_client, 20, [(ParaId::from(1337), 10..20)].into_iter().collect())
+		.await?;
+
+	// Let's initiate a dispute
+	malus.resume().await?;
+	// Pause flaky nodes, so a dispute doesn't conclude
+	let flaky_0 = network.get_node("honest-flaky-validator-0")?;
+	flaky_0.pause().await?;
+
+	// wait for a dispute to be initiated
+	let mut best_blocks = relay_client.blocks().subscribe_best().await?;
+	let mut dispute_session: u32 = u32::MAX;
+	while let Some(block) = best_blocks.next().await {
+		// NOTE: we can't use `at_latest` here, because it will utilize latest *finalized* block
+		// and finality is stalled...
+		let disputes = relay_client
+			.runtime_api()
+			.at(block?.hash())
+			.call_raw::<Vec<(SessionIndex, CandidateHash, DisputeState<BlockNumber>)>>(
+				"ParachainHost_disputes",
+				None,
+			)
+			.await?;
+		if let Some((session, _, _)) = disputes.first() {
+			dispute_session = *session;
+			break
+		}
+	}
+
+	assert_ne!(dispute_session, u32::MAX, "dispute should be initiated");
+	log::info!("Dispute initiated, now waiting for a new session");
+
+	while let Some(block) = best_blocks.next().await {
+		let current_session = relay_client
+			.runtime_api()
+			.at(block?.hash())
+			.call_raw::<SessionIndex>("ParachainHost_session_index_for_child", None)
+			.await?;
+		if current_session > dispute_session {
+			break
+		}
+	}
+
+	// We don't need malus anymore
+	malus.pause().await?;
+
+	let concluded_dispute_metric =
+		"polkadot_parachain_candidate_dispute_concluded{validity=\"invalid\"}";
+
+	let timeout_secs: u64 = 120;
+	// with one offline honest node, dispute should not conclude
+	honest
+		.wait_metric_with_timeout(concluded_dispute_metric, |d| d < 1.0, timeout_secs)
+		.await?;
+
+	// Now resume flaky validators
+	log::info!("Resuming flaky nodes - dispute should conclude");
+	flaky_0.resume().await?;
+
+	honest
+		.wait_metric_with_timeout(concluded_dispute_metric, |d| d > 0.0, timeout_secs)
+		.await?;
+	log::info!("A dispute has concluded");
+
+	honest
+		.wait_log_line_count_with_timeout(
+			"*Successfully reported pending slash*",
+			true,
+			1,
+			timeout_secs,
+		)
+		.await?;
+
+	assert_blocks_are_being_finalized(&relay_client)
+		.timeout(Duration::from_secs(400)) // enough for the aggression to kick in
+		.await?
+		.unwrap();
+
+	log::info!("Test finished successfully");
+
+	Ok(())
+}
diff --git a/polkadot/zombienet-sdk-tests/tests/helpers/mod.rs b/polkadot/zombienet-sdk-tests/tests/helpers/mod.rs
index 470345ca4d621fb87100b9c783098d288b22cdb6..2b1de28f7b64169f6642fdd26c8719058781b1d1 100644
--- a/polkadot/zombienet-sdk-tests/tests/helpers/mod.rs
+++ b/polkadot/zombienet-sdk-tests/tests/helpers/mod.rs
@@ -4,6 +4,7 @@
 use polkadot_primitives::Id as ParaId;
 use std::{collections::HashMap, ops::Range};
 use subxt::{OnlineClient, PolkadotConfig};
+use tokio::time::{sleep, Duration};
 
 #[subxt::subxt(runtime_metadata_path = "metadata-files/rococo-local.scale")]
 pub mod rococo {}
@@ -79,3 +80,25 @@ pub async fn assert_finalized_block_height(
 	}
 	Ok(())
 }
+
+/// Assert that finality has not stalled.
+pub async fn assert_blocks_are_being_finalized(
+	client: &OnlineClient<PolkadotConfig>,
+) -> Result<(), anyhow::Error> {
+	let mut finalized_blocks = client.blocks().subscribe_finalized().await?;
+	let first_measurement = finalized_blocks
+		.next()
+		.await
+		.ok_or(anyhow::anyhow!("Can't get finalized block from stream"))??
+		.number();
+	sleep(Duration::from_secs(12)).await;
+	let second_measurement = finalized_blocks
+		.next()
+		.await
+		.ok_or(anyhow::anyhow!("Can't get finalized block from stream"))??
+		.number();
+
+	assert!(second_measurement > first_measurement);
+
+	Ok(())
+}
diff --git a/polkadot/zombienet-sdk-tests/tests/lib.rs b/polkadot/zombienet-sdk-tests/tests/lib.rs
index 9feb9775e450e0149b0e357c4861a62beff5732e..d8548b9a23ea8f20aee371fae22625845443d689 100644
--- a/polkadot/zombienet-sdk-tests/tests/lib.rs
+++ b/polkadot/zombienet-sdk-tests/tests/lib.rs
@@ -4,6 +4,8 @@
 #[cfg(feature = "zombie-metadata")]
 mod helpers;
 
+#[cfg(feature = "zombie-metadata")]
+mod disabling;
 #[cfg(feature = "zombie-metadata")]
 mod elastic_scaling;
 #[cfg(feature = "zombie-metadata")]
diff --git a/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.toml b/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.toml
deleted file mode 100644
index a3bbc82e74ba6d9d5c442742afc2dd18f31c7305..0000000000000000000000000000000000000000
--- a/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.toml
+++ /dev/null
@@ -1,47 +0,0 @@
-[settings]
-timeout = 1000
-bootnode = true
-
-[relaychain.genesis.runtimeGenesis.patch.configuration.config]
-  needed_approvals = 2
-
-[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params]
-  max_validators_per_core = 1
-  group_rotation_frequency = 2
-
-[relaychain]
-default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}"
-chain = "westend-local" # using westend-local to enable slashing
-default_command = "polkadot"
-
-[relaychain.default_resources]
-limits = { memory = "4G", cpu = "2" }
-requests = { memory = "2G", cpu = "1" }
-
-  [[relaychain.node_groups]]
-  name = "honest-flaky-validator"
-  invulnerable = true # it will go offline, we don't want to disable it
-  count = 2
-  args = ["-lparachain=debug"]
-
-  [[relaychain.node_groups]]
-  name = "honest-validator"
-  count = 1
-  args = ["-lparachain=debug"]
-
-  [[relaychain.node_groups]]
-  image = "{{MALUS_IMAGE}}"
-  name = "malus-validator"
-  command = "malus suggest-garbage-candidate"
-  args = ["-lMALUS=trace"]
-  count = 1
-
-[[parachains]]
-id = 1000
-cumulus_based = true
-
-  [parachains.collator]
-  name = "alice"
-  command = "polkadot-parachain"
-  image = "{{CUMULUS_IMAGE}}"
-  args = ["-lparachain=debug"]
diff --git a/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.zndsl b/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.zndsl
deleted file mode 100644
index d92820391d53d85fb549878e621000829f570452..0000000000000000000000000000000000000000
--- a/polkadot/zombienet_tests/functional/0005-parachains-disputes-past-session.zndsl
+++ /dev/null
@@ -1,57 +0,0 @@
-Description: Past-session dispute slashing
-Network: ./0005-parachains-disputes-past-session.toml
-Creds: config
-
-# Ensure nodes are up and running
-honest-flaky-validator: reports node_roles is 4
-
-# Stop issuing disputes for now
-malus-validator: pause
-
-# Ensure parachain is registered
-honest-validator: parachain 1000 is registered within 100 seconds
-
-# Ensure parachain made progress
-honest-validator: parachain 1000 block height is at least 1 within 300 seconds
-
-# Start issuing disputes
-malus-validator: resume
-
-# Wait for malus to back garbage candidate
-malus-validator: log line matches "Suggesting malicious candidate" within 200 seconds
-
-# Pause first flaky node
-# Availability will continue with 3/4 nodes online (incl. malus)
-honest-flaky-validator-0: pause
-
-# Wait for the dispute
-honest-flaky-validator-1: reports parachain_candidate_disputes_total is at least 1 within 60 seconds
-
-# Pause second flaky node so that we do not revert blocks due to f+1 invalid votes
-# Availability and finality will stop
-honest-flaky-validator-1: pause
-
-# Wait for 1 full session to pass after the last unconcluded dispute.
-#
-# TODO: replace with assertion for "New session detected" in logs. I think that
-# would match on previous log lines, so we may need to programmatically wait for
-# a specific session, requiring zombienet v2.
-sleep 110 seconds
-
-# Now resume flaky validators
-honest-flaky-validator: resume
-
-# Stop issuing disputes
-malus-validator: pause
-
-# Disputes should start concluding now
-honest-validator: reports polkadot_parachain_candidate_dispute_concluded{validity="invalid"} is at least 1 within 200 seconds
-
-# Disputes should always end as "invalid"
-honest-validator: reports polkadot_parachain_candidate_dispute_concluded{validity="valid"} is 0
-
-# Check an unsigned extrinsic is submitted
-honest-validator: log line contains "Successfully reported pending slash" within 180 seconds
-
-# Finality should not lag after dispute resolution
-honest-validator: reports block height minus finalised block is lower than 8 within 100 seconds