diff --git a/man/systemd-imdsd@.service.xml b/man/systemd-imdsd@.service.xml
index d4007b7c87f..76d94dd68ac 100644
--- a/man/systemd-imdsd@.service.xml
+++ b/man/systemd-imdsd@.service.xml
@@ -71,7 +71,10 @@
access. Unless set to off early boot networking is enabled, ensuring that the
IMDS endpoint can be reached. If set to locked direct access to
the IMDS endpoint by regular unprivileged processes is disabled via a "prohibit" route, so that any
- access must be done through systemd-imdsd@.service or its associated tools. If
+ access must be done through systemd-imdsd@.service or its associated tools.
+ This also turns off IPv4 reverse path filtering on all Ethernet links that the early boot networking
+ configures (see IPv4ReversePathFilter= in
+ systemd.network5). If
set to unlocked (the default) this "prohibit" route is not created, and regular unprivileged
processes can directly contact IMDS.
diff --git a/src/imds/imdsd.c b/src/imds/imdsd.c
index 14860005cf3..4c8bb60afb0 100644
--- a/src/imds/imdsd.c
+++ b/src/imds/imdsd.c
@@ -1686,8 +1686,16 @@ static int setup_network(void) {
"\n"
"[Network]\n"
"DHCP=yes\n"
- "LinkLocalAddressing=ipv6\n"
- "\n"
+ "LinkLocalAddressing=ipv6\n", f);
+
+ /* IMDS's replies to imdsd carry no firewall mark. Reverse path filtering would check their source
+ * address against the main table, find the prohibit route below, and drop them. IPv6 has no
+ * reverse path filter. */
+ if (arg_network_mode != IMDS_NETWORK_UNLOCKED && in4_addr_is_set(&arg_address_ipv4))
+ fputs("# Reverse path filtering would drop IMDS's replies due to the prohibit route\n"
+ "IPv4ReversePathFilter=no\n", f);
+
+ fputs("\n"
"[DHCP]\n"
"UseTimezone=yes\n"
"UseHostname=yes\n"
diff --git a/test/units/TEST-74-AUX-UTILS.imds.sh b/test/units/TEST-74-AUX-UTILS.imds.sh
index 52719355e3d..5046b38eda8 100755
--- a/test/units/TEST-74-AUX-UTILS.imds.sh
+++ b/test/units/TEST-74-AUX-UTILS.imds.sh
@@ -15,6 +15,10 @@ fi
at_exit() {
set +e
systemctl stop fake-imds systemd-imdsd.socket
+ # Unmanage the link before removing it, so that networkd also removes its prohibit route and rule
+ rm -rf /run/systemd/network/85-imds-early.network /run/systemd/network/85-imds-early.network.d \
+ /run/systemd/resolve/static.d/imds-endpoint.rr
+ networkctl reload
ip link del veth-imds
ip netns del imds
rm -f /run/credstore/firstboot.hostname /run/credstore/acredtest /run/systemd/system/systemd-imdsd@.service.d/50-env.conf /run/fake-imds-flaky
@@ -156,3 +160,62 @@ systemctl daemon-reload
(! /usr/lib/systemd/systemd-imds --import 2>"$WORK_DIR/import.err")
cat "$WORK_DIR/import.err"
grep -F "Failed to parse IP address 'piff'" "$WORK_DIR/import.err" >/dev/null
+
+# Lock down IMDS access to imdsd (systemd.imds.network=locked), with the networking which
+# "systemd-imdsd --setup-network" generates and networkd applies. This needs IMDS at its usual link-local
+# address, as the prohibit route covers only that.
+ip -n imds addr add 169.254.169.254/32 dev veth-imds-peer
+IMDSD_LOCKED=("${IMDSD[@]}" --data-url=http://169.254.169.254:8088 --address-ipv4=169.254.169.254)
+
+# Unlocked mode has no prohibit route, and keeps reverse path filtering
+SYSTEMD_PROC_CMDLINE=systemd.imds.network=unlocked "${IMDSD[@]}" --address-ipv4=169.254.169.254 --setup-network
+cat /run/systemd/network/85-imds-early.network
+(! grep -F -e "Type=prohibit" -e "IPv4ReversePathFilter=" /run/systemd/network/85-imds-early.network >/dev/null)
+
+SYSTEMD_PROC_CMDLINE=systemd.imds.network=locked "${IMDSD_LOCKED[@]}" --setup-network
+cat /run/systemd/network/85-imds-early.network
+grep -Fx "Type=prohibit" /run/systemd/network/85-imds-early.network >/dev/null
+grep -Fx "IPv4ReversePathFilter=no" /run/systemd/network/85-imds-early.network >/dev/null
+
+# The generated .network matches physical Ethernet links only, and asks for DHCP. Apply it to the veth
+# instead, with its static address.
+mkdir -p /run/systemd/network/85-imds-early.network.d
+cat >/run/systemd/network/85-imds-early.network.d/50-test.conf < DROPS ))
+fi
+
+# Everybody else gets blocked
+(! bash -c 'echo >/dev/tcp/169.254.169.254/8088' 2>"$WORK_DIR/connect.err")
+cat "$WORK_DIR/connect.err"
+grep -F "Permission denied" "$WORK_DIR/connect.err" >/dev/null