diff --git a/code/game/objects/items/devices/ioncannon_remote.dm b/code/game/objects/items/devices/ioncannon_remote.dm
new file mode 100644
index 000000000000..4340ccda93df
--- /dev/null
+++ b/code/game/objects/items/devices/ioncannon_remote.dm
@@ -0,0 +1,56 @@
+/obj/item/device/loic_remote
+ name = "low-orbit ion cannon remote"
+ desc = "A remote control capable of sending a signal to the Syndicate's nearest remote satellite that has an ion cannon."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "batterer"
+ w_class = WEIGHT_CLASS_SMALL
+ /// How long until this can be used again?
+ var/recharge_time = 20 MINUTES
+ COOLDOWN_DECLARE(ion_cooldown)
+
+/obj/item/device/loic_remote/New()
+ ..()
+ START_PROCESSING(SSobj, src)
+
+/obj/item/device/loic_remote/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ ..()
+
+/obj/item/device/loic_remote/process()
+ update_appearance(UPDATE_ICON)
+
+/obj/item/device/loic_remote/update_icon(updates=ALL)
+ . = ..()
+ if(COOLDOWN_FINISHED(src, ion_cooldown))
+ icon_state = initial(icon_state)
+ else
+ icon_state = "[initial(icon_state)]burnt"
+
+/obj/item/device/loic_remote/examine(mob/user)
+ . = ..()
+ if(COOLDOWN_FINISHED(src, ion_cooldown))
+ . += "It is ready to fire."
+ else
+ var/seconds_left = COOLDOWN_TIMELEFT(src, ion_cooldown)/10
+ var/minutes_left_rounded = round(seconds_left/60, 0.1) // Don't want to deal with "1 minutes".
+ if(minutes_left_rounded > 1)
+ . += "It will be ready to fire in [minutes_left_rounded] minutes."
+ else
+ . += "It will be ready to fire in [seconds_left] seconds."
+
+/obj/item/device/loic_remote/attack_self(mob/user)
+ if(!COOLDOWN_FINISHED(src, ion_cooldown))
+ to_chat(user, span_notice("It is not ready to be used yet."))
+ return
+ if(!is_type_in_list(get_area(src), GLOB.the_station_areas))
+ to_chat(user, span_notice("The remote can't establish a connection. You need to be on the station."))
+ return
+
+ COOLDOWN_START(src, ion_cooldown, recharge_time)
+ to_chat(user, span_notice("[src]'s screen flashes green for a moment."))
+
+ var/datum/round_event/ion_storm/malicious/ion = new()
+ ion.location_name = get_area_name(src, TRUE)
+
+ message_admins("[key_name_admin(user)] generated an ion law using a LOIC remote.")
+ log_admin("[key_name(user)] generated an ion law using a LOIC remote.")
diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm
index 3a3dbd8f6534..079d23dc3891 100644
--- a/code/modules/events/ion_storm.dm
+++ b/code/modules/events/ion_storm.dm
@@ -62,6 +62,17 @@
if(prob(botEmagChance))
bot.emag_act()
+/datum/round_event/ion_storm/malicious
+ var/location_name
+
+/datum/round_event/ion_storm/malicious/announce(fake)
+ // Unlike normal ion storm, this always announces.
+ priority_announce("Abnormal ion activity detected. Please check all AI-controlled equipment for errors. Additional data has been downloaded and printed out at all communications consoles.", "Anomaly Alert", ANNOUNCER_IONSTORM)
+
+ var/message = "Malicious Interference with standard AI-Subsystems detected. Investigation recommended.
"
+ message += (location_name ? "Signal traced to [location_name].
" : "Signal untracable.
")
+ print_command_report(message, null, FALSE)
+
/*/proc/generate_ion_law() //yogs - start mirrored in the yogs folder
//Threats are generally bad things, silly or otherwise. Plural.
var/ionthreats = pick_list(ION_FILE, "ionthreats")
diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm
index ae20fcc1de8c..a3945f635658 100644
--- a/code/modules/uplink/uplink_items.dm
+++ b/code/modules/uplink/uplink_items.dm
@@ -2002,6 +2002,17 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/book/granter/mechpiloting
cost = 5 //this is genuinely a REALLY strong effect, don't sleep on it
+/datum/uplink_item/device_tools/loic_remote
+ name = "Low Orbit Ion Cannon Remote"
+ desc = "The Syndicate has recently installed a remote satellite nearby capable of generating a localized ion storm every 20 minutes. \
+ However, your local authorities will be informed of your general location when it is activated."
+ item = /obj/item/device/loic_remote
+ // TODO: When /datum/corporation/self is pickable for non-AI traitors, add it here.
+ limited_stock = 1 // Might be too annoying if someone had mulitple.
+ cost = 5 // Lacks the precision that a hacked law board (at 4 TCs) would give, but can be used on the go.
+ exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
+
+
// Implants
/datum/uplink_item/implants
category = "Implants"
diff --git a/yogstation.dme b/yogstation.dme
index bb47c3c05fb8..3c083895df1e 100644
--- a/yogstation.dme
+++ b/yogstation.dme
@@ -1196,6 +1196,7 @@
#include "code\game\objects\items\devices\forcefieldprojector.dm"
#include "code\game\objects\items\devices\geiger_counter.dm"
#include "code\game\objects\items\devices\gps.dm"
+#include "code\game\objects\items\devices\ioncannon_remote.dm"
#include "code\game\objects\items\devices\laserpointer.dm"
#include "code\game\objects\items\devices\lightreplacer.dm"
#include "code\game\objects\items\devices\megaphone.dm"