10 Oct 2026
LXer Linux News
SQLite 3.54 Released With Faster Performance, Drops Windows XP Support
SQLite 3.54 released today for this wildly popular embedded SQL database engine used by countless applications and other software. With SQLite 3.54, support for Microsoft Windows XP and older is finally removed...
10 Oct 2026 4:45am GMT
KDE Releases KDE Frameworks 6.31 with Various Improvements and Bug Fixes
The KDE Project released KDE Frameworks 6.31 today as the latest stable update to this open-source collection of more than 80 add-on libraries to Qt and a companion to the KDE Plasma desktop environment and KDE Gear software suite.
10 Oct 2026 3:14am GMT
Python 3.15 Released With Experimental JIT Compiler Running Faster
Python 3.15 is out today as the newest annual feature release for the Python programming language...
10 Oct 2026 1:42am GMT
11 of 23 Core Open Source Projects Run on 1 or 2 People
A Redditor counted who wrote every change to xz, sudo, bash, tz and 19 more projects. 11 of 23 rely on one or two people. See who they are and who pays.
10 Oct 2026 12:11am GMT
09 Oct 2026
LXer Linux News
Canonical Announces Official Ubuntu Desktop Images for RISC-V
Ubuntu maker Canonical announced today the general availability of Ubuntu Desktop images for the RISC-V architecture, along with unofficial and unsupported Xubuntu Minimal images for RISC-V.
09 Oct 2026 10:39pm GMT
AMD PerfOpt Boosting Prior-Gen Ryzen APU Performance For AI
Last week I ran benchmarks of the new AMD PerfOpt feature being introduced in Linux 7.4. In those PerfOpt benchmarks on current-gen AMD Ryzen AI APUs/SoCs the AI performance improved as much as 18~23%. Several Phoronix readers expressed interest in seeing how prior-gen AMD Ryzen hardware benefited or not from PerfOpt, so here are some additional benchmarks.
09 Oct 2026 9:08pm GMT
Linuxiac
Woodpecker CI 3.19 Adds Server-Enforced Agent Labels

Woodpecker CI 3.19 fixes a security issue involving matrix variables, adds server-enforced agent labels, and improves pipeline reliability.
09 Oct 2026 8:50pm GMT
LXer Linux News
aerynOS Makes Budgie 10.10.3 Widely Available, Updates COSMIC to 1.10
aerynOS moves Budgie 10.10.3 from testing to its Unstable Stream, making it broadly available alongside COSMIC Desktop 1.10 and Linux 7.2.9.
09 Oct 2026 7:36pm GMT
Boro: NVIDIA's Open-Source Effort For AI-Assisted Linux Kernel Development
Over the past few months NVIDIA has been developing Boro as a new AI-assisted kernel development CLI written in Rust and focused on local AI for enhancing efficiency for kernel development...
09 Oct 2026 6:05pm GMT
Linuxiac
KDE Frameworks 6.31 Released with File Management and Text Encoding Improvements

KDE Frameworks 6.31 improves file copying and moving, text encoding detection, text editing, metadata extraction, and more.
09 Oct 2026 5:03pm GMT
LXer Linux News
Ventoy 1.1.18 Adds Experimental Support for SteamOS Recovery Images
Ventoy 1.1.18 has been released today as a maintenance and feature update to this open-source bootable USB solution that introduces support for new systems and improves support for existing distributions.
09 Oct 2026 4:33pm GMT
Linuxiac
aerynOS Makes Budgie 10.10.3 Widely Available, Updates COSMIC to 1.10

aerynOS moves Budgie 10.10.3 from testing to its Unstable Stream, making it broadly available alongside COSMIC Desktop 1.10 and Linux 7.2.9.
09 Oct 2026 2:09pm GMT
LXer Linux News
Rocky Linux Rescues OpenRadioss From Siemens’ Dumpster
The OpenRadioss fork is already drawing an impressive community as contributors help restore builds and missing components.
09 Oct 2026 1:44pm GMT
Ubuntu vs Linux Mint: Which Linux Distro Is Better in 2026?
Ubuntu or Linux Mint? See how they compare on speed, software, updates and ease of use, and find out which one fits you before you install.
09 Oct 2026 12:13pm GMT
Ubuntu Currently Suffering From Sustained DDoS Attack
Those trying to access the Ubuntu website, ISO downloads, and similar Ubuntu resources today are finding the site inoperable amid what's now confirmed as an ongoing distributed denial of service attack...
09 Oct 2026 10:41am GMT
Linuxiac
Immich 3.3 Photo and Video Management Solution Adds People Sharing, Birthday Memories

Immich 3.3 introduces shared people management, birthday memories, automatic photo stacking, and improved image quality.
09 Oct 2026 9:45am GMT
LXer Linux News
Google's Kage Project Rethinks Linux Kernel Security With Isolated Device Drivers
Google is exploring a new approach to Linux kernel security that could significantly change how device drivers interact with the operating system. The experimental project, known as Kage, uses compiler-based sandboxing to isolate drivers inside the kernel, potentially limiting the damage caused by memory corruption, programming errors, and exploitable vulnerabilities without requiring drivers to run as separate user-space processes.
09 Oct 2026 9:10am GMT
COSMIC 1.10 Adds Support for Mapping Drawing Tablets to Specific Displays
Linux hardware vendor System76 released COSMIC 1.10 today as the latest stable version of this Rust-based desktop environment for modern GNU/Linux distributions.
09 Oct 2026 7:38am GMT
Linuxiac
Calibre 9.16 E-Book Manager Adds Kokoro Voices, Improves PDF Support

Calibre 9.16 introduces Kokoro text-to-speech voices, better PDF handling, AVIF image support, and performance improvements for large libraries.
09 Oct 2026 6:57am GMT
Ventoy 1.1.18 Adds Experimental SteamOS Support, Linux Boot Fixes

Ventoy 1.1.18 introduces experimental SteamOS recovery support, improves ISO partition mounting on Linux, and fixes several boot issues.
09 Oct 2026 6:44am GMT
LXer Linux News
New AI Agent Resources Proposed For The Linux Kernel, AI Skills To Help Developers
The latest proposal for the upstream Linux kernel is introducing infrastructure for AI agent resources. Initially these agent resources would be for a skill so AI agents can automatically add a "Fixes: " tag on relevant patches for noting the first problematic Git commit automatically that a patch fixes...
09 Oct 2026 6:07am GMT
Distro of the Week: VailuxOS 1.6.1.4
After a day or two of false alarms, Distro of the Week finally settled on a German distro based on Debian, specifically VailuxOS 1.6.1.4. The distro, aimed specifically at Windows refugees, has much to offer the wide spectrum of Linux users choosing it, and overall it was a pleasant surprise. .
09 Oct 2026 4:35am GMT
08 Oct 2026
Linuxiac
Flathub Reverses AI-Generated App Ban, Now Requires Disclosure

