EVERYONE@ is reserved in both directions (L4 auth / ACL)¶
The subject-token space is opaque bytes with exactly one spelling the evaluators know:
kEveryoneSubject — "EVERYONE@". An ACE carrying it applies to every resolved subject, which
is how a vertex is opened to all comers for one right without enumerating anybody
(ADR-0020).
The half that is easy to miss is the other direction, and it is the reason this gets its own example.
What to notice¶
The wire has ONE spelling for a subject token. The ACE’s subject and the resolver’s output are the same opaque bytes — the
acl/acl-acesconformance vector sendspeer-aand the wildcard as the same opaque VALUE. So a principal that could BE those bytes would be indistinguishable from the wildcard ACE.The core refuses the resolver’s OUTPUT, rather than trusting every integrator to blacklist the string. A caller that resolves to
EVERYONE@is denied at every gate (#908). The deployments at risk are exactly the ones whose resolver passes a caller-supplied identity through — usernames, certificate CNs, peer names — which is the most ordinary resolver there is.It is refused on a BARE vertex too, and that is the discriminating case. The refusal happens before the open-by-default rule, so it is not “the wildcard subject matches no ACE”; it is “this is not a principal at all”. The example checks the bare vertex with an ordinary caller as the ablation, so the deny is not just a vertex that happened to be closed.
is_reserved_subject()is public for a reason. A resolver can refuse the token at its own door as well; the core checks it in the two places a subject reaches an ACE comparison.The wildcard grant is still one bit.
EVERYONE@withREADis notEVERYONE@with access — seeaccess_maskis a bitfield.OWNER@is not a special subject and never was. ADR-0020 named it once, no evaluator ever special-cased it, so anOWNER@ACE matched nobody while still closing the vertex it was written to delegate. The erratum (#1033) withdraws the name rather than reserving it: with no document telling an operator to write that ACE, there is nothing for an impersonatedOWNER@principal to match either. The example asserts it is an ordinary token.Nothing here is conditional — the target builds and runs under every CI leg.
Source¶
1/*
2 * SPDX-License-Identifier: Apache-2.0
3 * SPDX-FileCopyrightText: Copyright 2026 avatarsd LLC
4 */
5
6/**
7 * @file
8 * @brief ONE CONCEPT — `EVERYONE@` is the one wildcard subject, and it is RESERVED both ways.
9 *
10 * The subject-token space is opaque bytes, with exactly one spelling the evaluators know:
11 * `tr::graph::kEveryoneSubject` — `"EVERYONE@"`. An ACE carrying it applies to every resolved
12 * subject, which is how a vertex is opened to all comers for one right without enumerating
13 * anybody (ADR-0020).
14 *
15 * The half that is easy to miss is the OTHER direction. The wire has ONE spelling for a subject
16 * token: the ACE's subject and the resolver's output are the same opaque bytes. So a principal
17 * that could BE those bytes would be indistinguishable from the wildcard — and the deployments
18 * at risk are exactly the ones whose resolver passes a caller-supplied identity through
19 * (usernames, certificate CNs, peer names). The core therefore refuses to let a RESOLVED subject
20 * spell it (#908): that caller is denied at every gate, on a guarded vertex and on a bare one
21 * alike, rather than every integrator being left to know to blacklist the string.
22 *
23 * Note what the bare-vertex case means: the refusal happens BEFORE the open-by-default rule, so
24 * it is not "the wildcard subject matches no ACE" — it is "this is not a principal at all".
25 *
26 * `OWNER@` is deliberately absent. ADR-0020 named it once, no evaluator ever special-cased it,
27 * and so an `OWNER@` ACE matched nobody while still CLOSING the vertex it was written to
28 * delegate — the erratum (#1033) withdraws the name rather than reserving it.
29 *
30 * Runs under ctest as `example_acl_everyone_reserved`; returns non-zero on any failed check.
31 */
32
33#include <cstdio>
34#include <cstring>
35#include <span>
36#include <string_view>
37#include <vector>
38
39#include "libtracer/graph.hpp"
40#include "libtracer/mem_heap.hpp"
41#include "libtracer/security_acl.hpp"
42
43namespace {
44
45using tr::graph::ace_t;
46using tr::graph::acl_right_t;
47using tr::graph::graph_t;
48using tr::graph::kEveryoneSubject;
49using tr::graph::path_t;
50using tr::graph::role_t;
51using tr::graph::status_t;
52using tr::graph::subject_token_t;
53using tr::graph::vertex_handle_t;
54
55/** @brief Report expectation @p what and record a failure on @p ok. */
56void check(bool& ok, bool cond, const char* what) {
57 std::printf(" [%s] %s\n", cond ? "ok" : "FAIL", what);
58 ok = ok && cond;
59}
60
61/** @brief @p s as opaque subject-token bytes. */
62std::vector<std::byte> as_bytes(std::string_view s) {
63 std::vector<std::byte> out(s.size());
64 std::memcpy(out.data(), s.data(), s.size());
65 return out;
66}
67
68/**
69 * @brief The pass-through resolver — the shape #908 exists for.
70 *
71 * It hands back whatever the caller context said, which is what an integrator writes when the
72 * transport already authenticated a name. It is also exactly what would let a peer that managed
73 * to be called `EVERYONE@` resolve to the wildcard, so the core refuses the OUTPUT rather than
74 * trusting every such resolver to blacklist the token itself.
75 */
76std::expected<subject_token_t, tr::wire::err_t> caller_is_subject(void*, std::string_view caller) {
77 return as_bytes(caller);
78}
79
80/** @brief A one-byte VALUE. */
81tr::view::view_t some_value() {
82 const std::byte one[1] = {std::byte{0x01}};
83 return *tr::view::over_bytes(one);
84}
85
86/** @brief True iff @p r was refused by an ACL gate. */
87template <class T>
88bool denied(const tr::graph::result_t<T>& r) {
89 return !r.has_value() && r.error() == status_t::PERMISSION_DENIED;
90}
91
92} // namespace
93
94int main() {
95 bool ok = true;
96 graph_t g;
97 g.configure_subject_resolver(caller_is_subject, nullptr);
98 const vertex_handle_t guarded = g.register_vertex(path_t("/guarded"), role_t::STORED_VALUE);
99 const vertex_handle_t bare = g.register_vertex(path_t("/bare"), role_t::STORED_VALUE);
100 (void)g.write(guarded, some_value()); // trusted local seeds, so a refused READ is the
101 (void)g.write(bare, some_value()); // only way either read below can fail
102
103 // The wildcard ACE: READ for everybody, and nothing else for anybody.
104 const ace_t wildcard[] = {{.subject = as_bytes(kEveryoneSubject),
105 .access_mask = static_cast<std::uint32_t>(acl_right_t::READ)}};
106 (void)g.write(path_t("/guarded:acl"), *tr::view::over_bytes(tr::graph::encode_acl(wildcard)));
107
108 // Direction 1 — as an ACE subject, it matches every principal, named or not.
109 check(ok, g.read(guarded, "alice").has_value(), "the wildcard ACE grants READ to alice");
110 check(ok, g.read(guarded, "a-peer-nobody-enumerated").has_value(), "…and to a stranger");
111 check(ok, denied(g.write(guarded, some_value(), "alice")),
112 "…and it is still ONE bit: the wildcard granted READ, not access");
113
114 // Direction 2 — as a RESOLVED subject, it is not a principal at all.
115 check(ok, denied(g.read(guarded, kEveryoneSubject)),
116 "a caller resolving to EVERYONE@ is denied on the guarded vertex…");
117 check(ok, denied(g.read(bare, kEveryoneSubject)),
118 "…and on the BARE one too, which open-by-default would otherwise have allowed");
119 check(ok, g.read(bare, "alice").has_value(),
120 "the ablation: the bare vertex really is open to an ordinary caller");
121
122 // The same predicate, published so a resolver can refuse the token at its own door as well.
123 check(ok, tr::graph::is_reserved_subject(as_bytes(kEveryoneSubject)),
124 "is_reserved_subject() is the check, and it is public for that reason");
125 check(ok, !tr::graph::is_reserved_subject(as_bytes("OWNER@")),
126 "OWNER@ is NOT reserved and NOT special — it is an ordinary opaque token (#1033)");
127
128 std::printf("one reserved subject, %zu bytes: \"%.*s\"\n", kEveryoneSubject.size(),
129 static_cast<int>(kEveryoneSubject.size()), kEveryoneSubject.data());
130 return ok ? 0 : 1;
131}
See also: security-acl module · protocol TLVs · the subject resolver · open by default.