Re: A less-circumventable age verification protocol: good ol' files

"Jeremy Soller" <[email protected]> Tue, 10 Mar 2026 21:03:38 -0600
Newsgroups gmane.linux.xdg.devel
Message-ID <[email protected]>
Hello Daniel,

I do not agree that having the API be technically possible to circumvent is a legal issue (the word "reasonably" carries a lot of weight), or that your implementation can resolve it. I could still virtualize or emulate an operating system where I have root, even if I do not have root on the host OS.

The New York bill also seems to require age estimation, done either with biometrics or using other collected user data. I have not seen a proposal that takes this into account yet, and I hope it will be unconstitutional for the same reason the Texas bill was.

-- 
  Jeremy Soller
  System76
  Principal Engineer
  [email protected]

On Tue, Mar 10, 2026, at 8:41 PM, Daniel Tang wrote:
> I would like to propose a better way to implement age verification. The
> existing proposals fall short of the anti-circumvention requirements.
>
> The New York bill at 
> https://www.nysenate.gov/legislation/bills/2025/S8102/amendment/A says:
>
>>    1. "age assurance" shall mean any method to reasonably  determine  the
>> age  category  of  a user, using methods that reasonably prevent against
>> circumvention. such method may include a method that meets the  require-
>> ments  of article forty-five of this chapter, or may be a method that is
>> identified pursuant to  new  regulations  promulgated  by  the  attorney
>> general consistent with section fifteen hundred forty-five of this arti-
>> cle.
>
> Their first proposal was 
> https://gitlab.freedesktop.org/xdg/xdg-specs/-/merge_requests/113 .
> That was rapidly circumvented by 
> https://github.com/HaplessIdiot/ageverificationbypass/blob/main/bypassageverification.py 
> .
> Someone else's proposal was 
> https://github.com/flatpak/xdg-desktop-portal/pull/1922 .
>
> Both use D-BUS. I assert that the age verification must not use D-BUS.
> While the first circumvention might require root, a child could wrap it
> to not require root. They could just set the DBUS_SYSTEM_BUS_ADDRESS
> environment variable. Then a Python server could start listening on
> that file to falsely respond to requests.
>
> The second proposal is 535 lines of code of D-BUS verboseness. That
> feels wrong. Let's go back the Unix philosophy of "everything is a file".
>
> What I propose is a root-owned world-unwritable directory at either:
> * /etc/age-verification/$UID/ , or
> * ${XDG_RUNTIME_DIR:-/run/user/$UID}/ageverification/ , or
> * /var/lib/ageverification/$UID/
>
> /etc is trusted by sudo's authentication, and by ImageMagick's security
> blocking PDFs.XDG_RUNTIME_DIR can be better if /etc is out of scope
> for the XDG mailing list and we want dynamic updates coexisting with
> ReadonlyRoot. To prevent tampering, no directory there should be empty.
>
> Originally I considered a /etc/age/$UID or /etc/birthday/$UID file, but
> that offers less privacy. For additional privacy, each directory should
> have 0711 permissions, so accesses can be granular. Then there should
> be exactly one of the following empty regular files:
> * "under-13"
> * "13-to-15"
> * "16-to-17"
> * "18-plus"
>
> Only when a different jurisdiction enacts conflicting age intervals, we
> can discuss whether to include both.
>
> An absent directory indicates a system service or test environment.
> Each desktop environment shall be responsible for prompting existing
> users and talking to a service or setuid helper binary unless the
> CI=true environment variable is set or the UID is below 1000.
> libpam_systemd can be used to delay login until any dynamic directory
> is created.
>
> The helper should have PAM-like interactions to dynamically drive a UI
> like KDE or GNOME's current lockscreens. I originally considered
> introducing a new PAM type, but too many setups might already assume
> exactly the 4 traditional account/auth/password/session set, and I
> don't know whether PAM is convenient with Flatpak. Anyway, Flatpak
> shall be responsible that the directory is accessible and not
> overmounted inside its sandbox. The "real-time application programming
> interface" in the law can be `access(2)` on the appropriate file.
>
> Each Linux distribution shall choose what helper to run, depending
> on the local laws of its target market. It can also omit the helper, and
> lock in the age bracket set at install-time. If the helper stores the
> birthdate, it can add-then-remove files as time goes by. The
> simplicity of this file-based approach establishes clear
> responsibilities between operation system code and application code.
> A simple protocol will be implemented faster, and this speed is
> important, as mentioned in a comment in the second proposal, for LTS
> distributions.
>
> California Assembly Bill No. 1043 prohibits sharing "the digital
> signal information with a third party for a purpose not required by
> [the] title". Accordingly, https://github.com/systemd/systemd/pull/40954
> may violate it by storing the birthdate. I am not a lawyer, and this is
> not legal advice. But decopuling the birthdate from the files and
> into the helper allows different distributions to follow the differing
> opinions of their different legal counsel.
>
> The anti-circumvention should center on requiring root access.
> Reinstallation is no more of a concern than factory-resetting other
> OSes. Parents are responsible for not adding their children to the
> sudo group and adding a GRUB password. To make the anti-circumvention
> complete, other distributions could need to, like Ubuntu, restrict
> unprivileged user namespaces. The security of my whole proposal rests
> on the fact that without userns, getuid(2) cannot be remapped, and
> /etc cannot be overmounted. sudo and ImageMagick rely on this. These
> two steps provide secure attestation of the user's age range.
>
> The other proposals rest on one weak link, namely
> DBUS_SYSTEM_BUS_ADDRESS. With so many programming languages, at least
> one will have an age verification library that is vulnerable to an
> attack where it fails to unsetenv(3) or reject this envvar. LD_PRELOAD
> attacks are different and don't matter, because it's code not data, and
> injected code can turn any application into any new application, so the
> some may consider the person injecting the code to be the new legal
> developer.
>
> ~ daniel . z . tg