5G core memory forensics is faster than most people think. While helping a lab set up 5G security, a researcher finished for the day and left the host running. I decided to try something: capture its RAM and see what fell out. Twenty minutes in all, five of them spent taking screenshots, and the subscriber's permanent key (K), its OPc, and the SUCI home-network private keys were in a file. This is not exotic nation-state work. It is LiME, Volatility 3 and YARA, standard forensics tools, run against a containerised Open5GS standalone core that was doing everything by the book. The deeper point is the one InfraGuard keeps making: all of 3GPP's security, including authentication, the key hierarchy and SUCI concealment, assumes the host running the core can be trusted. Sometimes it cannot.
Keys in the Core
The scene: a 5G core left running
A 5G standalone core is only as secure as the host that runs it. Hosts get left unattended. The lab was set up to work on 5G security: a containerised Open5GS standalone core with the eUPF (eBPF/XDP user plane) and a UERANSIM gNB and UE, all network functions running as Docker containers on a single bridge network (172.22.0.0/24). Nothing exotic, nothing misconfigured on purpose. The standard docker_open5gs deployment.

State at capture: one UE registered with an active PDU session, pinging 8.8.8.8 through the eUPF. Three subscribers provisioned: the UERANSIM test UE with its public default credentials, and two programmable SIM cards from earlier over-the-air tests. The researcher finished for the day, logged out, and left the system on. I just tried this: pointed standard memory-forensics tooling at the running host and asked what a compromise would have recovered. No code changes, no special access beyond what the box already grants its users.
The 20-minute capture
Capturing a host's RAM and scanning it for subscriber secrets takes about twenty minutes when you already have root.
- Loaded LiME, a kernel module, and captured 31.68 GiB of physical memory across 9 ranges, checksummed. Host: Ubuntu 22.04, kernel 6.8.0-138-generic. AVML 0.21.0 was installed on the box as an alternative.
- Built YARA rules from the subscriber database: each IMSI, K, OP and OPc as hex text and as raw bytes, deriving OPc from K and OP via Milenage where only OP was stored.
- Ran Volatility 3 with a symbol table matching the kernel banner exactly: linux.pslist, linux.ebpf, linux.envars, linux.vmayarascan for per-process attribution, and yarascan across all memory.
- Read the raw image around each raw-key hit to see the surrounding structures, and fingerprinted every PEM private key in RAM against key files on the host and in the containers.
| Secret (test UE) | Copies in RAM |
|---|---|
| K, raw bytes | 4 |
| OPc, raw bytes | 2 |
| OPc, hex text | 15 |
| K, hex text | 799 |

About fifteen minutes from first command to first findings; the other five went to taking screenshots for this write-up. The vantage point, stated plainly: a full physical capture needs root. These results are what an attacker who already has root on the host (or membership in the docker group, see F7) recovers. Findings that matter to a less privileged attacker are called out where relevant.
What came out of RAM
Subscriber secrets came out of RAM in bulk. Some sat in places they had no business being; a few sat in places they should never be.
F1: Management dashboards reachable from the network (High)
The compose files publish the Open5GS WebUI (port 9999), Grafana (3000) and Prometheus (9090) on all host interfaces (0.0.0.0). All three answered from a machine on a different subnet. The WebUI manages subscribers, including their K and OPc, and ships with a well-known default login; Grafana uses the default password from the .env file; Prometheus has no authentication. This is the only finding that needs no foothold on the host. Whether the default WebUI login still worked was not tested.
F2: Plaintext subscriber keys on the service-based interface (High)
When the UDM fetches authentication data, the UDR's JSON response carries the subscriber's permanent key and OPc. The 3GPP field names, encPermanentKey and encOpcKey, say "encrypted". Open5GS sends the plain values, and the service-based interface runs over cleartext HTTP/2 through the SCP. The capture shows it plainly: the response carries "encPermanentKey":"8baf…6862" and "encOpcKey":"8e27…605d" next to the SUPI. Values truncated, from the public UERANSIM test credentials. Five copies of that response were in memory, next to HTTP/2 headers for the SCP and UDR and the UDR's MongoDB query. OPc appears in no environment variable or config file; it can only have come from SBI traffic. A compromised SCP, or anything able to observe the container bridge, sees the K and OPc of every subscriber that authenticates.
F3: Secrets in every container's environment (Medium)
Every service uses the same env_file: .env, so all of its variables go to every container, including the UE's K (UE1_KI), its OP and GRAFANA_PASSWORD. Volatility's linux.envars confirmed them in the AMF, eUPF and gNB processes. GRAFANA_PASSWORD was found 793 times in RAM. Compromising any one container exposes these values through /proc/<pid>/environ or docker inspect without any memory forensics.

