diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm
index 22894dd2c34..b8715810c69 100644
--- a/code/game/gamemodes/nuclear/nuclearbomb.dm
+++ b/code/game/gamemodes/nuclear/nuclearbomb.dm
@@ -808,6 +808,125 @@ GLOBAL_VAR(bomb_set)
if(length(open_turfs))
return pick(open_turfs)
+// MARK: NAD Scanner
+
+/obj/item/nad_scanner
+ name = "authentication disk decryptor"
+ desc = "A tiny tablet computer that can scan a nuclear authentication disk. The syndicate will relay the activation codes to you but it is likely the transmission will be intercepted by NT. Be prepared for a fight."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "nadscanner"
+ worn_icon_state = "electronic"
+ inhand_icon_state = "electronic"
+ w_class = WEIGHT_CLASS_TINY
+ /// The currently stored NAD
+ var/obj/item/disk/nuclear/disky
+ /// Is the device currently scanning?
+ var/scanning = FALSE
+ /// Is the device done decryption?
+ var/decrypted = FALSE
+
+ new_attack_chain = TRUE
+
+/obj/item/nad_scanner/examine(mob/user)
+ . = ..()
+ if(decrypted)
+ . += "It's burnt out!"
+
+/obj/item/nad_scanner/item_interaction(mob/living/user, obj/item/used, list/modifiers)
+ if(!istype(used, /obj/item/disk/nuclear))
+ return ..()
+ if(disky)
+ to_chat(user, "There is already something in [src]!")
+ return ITEM_INTERACT_COMPLETE
+
+ if(used.flags & NODROP || !user.transfer_item_to(used, src))
+ to_chat(user, "[used] is stuck to your hand!")
+ return ITEM_INTERACT_COMPLETE
+
+ to_chat(user, "You insert [used] into [src].")
+ disky = used
+ playsound(src, 'sound/machines/pda_button1.ogg', 50, TRUE)
+ update_icon(UPDATE_ICON_STATE)
+
+/obj/item/nad_scanner/update_icon_state(updates)
+ icon_state = "nadscanner"
+ if(!disky)
+ return
+ if(decrypted)
+ icon_state += "_decrypted"
+ else if(scanning)
+ icon_state += "_decrypting"
+ else if(disky)
+ icon_state += "_insert"
+
+/obj/item/nad_scanner/activate_self(mob/user)
+ if(world.time < 45 MINUTES) // 45 minutes of no nuke
+ to_chat(user, "[src] is still calibrating. Please wait another [round((27000 - world.time) / 600)] minutes before trying again.")
+ return ..()
+ scan_nad(user)
+ return ..()
+
+/obj/item/nad_scanner/AltClick(mob/user, modifiers)
+ if(scanning)
+ to_chat(user, "The disk is currently being scanned!")
+ return ..()
+ eject_nad(user)
+ return ..()
+
+/obj/item/nad_scanner/proc/eject_nad(mob/living/carbon/user)
+ if(!disky)
+ return
+ var/mob/M = user
+ M.put_in_hands(disky)
+ to_chat(user, "You remove [disky] from [src].")
+ disky = null
+ update_icon(UPDATE_ICON_STATE)
+ playsound(src, 'sound/machines/terminal_eject.ogg', 50, TRUE)
+
+/obj/item/nad_scanner/proc/scan_nad(mob/user)
+ if(!disky)
+ to_chat(user, "There is no disk inserted!")
+ return
+ if(decrypted)
+ to_chat(user, "This device is burnt out!")
+ return
+ if(scanning)
+ to_chat(user, "You are already scanning a disk!")
+ return
+ scanning = TRUE
+ to_chat(user, "You start the decryption process.")
+ update_icon(UPDATE_ICON_STATE)
+ if(!do_after(user, 10 SECONDS, needhand = FALSE, target = src, allow_moving = TRUE, hidden = TRUE))
+ to_chat(user, "You stop the decryption process.")
+ return
+ if(istype(disky, /obj/item/disk/nuclear/training))
+ atom_say("Incompatible disk detected!")
+ scanning = FALSE
+ update_icon(UPDATE_ICON_STATE)
+ return
+ var/complete_message = "We have intercepted a syndicate communication inbound to your station. The message reads: \n\"We have decrypted the codes from the nuclear authentication disk."
+ var/code
+ for(var/obj/machinery/nuclearbomb/bombue in SSmachines.get_by_type(/obj/machinery/nuclearbomb))
+ if(length(bombue.r_code) <= 5 && bombue.r_code != "LOLNO" && bombue.r_code != "ADMIN")
+ code = bombue.r_code
+ break
+ if(!code)
+ atom_say("No nuclear device detected!")
+ return
+ complete_message += " The code is [code]. Take those scum down.\" \n"
+ complete_message += "We suspect the syndicate is trying to detonate your nuclear device. All crew are to ensure this does not happen."
+
+ GLOB.major_announcement.Announce(
+ complete_message,
+ new_title = "Enemy Communication Intercepted",
+ new_subtitle = "Intercepted Syndicate Communique",
+ new_sound = 'sound/AI/intercept.ogg'
+ )
+ print_command_report(complete_message, "Intercepted Syndicate Communique")
+ decrypted = TRUE
+ scanning = FALSE
+ update_icon(UPDATE_ICON_STATE)
+
// MARK: Training Nuke
/obj/machinery/nuclearbomb/training
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 54cb48613ef..79650f1bca0 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -584,13 +584,8 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
/datum/objective/nuke/New(text, datum/team/team_to_join, datum/mind/_owner)
. = ..()
- var/code
- for(var/obj/machinery/nuclearbomb/bombue in SSmachines.get_by_type(/obj/machinery/nuclearbomb))
- if(length(bombue.r_code) <= 5 && bombue.r_code != "LOLNO" && bombue.r_code != "ADMIN")
- code = bombue.r_code
- break
- if(code)
- explanation_text += " We have intercepted the nuclear codes for the warhead. The code is [code]. Good luck."
+ // We have to do it with a callback because mind/Topic creates the objective without an owner
+ addtimer(CALLBACK(src, PROC_REF(give_kit), /obj/item/nad_scanner), 5 SECONDS, TIMER_DELETE_ME)
/datum/objective/nuke/check_completion()
if(SSticker.mode.station_was_nuked)
diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi
index ca9e98b7015..5e0e58f477e 100644
Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