diff --git a/Content.Server/Storage/Components/PickRandomComponent.cs b/Content.Server/Storage/Components/PickRandomComponent.cs
new file mode 100644
index 0000000000..1046c55911
--- /dev/null
+++ b/Content.Server/Storage/Components/PickRandomComponent.cs
@@ -0,0 +1,31 @@
+using Content.Server.Storage.EntitySystems;
+using Content.Shared.Whitelist;
+
+namespace Content.Server.Storage.Components;
+
+///
+/// Adds a verb to pick a random item from a container.
+/// Only picks items that match the whitelist.
+///
+[RegisterComponent]
+[Access(typeof(PickRandomSystem))]
+public sealed class PickRandomComponent : Component
+{
+ ///
+ /// Whitelist for potential picked items.
+ ///
+ [DataField("whitelist"), ViewVariables(VVAccess.ReadWrite)]
+ public EntityWhitelist? Whitelist;
+
+ ///
+ /// Locale id for the pick verb text.
+ ///
+ [DataField("verbText"), ViewVariables(VVAccess.ReadWrite)]
+ public string VerbText = "comp-pick-random-verb-text";
+
+ ///
+ /// Locale id for the empty storage message.
+ ///
+ [DataField("emptyText"), ViewVariables(VVAccess.ReadWrite)]
+ public string EmptyText = "comp-pick-random-empty";
+}
diff --git a/Content.Server/Storage/EntitySystems/PickRandomSystem.cs b/Content.Server/Storage/EntitySystems/PickRandomSystem.cs
new file mode 100644
index 0000000000..eb48829b26
--- /dev/null
+++ b/Content.Server/Storage/EntitySystems/PickRandomSystem.cs
@@ -0,0 +1,61 @@
+using Content.Server.Storage.Components;
+using Content.Shared.Database;
+using Content.Shared.Hands.EntitySystems;
+using Content.Shared.Verbs;
+using Robust.Shared.Containers;
+using Robust.Shared.Random;
+using System.Linq;
+
+namespace Content.Server.Storage.EntitySystems;
+
+// TODO: move this to shared for verb prediction if/when storage is in shared
+public sealed class PickRandomSystem : EntitySystem
+{
+ [Dependency] private readonly SharedContainerSystem _container = default!;
+ [Dependency] private readonly SharedHandsSystem _hands = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent>(OnGetAlternativeVerbs);
+ }
+
+ private void OnGetAlternativeVerbs(EntityUid uid, PickRandomComponent comp, GetVerbsEvent args)
+ {
+ if (!args.CanAccess || !args.CanInteract || !TryComp(uid, out var storage))
+ return;
+
+ var user = args.User;
+
+ // alt-click / alt-z to pick an item
+ args.Verbs.Add(new AlternativeVerb
+ {
+ Act = (() => {
+ TryPick(uid, comp, storage, user);
+ }),
+ Impact = LogImpact.Low,
+ Text = Loc.GetString(comp.VerbText),
+ Disabled = !(storage.StoredEntities?.Any(item => comp.Whitelist?.IsValid(item, EntityManager) ?? true) ?? false),
+ Message = Loc.GetString(comp.EmptyText, ("storage", uid))
+ });
+ }
+
+ private void TryPick(EntityUid uid, PickRandomComponent comp, ServerStorageComponent storage, EntityUid user)
+ {
+ if (storage.StoredEntities == null)
+ return;
+
+ var entities = storage.StoredEntities.Where(item => comp.Whitelist?.IsValid(item, EntityManager) ?? true);
+ if (!entities.Any())
+ return;
+
+ var picked = _random.Pick(entities.ToList());
+ // if it fails to go into a hand of the user, will be on the storage
+ _container.AttachParentToContainerOrGrid(Transform(picked));
+
+ // TODO: try to put in hands, failing that put it on the storage
+ _hands.TryPickupAnyHand(user, picked);
+ }
+}
diff --git a/Resources/Locale/en-US/storage/components/pick-random-component.ftl b/Resources/Locale/en-US/storage/components/pick-random-component.ftl
new file mode 100644
index 0000000000..a3e72a0e6a
--- /dev/null
+++ b/Resources/Locale/en-US/storage/components/pick-random-component.ftl
@@ -0,0 +1,2 @@
+comp-pick-random-empty = {CAPITALIZE(THE($storage))} is empty!
+comp-pick-random-verb-text = Pick item