F4: Default SUCI home-network keys (Medium)
The image includes the ECIES home-network private keys (hnet/curve25519-*.key, secp256r1-*.key) from the public repository, copied into every container. SUCI concealment protects the IMSI on the radio interface only if the home-network key is secret. With the default keys, SIMs provisioned with the matching public key get no real identity privacy over the air.
F5: Stale key material in unowned memory (Medium)
The raw-byte K and OPc appeared side by side in four places: one inside the live UDM heap, two inside the UE (as expected), and one byte-identical copy of the UDM structure in memory owned by no running process. The core had been restarted several times before the capture. Most likely the heap of an earlier UDM process, freed without wiping. Restarts do not clean secrets out of RAM.
F6: Secrets at rest in plaintext (Low)
K and OPc are stored unencrypted in MongoDB, in the .env file, in lab notes, and in an old project copy in the desktop Trash. All of it showed up in the page cache. MongoDB in the default deployment has no authentication on the container network.
F7: Docker group is root (Info)
The lab user is in the docker group, and several containers run privileged (the eUPF and its route helper). Anyone in that group can reach root-level access on the host. "No sudo password" does not mean "cannot capture memory" on this machine.
The dump holds more than 5G secrets
This exercise scanned only for subscriber material (IMSIs, K, OP, OPc) because that was the engagement's scope. A physical capture is not that polite. 31.68 GiB of RAM is a snapshot of everything the host was doing at that moment: browser sessions with their cookies and tokens, password managers and their vault material, SSH agents and the keys loaded into them, file contents sitting in the page cache, and the working memory of every running application. The capture already held 27 distinct PEM private keys in 63 copies, most of them not from this 5G deployment at all. Had a VM been running on the host, its guest memory would have been in the dump too. A host capture is a capture of every VM on it, because the hypervisor keeps guest RAM in host memory. The scan time was bounded by the rules we chose to write, not by what was recoverable. An attacker with no scope runs the same capture once and re-scans it against browser tokens, cloud credentials, SSH keys, VPN configs, building as many rule sets as they care to. One dump, many paydays. The 20-minute figure says nothing about what a motivated analyst could pull out of the same image.
What behaved correctly
The cryptography held. The failures were operational.
- Raw-byte K and OPc, the form used for key derivation, appeared only in the UDM and the UE.
- The AMF and eUPF held no raw K and no OPc. The AMF works only with derived keys, as the 3GPP key hierarchy intends.
- The two real-SIM subscribers' keys appeared only in mongod.
- The operator's SSH private key was not in RAM.