Flathub reverses its ban on AI-generated apps, introducing mandatory disclosure requirements while keeping restrictions on automated submissions.
08 Oct 2026 10:25pm GMT
PhotoPrism AI-Powered Photos App Gets Better Image Recognition, NVIDIA GPU Support

PhotoPrism's October 2026 update improves AI image recognition, adds NVIDIA GPU acceleration, and enhances face detection and photo management.
08 Oct 2026 7:47pm GMT
Raspberry Pi Imager 2.0.12 Brings WPA3 Fixes, Safer Image Writing

Raspberry Pi Imager 2.0.12 improves image writing reliability, fixes WPA3 Wi-Fi configuration, and addresses Linux AppImage issues.
08 Oct 2026 6:04pm GMT
COSMIC Desktop 1.10 Released with Launcher and Compositor Updates

COSMIC Desktop 1.10 enables wGPU rendering in its launcher and introduces compositor improvements alongside updated desktop applications.
08 Oct 2026 5:43pm GMT
06 Oct 2026
Kernel Planet
Linux Plumbers Conference: Free Live Streaming and Matrix Chat available
To watch any of our live streams on youtube, go to the schedule overview and hover over the paperclip to see the 'Live Stream' link. Live streams are only available for A/V assisted tracks (so not non-A/V BoFs). If you want a two way conversation, you need to have a matrix account, join the Linux Plumbers Space and find the room corresponding to the track you're watching.
06 Oct 2026 6:27am GMT
09 Sep 2026
Kernel Planet
Dave Airlie (blogspot): nouveau on nvidia spark GB10 - it's alive!
After much back and forth and hoops jumping, I can finally reveal nouveau/nvk running on a NVIDIA Spark box.
This is running on a version of nouveau[1] that has
a) ported to the 610 NVIDIA firmware
b) a bunch of display rework from Moham
c) a bunch of 0 VRAM and L2 cache handling fixes
d) spark boot support
e) spark display support
and NVK[2] with patches to handle gb10 depth/stencil differences and 0 VRAM support.
I'm not sure how best to upstream it all, it's 100 patches and a new firmware which might mean it's a wait for nova type situation, but I just wanted to see it work.
[1] https://gitlab.freedesktop.org/nouvelles/kernel/-/commits/nouveau-610-wip-spark
[2] https://gitlab.freedesktop.org/airlied/mesa/-/commits/nvk-spark-wip
09 Sep 2026 7:56pm GMT
Matthew Garrett: SystemIO conflicts are not firmware bugs
I'm looking at something entirely unrelated, but tripped over some search results that made me realise that a lot of people still think getting errors like ACPI Warning: SystemIO range 0x0000000000001828-0x000000000000182F conflicts with OpRegion 0x0000000000001800-0x000000000000187F indicate a firmware bug. This is generally untrue. We need to dive a little into what ACPI is to clarify why.
The Advanced Configuration and Power Interface1 specification defines a whole bunch of stuff, but what's interesting to us here is the hardware abstraction it performs. While PCs are nominally a well-defined platform that's really not true at the hardware level once you get beyond a certain level of complexity. When you suspend a system you want to power down the hardware in the correct order, for instance, and knowing what that order is requires you to know details about the specific motherboard design. The approach taken in the embedded world is to just bake that knowledge into the OS in some form, which is how we end up with Devicetree. ACPI takes an alternative approach - rather than provide that information as data that has to be consumed by OS drivers, it distributes it as code.
The ACPI Source Language, or ASL, is a simple language that gets compiled into a bytecode that's then interpreted by the OS at runtime. One of the features of this language is the ability to define "Operation Regions", effectively structure definitions that describe access to underlying hardware. Let's imagine a simple device with two exposed registers. The first is an index register - it describes which internal register we want to access. The second is a data register, where reading it gives us the value of the internal register whose address is currently in the index register, and writing to it modifies that register. An example operation region declaration would look something like
|
|
This defines an operation region called "OPR1" at IO port 0x400, 2 bytes long. Inside it are two 8-bit fields, INDX and DATA. These are to be accessed one at a time, do not need the ACPI interpreter to take a global lock when accessing them, and if a subset of the register is modified then the other values should be preserved (irrelevant in this case since the fields are only a byte wide). Now any references to INDX or DATA in this scope will trigger accesses to those registers. So, a method to read the value of register 0x03 would look something like:
|
|
ie, set INDX to 3, and then read the value of DATA and return it. But! What if another ACPI method is running at the same time? Let's say we have one that writes to register 0x05:
|
|
What happens if RD03 executes while we're part-way through WR05? INDX might get reset to 0x03, and now WR05 will modify register 0x03 instead of 0x05. Oh no! But we can avoid this - we declare a mutex (Mutex (MUTX, 0x00)), and update our methods to be something like:
|
|
Each method takes a lock (waiting up to 0xffff milliseconds and then erroring out if it doesn't), and performs the access. There's now no chance of a race. Phew!
Now suppose someone writes a Linux driver for this piece of hardware. It accesses the hardware directly, with no knowledge of ACPI. What stops the driver from racing against one of the ACPI access methods? Nothing at all. Oh no! Again! This isn't hypothetical, by the way - here's a relatively harmless example, but back in the day we did trip over cases where temperature monitoring chips would be accessed by the firmware and Linux simultaneously and as a result you might end up thinking you're reading a temperature when you're actually reading a status flag, resulting in an impossibly high temperature and an immediate thermal shutdown.
In this case, the kernel saves you from this (potentially hardware damaging) outcome by printing a message like ACPI Warning: SystemIO range 0x0000000000000400-0x000000000000401 conflicts with OpRegion 0x0000000000000400-0x0000000000000401 (OPR1), telling you that the kernel has detected that a driver is attempting to allocate IO ports 0x400-0x401, but that there's an ACPI operation region called OPR1 that is claiming the same addresses. The kernel isn't in a position to know what type of access the firmware might perform in that region, so assumes that it might be dangerous and blocks the driver from loading.
But all is not lost! The kernel also prints some helpful advice, ACPI: If an ACPI driver is available for this device, you should use it instead of the native driver. And ACPI tables will often actually have a definition that looks like this:
|
|
which defines an ACPI device and associated methods. The _HID field defines the device type, and a Linux driver can be written that will be automatically loaded if a device with type VEND0001 is seen. That driver can then call ACPI methods associated with the device and access the resources in a way that matches the firmware's expectations.
(Interested in writing such a driver? I wrote a guide back in 2009)
The firmware did absolutely nothing wrong here2, but trying to load the native driver will generate an error and the internet will tell you that PC firmware developers are incompetent3 and you should pass a kernel argument that overrides this behaviour and it never did them any harm, and it probably won't do you any harm either but it might and you might never know why your system occasionally wedges or catches fire.
-
The ACPI spec used to live at
acpi.info, but sadly that seems to have vanished some time after UEFI took over stewardship of the spec ↩︎ -
You might argue that the firmware should simply not do anything at runtime because it is not the firmware's job to do that, and I do understand that and you can certainly boot with
acpi=offif you want to and no ACPI code will be executed at runtime. Let me know how that goes. ↩︎ -
I'm not going to present an opinion on that here, merely say that this provides no supporting evidence for that assertion ↩︎
09 Sep 2026 6:15pm GMT
26 Aug 2026
Kernel Planet
Matthew Garrett: Hooking an old magicJack adapter to modern Asterisk
I'm on a VPN setup with several friends that, obviously, includes a VoIP network. I also have an old magicJack adapter and a deep and abiding need to use hardware in ways I should not. There was obvious synergy here.
Plugging in the magicJack gives a USB vendor id of 0x06e6, which belonged to a company called TigerJet who made a range of chips for hooking up phones to computers, either via USB or PCI. Some more digging suggested that it was a 580 part, and someone had conveniently uploaded some reference code and datasheets, so figuring out how to talk to the chip wasn't terribly difficult. Once configured it simply sends HID events whenever a user hits a phone key or changes the hook state, and otherwise exposes a USB audio device that can be spoken to using the stock kernel driver. It also has the ability to generate dial tone and assert ring signal, giving a full traditional phone experience.
So you'd think this would be a super easy project, but I'd made things harder for myself by deciding I wanted to tie directly into Asterisk rather than just smashing an existing SIP stack onto the device. Asterisk uses channels to talk to devices, and channels end up as compiled C code that Asterisk can load dynamically. I didn't want to have to deal with the pain of compiling stuff and matching ABIs and everything so writing a new channel from scratch was unappealing. Fortunately, the websocket channel is available in recent versions of Asterisk and provides a convenient way to get audio in and out, but that still leaves the job of handling incoming and outgoing calls. That's handled with the Asterisk Rest Interface, which can initiate a call or respond to an incoming one and bridge various channels together to produce a bidirectional audio stream. There's a convenient async Python library that handles the low level protocol.
Code for all this is here1, and works for my use case, but I should really abstract out the asterisk side and the magicJack side to make it easier to adapt to other devices. That's a job for later, though. For now, you get this:
26 Aug 2026 4:04am GMT
15 Aug 2026
Kernel Planet
Linux Plumbers Conference: Linux Plumbers Conference 2026 is now SOLD OUT!
It has become a trend for us now. Linux Plumbers Conference 2026 that is to be held in Prague on October 5th through to the 7th is now sold out. But do not fret, you may still be able to attend, but to do so, you will need to add yourself to the wait-list.
Please note that the wait-list is a priority ordered list but adding yourself early still does help. The highest priority is for people with accepted content, followed by people who have submitted content but it was not accepted. Then we look at the rest. Each of these priority levels are processed in a first-come/first-served fashion. Thus, the earlier you add yourself, the higher you are in your priority level. We also take the "latest date you can be registered" seriously. If a spot opens up after the date you put in there and you are the next in line, you will be skipped.
Good luck everyone who wants to attend but still did not buy a ticket. We hope the wait-list will be empty by the time the conference begins.
15 Aug 2026 2:25pm GMT
05 Aug 2026
Kernel Planet
Linux Plumbers Conference: Microconference Topic CfP is coming to an End
This Friday (August 7th) is the last day to submit a topic to any of the Microconferences. If you have something interesting to discuss at a Microconference, do not hesitate, submit now! It's also a good idea to reread The Ideal Microconference Topic Session. Notifications for accepted and rejected topics will happen on or before August 21st.
05 Aug 2026 7:52pm GMT
24 Jul 2026
Kernel Planet
Linux Plumbers Conference: Linux Plumbers Conference Registration is now Open
We're pleased to announce Linux Plumbers Conference registration is now open. Please see our attend page for details.
24 Jul 2026 4:05pm GMT
03 Jul 2026
Kernel Planet
Matthew Garrett: Securing agentic identity
As is the case for many people working in the security industry, the last few months of my life have been focused on dealing with people wanting to use LLMs everywhere. From an enterprise security perspective that's not an inherent problem - what's more of a problem is that people want those agents to have access to resources like their calendar and email and so on, and now we have somewhat non-deterministic agents that seem very enthusiastic to achieve what you asked whether that's a good idea or not, and we're combining this with credentials that give them access to sensitive data, and leaving those credentials on disk where they can be committed into git repos or exfiltrated to some other service to make use of them on the agent's behalf or well just any other number of things, at which point your CEO's email is suddenly readable by everyone and you're having a bad day.
As I mentioned in my last post, pretty much every strong mechanism for keeping credentials in place is just not supported in the wider world. We can imagine a universe where agents use hardware (or at least hypervisor) backed certificates to obtain credentials and any that end up leaking are worthless as a result. But, sadly, that's not an option for most people using existing identity providers. The state of the art is that you use the device code flow and a human authenticates and the token ends up back inside the agent environment and then it proceeds to do whatever it wants with it and you just hope that you wake up the next morning without an awful infoleak occurring.
(An aside: I do not like the device code flow as used in enterprise environments, and I never will. The identity provider doesn't have a real opportuity to inspect the security posture of the system asking for the token, and as a result some identity providers will restrict tokens that are issued in this way. The common alternative of doing stuff using a more standard flow and having a redirect URI pointing at localhost works fine for local systems and is a pain for remote ones, even if you can commit crimes with SSH forwarding. I'm going to suggest something that I think is better, and you are free to disagree)
I'm not in a position to get every identity provider and service provider to change their security posture, so I'm somewhat stuck in terms of the tokens they're willing to issue me - largely either JWTs or opaque access tokens, with no support for any mechanism of binding that token to an instance. The token that's going to have to be provided to the remote service is something I have little influence over. But that doesn't mean I can't influence the token that lands inside the agent's environment. I can issue a placeholder token to the agent, and force it to communicate via a proxy that swaps out the placeholder for the real thing. The worst the agent can do is exfiltrate the placeholder token, and as long as malicious actors don't have access to that proxy, it doesn't matter - nobody else can do anything with the placeholder.
This isn't a terribly novel insight, and it seems like almost everybody has reinvented this on their own. But a lot of these implementations involve you somehow obtaining the real token in advance and then pasting that into something that generates a placeholder that you provide to your agent environment somehow, and it's all a bit clunky and awkward, and it also means that you need to deal with something that keeps track of the mapping between placeholders and real tokens and oh no we've just invented a secret store, and if you want this to work at scale and reliably you're just invented a high availability distributed secret store, and a lot of people who've read that are now shaking their heads and reaching for gin. Can we simplify this, and improve security at the same time? I think we can!
Remember when I said "as long as malicious actors don't have access to that proxy, it doesn't matter"? What if they do? What if they compromise one machine inside your environment and are then able to email a bunch of employees and convince their agents to send more tokens back to them and then delete the email before a human reads it? Now you have someone inside the wall with access to those tokens, and presumably with access to the proxy, and now they can be anyone whose agent was gullible enough to think sending them a token was a good idea. This isn't good!
So, I thought for a while, and I came up with a new idea. We can have a broker service that obtains credentials for us. We can run that centrally, away from the agents. A client in an agentic environment can request a token, and that can result in a URL being generated and the user being directed to open a URL in a browser and authenticate. When the user authenticates, the authentication flow redirects the confirmation back via the broker, and the broker obtains the real auth token. The obvious thing to do now would be to return the auth token to the client in the agentic environment, but we don't do that. Instead, we mint a new JWT, and add a new claim - one that contains an encrypted copy of the token. In the process we can copy over all the original claims, because those aren't secret - and now even if the client inspects the token to figure out what access it has, it'll get a correct answer. We sign the new token with our own signing key, and pass that back to the client. The client now has a legitimate JWT that is utterly useless, because the signature isn't trusted by anyone other than us.
How does it use it? It makes an API request via a proxy, including the new token in the Authorization: header. The proxy verifies the signature on the token, and then decrypts the original token and swaps out the fake token for the real one. The remote API sees what it expects, and everyone is happy. There's never a real token in the agentic environment, but also we don't need to store anyting anywhere. The only state is the encryption keys, and those can be injected into the environment at startup. You need to scale? Just start more of these processes. You need to support multiple availability zones? Just start more of these processes in different places. No persistent data is ever held in the broker or the proxy. You don't need to care about distributed databases or secret stores.
This felt wonderfully elegant and I felt smug about coming up with a better idea, and then I went to a bar earlier this week and sat down to read RFC 8705 and the guy next to me saw that over my shoulder and asked what I was reading and I explained why I was interested and we talked about agentic identity and then he mentioned that fly.io had something that sounded very similar and I read that and gosh yes it is very similar, so damn you fly.io for stealing my ideas 3 years before I even had them. Anyway. Now I need to do better.
Remember that there's still a risk around anyone who has access to the proxy having access to the encrypted keys? We can remove that risk as well. It's not uncommon for agentic environments to have an identity issued via something like SPIFFE, at which point they have a client certificate. You can probably guess where I'm going with this. If we require that an agent present a client cert to the broker when requesting a token, we can embed a representation of that client cert into the token we mint. The proxy can then require mTLS for the client connection, and can verify that the presented certificate matches the one represented in the token. If it does then whoever's using the token has access to the private key associated with the environment it was issued to. If we then ensure that the private keys backing these certificates are either hardware or hypervisor backed, and as such tied to a specific instance, we now have a high degree of confidence that the token can only be used in its intended environment. Even if our identity provider doesn't support RFC 8705, we can.
This is fairly straightforward where you're using a platform where your identity provider is also the environment that's consuming your tokens, and more annoying for third parties. The broker potentially needs some amount of third party vendor knowledge to make that work for everyone. This is even more the case where login isn't via your identity provider (thanks, github), but none of this is insurmountable - just annoying. And where vendors issue opaque tokens rather than JWTs, this still isn't a problem; we can just mint a new JWT that includes the opaque token as an encrypted claim, and include the same certificate binding. The opaque token ends up being the thing that's presented to the third party, but only after we've verified the mTLS binding.
In an ideal world none of this would be necessary - someone would spin up a new agentic environment, a user would prove their identity, and a certificate embodying that identity would be issued to the environment with a private key that can't be exfiltrated. That certificate would be sufficient to obtain new certificates associated with the same private key, and we could still bind that into mTLS identity. This would be much simpler, but browsers don't support it, so it's not likely to happen any time soon.
Anyway. Even if we can't have the best thing, we can do better than we are at the moment, and also it would be lovely if we could standardise on this rather than have everyone build their own thing. The end.
03 Jul 2026 12:38am GMT
02 Jul 2026
Kernel Planet
Matthew Garrett: Preventing token theft
When you log into a service you're given an authentication token. Each further request to the site includes that token, allowing the server to figure out who you are and ensuring that you have access to your data. Depending on site policy, this token may either be stored in memory (and so vanish if you restart your browser) or disk. The token is the proof of your identity. As far as the site is concerned, anyone with your token is you. These tokens may be traditional browser cookies, but they may also be stored in either site local storage or (if you're not using a browser) in some other storage location.
In recent years we've seen infostealer malware (like LummaC2) gain the ability to exfiltrate user tokens, allowing attackers to gain access to the user's data without needing to retain access to the user's machine. This attack is viable even if the site has strong MFA requirements, so passkeys don't help. Encrypting the tokens on disk doesn't prevent the malware from scraping them out of the browser's RAM or obtaining whatever key is used to encrypt them. This feels like a pretty hard problem to solve.
But that hasn't stopped people from trying! Dirk Balfanz wrote an IETF draft describing a mechanism for using self-signed certificates for TLS authentication. This uses the mutual authentication feature of the TLS protocol that requires both sides prove their identity to each other. In regular TLS, the remote site presents a signed certificate that tells you who it is. When performing mutual authentication, you then present a certificate to the remote site telling it who you are. These client certificates are largely unused outside enterprise environments because they're a huge pain to deploy. It's not so much that this has sharp edges, it's that it's entirely made of sharp edges. Managing certificate deployment to your devices is hard. Browsers get confused if the certificates change under them. You have one certificate and it lives forever, so sites you present it to can track your identity. Users are prompted to choose a certificate to authenticate with, and if they pick the wrong one everything breaks and is hard to recover. I've deployed this and I did not have a good time.
But Balfanz's idea was simple. Rather than require certificates to be deployed, browsers would simply generate a certificate on the fly. The goal wasn't to prove the device or user's identity in any global way - but it would associate a TLS session with a specific certificate. You could then, for example, include a hash of the certificate in the cookie, and if someone tried to use that cookie without presenting that certificate then the cookie could be rejected. If the browser used a hardware-backed private key for the certificate then it would be impossible for an attacker to steal it. Sure, you could still steal cookies, but you wouldn't be able to use them.
This was written almost 15 years ago, and seems simple, elegant, and functional. It didn't happen. Part of the reason for that is that, well, it wasn't quite so simple. One problem was privacy related. Cookies are only sent after the TLS session is established, so anyone monitoring the network doesn't know anything about the user identity. A naive implementation of this approach would have meant the client certificate being sent before session establishment, and now user identity can be tracked (no longer an issue if this was implemented on top of TLS 1.3, but this was a log time ago). This was avoided by reordering the client handshake, but that meant having to modify the TLS specification and implementations would have to be updated to support this. Another was that figuring out the granularity of the certificates was difficult. You'd want to use different certificates for every site to avoid them effectively becoming tracking cookies, but you need to provide the certificate before cookies are set, and you don't know what origin the site is going to set in its cookies. If you generate a certificate for a.example.com and a different one for b.example.com, and a.example.com sets a cookie for *.example.com and includes the certificate you used for a.example.com, that cookie isn't going to work on b.example.com and things are broken. This meant supporting it wasn't as straightforward as it seemed - you'd need to ensure that your cookie scope was compatible with the certificate scope. You could probably make this work well enough by aligning it with the Public Suffix List, but there was still some risk of expectations not being aligned.
And, perhaps most importantly, TLS session resumption (replaced by pre-shared keys in TLS 1.3) somewhat defeats the purpose of the exercise - clients store state that allows them to re-establish a TLS connection without performing certificate exchange (this reduces overhead if a connection gets interrupted or you switch to a new network or anything along those lines), and anyone in a position to steal cookies could steal that state as well.
The followup attempt was channel IDs. This simplified the implementation somewhat - rather than certificates, a raw public key would be sent, along with proof of possession of the private key in the form of a signature over a portion of the TLS handshake. This was required even in the event of session resumption, which avoided having to worry about theft of session secrets. The timing of the exchange was after the encrypted session had been established, so user identity couldn't be leaked that way either. Cookies could then be bound to this identifier. Unfortunately it didn't really deal with the problem of scoping keys in a way that would match cookie requirements, and the spec suggests that the right way of handling this is to scope keys to TLDs, which would enable user tracking across sites (Chrome's implementation apparently restricted it to eTLD+1, which would match the third party cookie policy and avoid the tracking risk).
Chrome added support for this, but it was removed in early 2018. The discussion of some of the pain points in that message is interesting, explicitly calling out problems with connection coalescing across domains and the incompatibility with zero-RTT TLS1.3. The overall consensus at the time seems to be that trying to solve this entirely at the TLS layer has too many rough edges, and a different approach should be taken.
And so almost 7 years after the initial draft for origin bound certificates, we come to token binding. This ended up being a rather more complex endeavour, covering 3 different RFCs describing how it impacts TLS, how to incorporate it into HTTP, and how to manage all the various parties involved in the process. The short version is that it's pretty similar to channel ID, except that there's also a documented mechanism for allowing tokens to be bound to one party and consumed by another, avoiding any need for widely scoped keys. Token binding effectively solved all the issues in the original proposal, but at the cost of somewhat more complexity.
The RFC was finalised in October 2018. Chrome removed its (incomplete, draft) support for token binding in November 2018. Edge carried support until late 2024. Despite getting all the way through the RFC process, it's functionally dead.
The process up until this point had been largely initiated by Google, with Microsoft contributing significantly to the token binding standards. The work had been focused on identifying a generic solution to the problem rather than tying it to any specific authentication flow. The next step was in a different direction - rather than trying to fix this for the entire internet, how about we try to fix it for OAuth?
RFC 8705 is titled "OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens". This is basically the 2011 approach, but (a) with an explicit definition of how the certificate should be incorporated into issued auth cookies, and (b) with a proviso that well uh if you're going to use tokens issued by your IdP to authenticate to someone else then well you're going to need to use the same cert for both. This is probably fine for the company-owned-laptop case where you're actually fine with multiple sites being able to tie identities together (that's kind of the point here!), and also works for "I am using an app and not a browser", but doesn't work for more generic scenarios. It also doesn't seem to take the session resumption case into account at all? Support for RFC8705 seems poor, as far as I can tell of the big players only Auth0 implements it. In theory it works fine with self-signed client certs but in reality that's going to be almost as difficult to support across multiple platforms as just issuing proper client certs in the first place, so deployment is going to be kind of a pain. But the good news is it doesn't rely on any TLS extensions or custom browser behaviour, so at the client side it works fine with any browser.
Which brings us on to RFC 9449, "Demonstrating Proof of Possession". This goes even further than RFC8705 in terms of reducing the burden of deployment - it works fine with existing browsers, and it doesn't even require any certs. The client generates a keypair and provides the pubkey when requesting the cookie. The cookie contains the pubkey. Every request to the service now provides the cookie with the pubkey and also provides a signature over the URI and HTTP method. If the signature matches the pubkey in the token then clearly the signature came from the machine the token was issued to, and everything is good.
This does come with some downsides, though. The first is that it uses browser interfaces to generate the keys (typically crypto.subtle.generatekey()) and as far as I can tell there are no browsers that guarantee that that key is going to be generated in hardware even if it's marked non-exportable, so anyone able to steal the cookies can also steal the keys. The second is that the signature only covers the URI and HTTP method, and not the message content or any other headers, so anyone able to exfiltrate a valid signature can replay it against the same URI with different message content. The recommended way to handle this is to reject any signatures that weren't generated within the last few seconds, which is a wonderful additional way to allow clock skew to give you a Bad Day. And the third is that every single request has to be separately signed, which is not intrinsically a problem because computers are fast and have multiple cores, but if you're trying to solve the first problem by sticking the key in a TPM then you're dealing with something that's slow and single threaded and that's maybe acceptable if you're using client certificates (because there's going to be one signature per session and you can use the same session for multiple requests) but probably not if you're dealing with a user opening a browser that restores previous tabs and each of those is a webapp that fires off 100 requests in parallel.
In case it wasn't clear, I don't like DPoP. It doesn't feel like it actually solves the underlying problem that we see in the real world (malware running in a context where if it can grab the tokens it can grab the keys), it adds a massive amount of overhead, and it has baked in replay vulnerabilities. I don't know why it exists and I'm incredibly suspicious of vendors telling me that it fixes my problems, because if they're telling me that then I'm going to end up assuming that they either don't understand my problems or they don't understand their technology, and neither of those is good.
Still. Then we get to the thing that prompted me to write this - Chrome's announcement that they had launched device-bound session credentials. This is interesting because it's a Chrome feature that's explicitly intended to counter on-device malware, which was one of the things that was out of scope in 2018 when token binding was being removed. Since this is entire web level it doesn't have to be an RFC, and so is instead defined by W3C. I'm going to handwave all the complexity and say that it's basically a way to register a public key when a cookie is issued, and then prove possession of the private key when it's time to renew the cookie. By making the cookies shortlived and having support for rotating them in the background, user impact is basically zero and while it's still possible for an attacker to exfiltrate and use a cookie they'll only be able to do so for a short window before it needs to be refreshed - something the attacker can't do, since they don't have the private key. This avoids the DPoP overhead because you only need to do signing once per cookie per cookie lifetime, and not on every single request. I don't like this due to the window where exfiltrated tokens can be used, but it feels like a strict improvement over the status quo. An extension called device-bound session credentials for enterprise allows pre-enrollment of device keys, so even though the actual runtime DBCE flow doesn't involve certificates, certificates can be used for device registration in enterprise environments and you can make sure that auth cookies only go to trusted devices. Unfortunately this is Chrome-only, and so we're going to need to wait for it to be backported to all the random app frameworks for it to have widespread support on mobile or for almost everyone's desktop app that's actually three websites in an Electron wrapper. Mozilla's current position is that they're not in favour of it, so I guess we'll see where Safari lands in terms of broad uptake.
The last thing on my list is another client cert/OAuth binding, this one still in draft state at the time of writing. This one is aimed primarily at the use of agent-driven tooling, where you have something running in the background using a whole bunch of tools that are each acting on your behalf. Authenticating to all of them separately isn't a fun time, but giving broadly scoped access tokens to a non-deterministic agent and trusting that it'll never post them somewhere public also isn't a fun time. The key distinction between it and RFC8705 is that it's aimed at connections rather than sessions, which avoids the worries about session resumption. This is done with TLS Exporters, which in TLS 1.3 should be unique to the connection even over session resumption (TLS 1.2 may reuse some of the same key material for exporters over session resumption, so it's recommended to enforce 1.3 for this). By providing a new signature alongside the cookie on every new connection, the client proves that it still has access to the private key. This is a very new spec and I haven't had much time to work through it yet, but my naive understanding is that unlike RFC8705 this would require some additional client support to be able to regenerate the client signature on every TLS reconnection.
This doesn't avoid all the problems that RFC8705 has, including how to scope certificates. For the agentic use case that probably doesn't matter - all these tools are acting on behalf of the same user, it's fine if all the sites involved know they're the same user. But it doesn't solve the general purpose user use case, and right now DBSC seems like the best we have there.
But. Part of me still wonders whether Dirk Balfanz's approach was the right one. Yes, there's risk associated with TLS session resumption, but in the worst case you could just switch that off for high risk setups. The cookie scope argument is real, and also in cases where it could violate privacy the site owner could already choose to broaden their cookie scope and violate your privacy, and in cases where it breaks things you could just not make use of it. The other problems are largely fixed by TLS 1.3, and then we're just left with "Browsers handle client certificates badly" to which my answer is "Yes, and we should fix that anyway".
Despite having a pretty good answer to this solution over a decade ago, the closest we have to actual deployment is something that offers strictly worse security guarantees. And tokens keep getting stolen, and compromises keep occurring, and for the most part people shrug and get on with things.
02 Jul 2026 2:23am GMT
04 Jun 2026
Kernel Planet
Dave Airlie (blogspot): Appearing on the Software Engineering Radio Podcast
Software Engineering Radio is a podcast for people in IT/development with over 700 episodes across many topics over 20 years. They haven't touched on the Linux kernel much. I was invited on as part of my role at Red Hat as a Distinguished Engineer, but the podcast is really an insight into kernel maintenance, in graphics and beyond, touching on the scope and scale of the project.
It was my first time to record something that wasn't just me talking at a conference/meetup, and it was all very professional, with sound checks and brainstorming before hand.
The content is at a pretty broad and introductory level. We talked about kernel development processes, maintenance processes, and we touch on rust in the kernel a bit. It's mostly about the sheer size and scale of the project and how Linus releases things, how trees get to Linus and how the GPU work is done.
Hopefully you enjoy listening to it!
[1] https://se-radio.net/2026/06/se-radio-723-dave-airlie-on-linux-kernel-maintenance/
04 Jun 2026 12:05am GMT
01 Jun 2026
Kernel Planet
Linux Plumbers Conference: All Microconferences have now been accepted!
Hello Linux Plumbers community!
All Microconferences have now been accepted. Please go ahead and take a look at them and if you find something you would like to discuss, please submit a contribution. To do so, go to the Call for Proposals page, select the Submit new abstract button, add your discussion topic and submit. Make sure to select the proper Microconference in the Track field.
It is also a good idea to read the blog about The Ideal Microconference Topic Submission to understand what is expected of a microconference topic.
01 Jun 2026 8:25pm GMT
06 Apr 2026
Kernel Planet
Linux Plumbers Conference: Changes to Registration Availability for 2026
As most of you are painfully aware, Linux Plumbers Conference registrations can run out very fast (yes, we got lots of complaints last year). This year, we're taking a couple of steps to alleviate the issue. Firstly, we're expanding the venue size in Prague to match the number of attendees we got in Vienna (800) which will hopefully mean we have more than enough places to keep registration open all the way up to the beginning of the conference. Secondly, we're going to have an pre-registration period starting two weeks before general registration opens for anyone who submits content. The way this will work is that if you submit anything via indico before general registration opens, you'll receive a voucher and instructions to participate (this applies to every track and MC submission regardless of the accept/reject or pending state). The cost will be the same as general registration (US$600) but you'll be under no obligation to take up the voucher, which will expire when general registration opens. We're aligning the acceptance/rejection notices of the tracks we directly control (Refereed and Kernel Summit) to be complete around the time we open pre-registration. However, for other tracks and MC submissions that aren't aligned, if you take up an early registration voucher but are subsequently offered a free pass, we'll refund it (although if your company pays, we'd appreciate not having to since cvent charges us).
As a reminder of free pass distribution: every accepted Track Speaker (Refereed, Kernel Summit, Net, BPF and Toolchain) gets a free pass. However, Microconferences operate differently and accepted Microconference discussion leads may not receive a free pass (Microconferences have two free passes each and can distribute them arbitrarily to encourage key attendees).
The anticipated date for the opening of pre-registration is Friday 10 July 2026 (with the first day of general registration being 24 July), but remember this may change due to logistical problems with the cvent website (which we don't control).
06 Apr 2026 4:13pm GMT
01 Apr 2026
Kernel Planet
Dave Airlie (blogspot): drm subsystem contributor numbers
I'm doing a podcast recording this week, so I wanted to run some numbers so I could have some facts rather than feels. It turns out my feels were off by a factor of 3 or so.
If asked, I've always said the contributor count to the drm subsystem is probably in the 100 or so developers per release cycle.
Did the simplest:
git log --format='%aN' v6.14..v6.15 drivers/gpu/drm/ include/uapi/drm/ include/drm/ | sort -u | wc -l
Iterated over a few kernel releases
v6.15 326
v6.16 322
v6.17 300
v6.18 334
v6.19 332
v7.0-rc6 346
The number for the complete kernel in those scenarios are ~2000 usually, which means drm subsystem has around 15-16% of the kernel contributors.
I'm a bit spun out, that's quite a lot of people. I think I'll blame Sima for it. This also explains why I'm a bit out of touch with the process problems other maintainers have, and when I say stuff like a lot of workflows don't scale, this is what I mean.
01 Apr 2026 8:59pm GMT
Matthew Garrett: Self hosting as much of my online presence as practical
Because I am bad at giving up on things, I've been running my own email server for over 20 years. Some of that time it's been a PC at the end of a DSL line, some of that time it's been a Mac Mini in a data centre, and some of that time it's been a hosted VM. Last year I decided to bring it in house, and since then I've been gradually consolidating as much of the rest of my online presence as possible on it. I mentioned this on Mastodon and a couple of people asked for more details, so here we are.
First: my ISP doesn't guarantee a static IPv4 unless I'm on a business plan and that seems like it'd cost a bunch more, so I'm doing what I described here: running a Wireguard link between a box that sits in a cupboard in my living room and the smallest OVH instance I can, with an additional IP address allocated to the VM and NATted over the VPN link. The practical outcome of this is that my home IP address is irrelevant and can change as much as it wants - my DNS points at the OVH IP, and traffic to that all ends up hitting my server.
The server itself is pretty uninteresting. It's a refurbished HP EliteDesk which idles at 10W or so, along 2TB of NVMe and 32GB of RAM that I found under a pile of laptops in my office. We're not talking rackmount Xeon levels of performance, but it's entirely adequate for everything I'm doing here.
So. Let's talk about the services I'm hosting.
Web
This one's trivial. I'm not really hosting much of a website right now, but what there is is served via Apache with a Let's Encrypt certificate. Nothing interesting at all here, other than the proxying that's going to be relevant later.
Inbound email is easy enough. I'm running Postfix with a pretty stock configuration, and my MX records point at me. The same Let's Encrypt certificate is there for TLS delivery. I'm using Dovecot as an IMAP server (again with the same cert). You can find plenty of guides on setting this up.
Outbound email? That's harder. I'm on a residential IP address, so if I send email directly nobody's going to deliver it. Going via my OVH address isn't going to be a lot better. I have a Google Workspace, so in the end I just made use of Google's SMTP relay service. There's various commerical alternatives available, I just chose this one because it didn't cost me anything more than I'm already paying.
Blog
My blog is largely static content generated by Hugo. Comments are Remark42 running in a Docker container. If you don't want to handle even that level of dynamic content you can use a third party comment provider like Disqus.
Mastodon
I'm deploying Mastodon pretty much along the lines of the upstream compose file. Apache is proxying /api/v1/streaming to the websocket provided by the streaming container and / to the actual Mastodon service. The only thing I tripped over for a while was the need to set the "X-Forwarded-Proto" header since otherwise you get stuck in a redirect loop of Mastodon receiving a request over http (because TLS termination is being done by the Apache proxy) and redirecting to https, except that's where we just came from.
Mastodon is easily the heaviest part of all of this, using around 5GB of RAM and 60GB of disk for an instance with 3 users. This is more a point of principle than an especially good idea.
Bluesky
I'm arguably cheating here. Bluesky's federation model is quite different to Mastodon - while running a Mastodon service implies running the webview and other infrastructure associated with it, Bluesky has split that into multiple parts. User data is stored on Personal Data Servers, then aggregated from those by Relays, and then displayed on Appviews. Third parties can run any of these, but a user's actual posts are stored on a PDS. There are various reasons to run the others, for instance to implement alternative moderation policies, but if all you want is to ensure that you have control over your data, running a PDS is sufficient. I followed these instructions, other than using Apache as the frontend proxy rather than nginx, and it's all been working fine since then. In terms of ensuring that my data remains under my control, it's sufficient.
Backups
I'm using borgmatic, backing up to a local Synology NAS and also to my parents' home (where I have another HP EliteDesk set up with an equivalent OVH IPv4 fronting setup). At some point I'll check that I'm actually able to restore them.
Conclusion
Most of what I post is now stored on a system that's happily living under a TV, but is available to the rest of the world just as visibly as if I used a hosted provider. Is this necessary? No. Does it improve my life? In no practical way. Does it generate additional complexity? Absolutely. Should you do it? Oh good heavens no. But you can, and once it's working it largely just keeps working, and there's a certain sense of comfort in knowing that my online presence is carefully contained in a small box making a gentle whirring noise.
01 Apr 2026 2:35am GMT
23 Mar 2026
Kernel Planet
Linux Plumbers Conference: Submission time for Linux Plumbers 2026
Submissions for the Refereed Track, Kernel Summit, BoF and Microconferences are now open. Linux Plumbers will be held this year in Prague, Czechia from October 5-7th.
The Refereed presentations are 45 minutes in length (Talk+Q&A) and should focus on a specific aspect of the "plumbing" in a Linux ecosystem. Examples of Linux plumbing include core kernel subsystems, init systems, core libraries, toolchains, windowing systems, management tools, device support, media creation/playback, testing, and so on. The best presentations are not about finished work, but rather problem statements, proposals, or proof-of-concept solutions that require face-to-face discussions and debate.
The Kernel Summit track is divided into sessions of 45 minutes. Sessions may be focused on the discussion of specific Linux kernel topics which can be better resolved in person than over e-mail. The program committee will also consider "information sharing" topics if they are clearly of interest to the wider development community (i.e., advanced training in topics that would be useful to kernel developers). In addition to submitting proposals to the Linux Plumber website, please also send a copy of the proposal as an e-mail to the ksummit@lists.linux.dev mailing list with a subject prefix of [TECH TOPIC].
The Microconferences are 3 and a half hours of technical discussion, broken up into 15 to 30 minute subtopics. The only presentations allowed are those that are needed to bring the audience up to speed and should not last more than half the allotted time for the subtopic. To submit a Microconference, provide a topic, some examples of subtopics to be discussed and a list of key people that should be present to have meaningful discussions. For Microconferences that have been to Linux Plumbers in the past, they should provide a list of accomplishments that were a direct result of the discussions from their previous sessions (with links to patches and such).
Presenters and Microconference subtopic leads should be physically present at the conference. Remote presentations will be allowed strictly on an emergency basis.
The Microconference Track submissions end at 11:59PM UTC on Thursday, April 23, 2026, submissions for subtopics within a Microconference will open shortly after the Microconference has been fully accepted.
The Refereed Track and Kernel Summit submissions end at 11:59PM UTC on Sunday, June 28, 2026.
Please submit your Refereed Track, Kernel Summit, BoF or Microconference topic. We are looking forward to seeing the great content that is submitted that makes Linux Plumbers the best technical conference there is.
23 Mar 2026 8:51pm GMT
21 Mar 2026
Kernel Planet
Matthew Garrett: SSH certificates and git signing
When you're looking at source code it can be helpful to have some evidence indicating who wrote it. Author tags give a surface level indication, but it turns out you can just lie and if someone isn't paying attention when merging stuff there's certainly a risk that a commit could be merged with an author field that doesn't represent reality. Account compromise can make this even worse - a PR being opened by a compromised user is going to be hard to distinguish from the authentic user. In a world where supply chain security is an increasing concern, it's easy to understand why people would want more evidence that code was actually written by the person it's attributed to.
git has support for cryptographically signing commits and tags. Because git is about choice even if Linux isn't, you can do this signing with OpenPGP keys, X.509 certificates, or SSH keys. You're probably going to be unsurprised about my feelings around OpenPGP and the web of trust, and X.509 certificates are an absolute nightmare. That leaves SSH keys, but bare cryptographic keys aren't terribly helpful in isolation - you need some way to make a determination about which keys you trust. If you're using someting like GitHub you can extract that information from the set of keys associated with a user account1, but that means that a compromised GitHub account is now also a way to alter the set of trusted keys and also when was the last time you audited your keys and how certain are you that every trusted key there is still 100% under your control? Surely there's a better way.
SSH Certificates
And, thankfully, there is. OpenSSH supports certificates, an SSH public key that's been signed by some trusted party and so now you can assert that it's trustworthy in some form. SSH Certificates also contain metadata in the form of Principals, a list of identities that the trusted party included in the certificate. These might simply be usernames, but they might also provide information about group membership. There's also, unsurprisingly, native support in SSH for forwarding them (using the agent forwarding protocol), so you can keep your keys on your local system, ssh into your actual dev system, and have access to them without any additional complexity.
And, wonderfully, you can use them in git! Let's find out how.
Local config
There's two main parameters you need to set. First,
|
|
because unfortunately for historical reasons all the git signing config is under the gpg namespace even if you're not using OpenPGP. Yes, this makes me sad. But you're also going to need something else. Either user.signingkey needs to be set to the path of your certificate, or you need to set gpg.ssh.defaultKeyCommand to a command that will talk to an SSH agent and find the certificate for you (this can be helpful if it's stored on a smartcard or something rather than on disk). Thankfully for you, I've written one. It will talk to an SSH agent (either whatever's pointed at by the SSH_AUTH_SOCK environment variable or with the -agent argument), find a certificate signed with the key provided with the -ca argument, and then pass that back to git. Now you can simply pass -S to git commit and various other commands, and you'll have a signature.
Validating signatures
This is a bit more annoying. Using native git tooling ends up calling out to ssh-keygen2, which validates signatures against a file in a format that looks somewhat like authorized-keys. This lets you add something like:
|
|
which will match all principals (the wildcard) and succeed if the signature is made with a certificate that's signed by the key following cert-authority. I recommend you don't read the code that does this in git because I made that mistake myself, but it does work. Unfortunately it doesn't provide a lot of granularity around things like "Does the certificate need to be valid at this specific time" and "Should the user only be able to modify specific files" and that kind of thing, but also if you're using GitHub or GitLab you wouldn't need to do this at all because they'll just do this magically and put a "verified" tag against anything with a valid signature, right?
Haha. No.
Unfortunately while both GitHub and GitLab support using SSH certificates for authentication (so a user can't push to a repo unless they have a certificate signed by the configured CA), there's currently no way to say "Trust all commits with an SSH certificate signed by this CA". I am unclear on why. So, I wrote my own. It takes a range of commits, and verifies that each one is signed with either a certificate signed by the key in CA_PUB_KEY or (optionally) an OpenPGP key provided in ALLOWED_PGP_KEYS. Why OpenPGP? Because even if you sign all of your own commits with an SSH certificate, anyone using the API or web interface will end up with their commits signed by an OpenPGP key, and if you want to have those commits validate you'll need to handle that.
In any case, this should be easy enough to integrate into whatever CI pipeline you have. This is currently very much a proof of concept and I wouldn't recommend deploying it anywhere, but I am interested in merging support for additional policy around things like expiry dates or group membership.
Doing it in hardware
Of course, certificates don't buy you any additional security if an attacker is able to steal your private key material - they can steal the certificate at the same time. This can be avoided on almost all modern hardware by storing the private key in a separate cryptographic coprocessor - a Trusted Platform Module on PCs, or the Secure Enclave on Macs. If you're on a Mac then Secretive has been around for some time, but things are a little harder on Windows and Linux - there's various things you can do with PKCS#11 but you'll hate yourself even more than you'll hate me for suggesting it in the first place, and there's ssh-tpm-agent except it's Linux only and quite tied to Linux.
So, obviously, I wrote my own. This makes use of the go-attestation library my team at Google wrote, and is able to generate TPM-backed keys and export them over the SSH agent protocol. It's also able to proxy requests back to an existing agent, so you can just have it take care of your TPM-backed keys and continue using your existing agent for everything else. In theory it should also work on Windows3 but this is all in preparation for a talk I only found out I was giving about two weeks beforehand, so I haven't actually had time to test anything other than that it builds.
And, delightfully, because the agent protocol doesn't care about where the keys are actually stored, this still works just fine with forwarding - you can ssh into a remote system and sign something using a private key that's stored in your local TPM or Secure Enclave. Remote use can be as transparent as local use.
Wait, attestation?
Ah yes you may be wondering why I'm using go-attestation and why the term "attestation" is in my agent's name. It's because when I'm generating the key I'm also generating all the artifacts required to prove that the key was generated on a particular TPM. I haven't actually implemented the other end of that yet, but if implemented this would allow you to verify that a key was generated in hardware before you issue it with an SSH certificate - and in an age of agentic bots accidentally exfiltrating whatever they find on disk, that gives you a lot more confidence that a commit was signed on hardware you own.
Conclusion
Using SSH certificates for git commit signing is great - the tooling is a bit rough but otherwise they're basically better than every other alternative, and also if you already have infrastructure for issuing SSH certificates then you can just reuse it4 and everyone wins.
-
Did you know you can just download people's SSH pubkeys from github from
https://github.com/<username>.keys? Now you do ↩︎ -
Yes it is somewhat confusing that the
keygencommand does things other than generate keys ↩︎ -
This is more difficult than it sounds ↩︎
-
And if you don't, by implementing this you now have infrastructure for issuing SSH certificates and can use that for SSH authentication as well. ↩︎
21 Mar 2026 7:38pm GMT
