From 6f3c1e93c7f76944b135e3cb64c96666377d4208 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Thu, 13 Aug 2026 19:15:47 +0530 Subject: [PATCH 1/2] =?UTF-8?q?docs:=20correct=20not=5Fenforced=20?= =?UTF-8?q?=E2=80=94=20the=20default=20is=20now=20deny,=20not=20user-alone?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit agent-identity.md contradicted itself: the callout at the top says a delegated check against a model with no `type agent` is now denied, while the observability table two screens down still said it is "authorized as the user alone". metrics-monitoring.md carried the same stale line. Both now describe what the outcome actually means, which depends on --fga-allow-unconstrained-agents: unset it is a denial (a misconfiguration users will report as a broken integration), set it is the old unconstrained behaviour (exposure with a clock on it). Same remedy either way. --- docs/core/metrics-monitoring.md | 5 ++++- docs/enterprise/agent-identity.md | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/core/metrics-monitoring.md b/docs/core/metrics-monitoring.md index 9c18810..9dbe5df 100644 --- a/docs/core/metrics-monitoring.md +++ b/docs/core/metrics-monitoring.md @@ -170,7 +170,10 @@ The `outcome` label is what makes an intersection denial diagnosable: This is the Confused Deputy being stopped. Do **not** widen the agent; it cannot help, and the user genuinely lacks access. - **`not_enforced`** — a delegated caller arrived but the active model declares - no `agent` type, so the request was authorized as the **user alone**. + no `agent` type, so the agent half of the intersection could not be evaluated. + By default the check is **denied**; with `--fga-allow-unconstrained-agents` + set it is authorized as the **delegating user alone**, with the agent + unconstrained. Only `check_permissions` emits `allowed` / `denied_by_agent` / `denied_by_user`. `list_permissions` intersects object *sets* rather than folding a per-check diff --git a/docs/enterprise/agent-identity.md b/docs/enterprise/agent-identity.md index 92906aa..a696120 100644 --- a/docs/enterprise/agent-identity.md +++ b/docs/enterprise/agent-identity.md @@ -222,9 +222,21 @@ Without this an agent's actions are indistinguishable from the user's own — sa | `allowed` | both halves permitted | — | | `denied_by_agent` | the agent has no grant; the user may well have access | grant the **agent** a tuple | | `denied_by_user` | the agent had its grant, the user does not have access | **do not** widen the agent — this is the Confused Deputy case working as intended | -| `not_enforced` | a delegated caller arrived but the model declares no `agent` type, so it was authorized as the **user alone** | declare `type agent` and grant your agents | +| `not_enforced` | a delegated caller arrived but the model declares no `agent` type, so the agent half could not be evaluated | declare `type agent` and grant your agents | -`not_enforced` is the one to alert on: it is the only outcome that reports a security property *not* being enforced, and it is silent by construction — the request succeeds and nothing in the response says the agent was unconstrained. +`not_enforced` is the one to alert on, and it means one of two things depending +on [`--fga-allow-unconstrained-agents`](#turning-it-on): + +- **Default (flag unset):** the check was **denied**. Agents are failing against + a model that cannot express agent grants — a misconfiguration, not an attack. + Users will report it as a broken integration; this counter tells you why. +- **Flag set:** the check was authorized as the **delegating user alone**, with + the agent unconstrained. That is silent by construction — the request + succeeds and nothing in the response says so. Treat a non-zero rate here as + exposure with a clock on it, not a steady state. + +Either way the remedy is the same: add `type agent` to the model and grant the +agents. `allowed`, `denied_by_agent` and `denied_by_user` are emitted by **`check_permissions` only**. `list_permissions` intersects object *sets* From 4123f0a7a0c0465d0d94cfcfa8152dca5ddbaf75 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Thu, 13 Aug 2026 19:16:49 +0530 Subject: [PATCH 2/2] docs(mcp): fix the self-registering-clients anchor The heading is 'Self-registering clients: CIMD vs DCR', so the slug carries the suffix. Broke the build's anchor check on main. --- docs/core/mcp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/mcp.md b/docs/core/mcp.md index 38eb8dd..37c2f06 100644 --- a/docs/core/mcp.md +++ b/docs/core/mcp.md @@ -102,7 +102,7 @@ happens rather than what the specs allow. | Any client that needs to self-register | yes | Enable `--enable-client-id-metadata-document` (preferred) or `--enable-dynamic-client-registration` (RFC 7591, for clients that predate CIMD) | Both self-registration mechanisms ship in 2.4.0 and are **off by default**. Turn -on the one your client can use — see [Self-registering clients](#self-registering-clients) +on the one your client can use — see [Self-registering clients](#self-registering-clients-cimd-vs-dcr) below. The static-token path remains the simplest option when you control the client and do not want an interactive flow at all.