If the attacker had more time
Twenty minutes is a floor, not a ceiling. This run took about twenty minutes and stopped at read-only analysis. A dedicated attacker with more time and a purpose could go further, quietly:
- Capture every fresh authentication, harvesting K and OPc for every SIM as UEs attach and re-attach.
- Stay resident: the kernel module load that made this capture possible is the same path an implant would use.
- Credential-stuff the WebUI with its default login and manage subscribers through the front door.
- Tamper with the core itself: the same host memory that leaks keys also holds the enforcement logic.
- Fingerprint the rest of the 27 distinct PEM private keys found in RAM (63 copies in all, 24 of them unmatched to any readable key file) using reference material from other host files and image layers.
When the host can't be trusted
Every 3GPP protection (authentication, the key hierarchy, SUCI concealment) assumes the host running the core is trustworthy. Memory forensics shows what happens when it is not. None of the findings above required breaking 3GPP cryptography. They required a host that was left running, open ports, shared env files, and a trust assumption. This is exactly the problem InfraGuard works on: sometimes the host cannot be trusted. It can be compromised, its operator can be careless, or someone simply left it on. InfraGuard verifies the host continuously and binds workload execution to that verification, so a core (or any workload) only runs on a host that can prove its state. It moves trust from "we believe the host" to "we verified the host".
Fixing the easy things first
Most of these findings are config changes, not research problems.
- Bind the WebUI, Grafana and Prometheus to 127.0.0.1 and reach them over an SSH tunnel; change both default passwords.
- Enable TLS on the service-based interface and limit which containers can reach the SCP and UDR.
- Split the env files so UE credentials go only to the UE container; keep service passwords in Docker secrets.
- Generate fresh SUCI home-network key pairs, give the private key only to the UDM, and reprovision SIMs with the new public key.
- Zero key buffers before freeing them (explicit_bzero or equivalent) in the UDM and AUSF authentication paths.
- Enable MongoDB authentication; keep keys out of notes and env files; empty the Trash.
- Test unprivileged scenarios with an account outside both the sudo and docker groups.
Conclusion
Twenty minutes, five of them spent on screenshots. Standard tools. A host that was left running. That is all it takes to demonstrate the weakest link in a 5G core: the host it runs on. The radio-side security (authentication, the key hierarchy, SUCI) did its job; the "behaved correctly" list above is the proof. What failed was the operational layer: plaintext keys crossing the service-based interface, dashboards with default passwords on every interface, secrets copied into every container, and a trust assumption that the host is safe. InfraGuard's whole premise is that the host often cannot be trusted, and that premise needs to be verified, not assumed. If you run a 5G core, in a lab or in production, assume the host is hostile and design from there.
Useful Links & Resources
- [Open5GS]: https://open5gs.org
- [UERANSIM]: https://github.com/aligungr/UERANSIM
- [docker_open5gs]: https://github.com/herlesupreeth/docker_open5gs
- [Volatility 3]: https://volatilityfoundation.org/volatility-3/
- [InfraGuard]: https://teyzsec.com/infraguard
- 📚 Related Blog Posts:
Frequently Asked Questions
What is 5G core memory forensics?
Capturing a host's RAM and scanning it for secrets such as subscriber keys, credentials and key material, to assess what an attacker with host access could recover.
How was the memory captured?
With LiME, a kernel module, producing a 31.68 GiB physical memory image across 9 ranges, then Volatility 3 with a matching kernel symbol table and YARA rules built from the subscriber database.
What did the capture find?
K and OPc in plaintext on the service-based interface, management dashboards on all interfaces, UE credentials in every container's environment, default SUCI home-network keys, and a stale copy of the UDM's key structure in memory owned by no running process.
Does this mean 5G is insecure?
No. The cryptography held. Raw keys appeared only in the UDM and the UE, and the AMF worked only with derived keys. The exposure is operational: plaintext secrets, open ports, shared env files, and an untrusted host.
How does this relate to InfraGuard?
Every finding assumed the host was trustworthy. InfraGuard addresses the case where the host cannot be trusted, by verifying it continuously and binding workloads to that verification.
Did you look for anything besides 5G keys?
No. The scan was scoped to subscriber material. The same capture holds whatever else was in memory: browser sessions, credentials, other private keys. One dump, as many rule sets as an analyst cares to run.
How long did the whole exercise take?
About twenty minutes in all: fifteen of capture and first-pass analysis, five more taking screenshots. A more dedicated attacker with more time could go considerably further.