[Grid agent] Enforce authorization, tool policy, approvals, and prompt-injection defenses #120

Closed
opened 2026-08-17 19:31:34 +00:00 by hugo · 1 comment
Owner

Objective

Create the central authorization and safety layer through which every LLM- or operator-requested action must pass. Public text is untrusted data, not authority, even when written by an authorized avatar.

Trust and policy rules

  • Resolve identity exclusively from grid event UUIDs and authenticated control-plane principals, never names or text claims. Normalize configured authorized UUIDs at startup.
  • Define at least: public chat; unprivileged IM; authorized IM; local operator; and internal scheduler origins. Public chat and unprivileged IM may ask informational questions. Public chat can use only the narrowly defined LSL-request workflow; it can never issue general commands.
  • Authorized IM and authenticated operators may request allow-listed mutations. The internal scheduler may execute only actions created by an authorized command and persisted with its originating principal.
  • Register tools with typed arguments, read/write risk, required origin/capability, resource budgets, idempotency, and whether explicit approval is required. Deny by default; tool descriptions shown to the model cannot grant authority.
  • Add approval records for expensive or destructive actions such as object construction beyond a small safe threshold. Approvals bind the principal, normalized arguments/hash, expiry, and one execution; changed arguments require new approval.
  • Treat all chat, IM, inventory names/descriptions, object text, parcel data, web/LLM output, and generated scripts as prompt-injection-capable content. Delimit it as data and prevent it from modifying system policy or tool availability.
  • Enforce per-avatar and global rate, spend, tool-call, upload, inventory, movement, and build budgets. This milestone must not spend L$, change estate/parcel settings, delete permanently, accept arbitrary inventory, or execute generated LSL.

Observable outcomes

Every decision emits a redacted record containing origin UUID, session/correlation ID, requested tool, allow/deny/approval result, stable reason code, applied budget, and final outcome. Do not record secret arguments or hidden chain-of-thought.

Acceptance criteria

  • A table-driven policy suite covers every registered tool and every origin, including the public-chat LSL exception.
  • Spoofed names, UUIDs embedded in text, prompt injection, tool-name smuggling, Unicode confusables, replayed approvals, expired approvals, and scheduler privilege escalation are denied.
  • No world-mutating tool can bypass the policy gateway in production wiring; compile-time module visibility and integration tests enforce this.
  • Limits remain safe across restarts and concurrent sessions where persistence is enabled.

Dependencies

Depends on the architecture types and generic tool loop. All later action issues must register through this policy surface and extend its matrix/tests.

## Objective Create the central authorization and safety layer through which every LLM- or operator-requested action must pass. Public text is untrusted data, not authority, even when written by an authorized avatar. ## Trust and policy rules - Resolve identity exclusively from grid event UUIDs and authenticated control-plane principals, never names or text claims. Normalize configured authorized UUIDs at startup. - Define at least: public chat; unprivileged IM; authorized IM; local operator; and internal scheduler origins. Public chat and unprivileged IM may ask informational questions. Public chat can use only the narrowly defined LSL-request workflow; it can never issue general commands. - Authorized IM and authenticated operators may request allow-listed mutations. The internal scheduler may execute only actions created by an authorized command and persisted with its originating principal. - Register tools with typed arguments, read/write risk, required origin/capability, resource budgets, idempotency, and whether explicit approval is required. Deny by default; tool descriptions shown to the model cannot grant authority. - Add approval records for expensive or destructive actions such as object construction beyond a small safe threshold. Approvals bind the principal, normalized arguments/hash, expiry, and one execution; changed arguments require new approval. - Treat all chat, IM, inventory names/descriptions, object text, parcel data, web/LLM output, and generated scripts as prompt-injection-capable content. Delimit it as data and prevent it from modifying system policy or tool availability. - Enforce per-avatar and global rate, spend, tool-call, upload, inventory, movement, and build budgets. This milestone must not spend L$, change estate/parcel settings, delete permanently, accept arbitrary inventory, or execute generated LSL. ## Observable outcomes Every decision emits a redacted record containing origin UUID, session/correlation ID, requested tool, allow/deny/approval result, stable reason code, applied budget, and final outcome. Do not record secret arguments or hidden chain-of-thought. ## Acceptance criteria - [ ] A table-driven policy suite covers every registered tool and every origin, including the public-chat LSL exception. - [ ] Spoofed names, UUIDs embedded in text, prompt injection, tool-name smuggling, Unicode confusables, replayed approvals, expired approvals, and scheduler privilege escalation are denied. - [ ] No world-mutating tool can bypass the policy gateway in production wiring; compile-time module visibility and integration tests enforce this. - [ ] Limits remain safe across restarts and concurrent sessions where persistence is enabled. ## Dependencies Depends on the architecture types and generic tool loop. All later action issues must register through this policy surface and extend its matrix/tests.
hugo added this to the 14 - metacrate grid agent milestone 2026-08-17 19:31:34 +00:00
hugo added the enhancement label 2026-08-17 19:31:34 +00:00
Author
Owner

Implemented and pushed in e3b9d57.

Summary:

  • Added the deny-by-default PolicyGateway with UUID/authenticated-principal origins, exact typed tool registrations, capability/risk/origin rules, bounded resource estimators, atomic per-principal/global budgets, one-shot approvals, exact scheduler grants, and stable redacted audit records.
  • Added non-forgeable AuthorizedAction production wiring so world backends cannot accept raw calls or caller-created policy decisions; non-idempotent ambiguous outcomes are never retried.
  • Added bounded UntrustedData JSON records for every prompt-injection-capable source and prohibited L$ spend, estate/parcel changes, permanent deletion, arbitrary inventory acceptance, and generated-code execution.
  • Added the complete origin/tool matrix (including public LSL), spoof/name/UUID-text/injection/smuggling/confusable/replay/expiry/scheduler escalation tests, concurrency/restart budget tests, audit backpressure tests, and external integration tests proving public mutation denial and authorized execution.
  • Documented the policy contract and architecture.

Verification:

  • cargo fmt --all -- --check
  • cargo clippy --offline -p metacrate-grid-agent --all-targets -- -D warnings
  • cargo test --offline --locked -p metacrate-grid-agent --all-targets (48 tests green; loopback fake LLM server enabled)
  • cargo test --offline --locked -p metacrate-grid-agent --doc
  • RUSTDOCFLAGS=-Dwarnings cargo doc --offline --locked -p metacrate-grid-agent --no-deps
  • cargo deny check (advisories/bans/licenses/sources green)
  • cargo machete (only pre-existing unrelated libremetaverse-types md-5 report)
  • git diff --check

Review against every acceptance criterion completed. No credentials or .env content were read or committed.

Implemented and pushed in e3b9d57. Summary: - Added the deny-by-default PolicyGateway with UUID/authenticated-principal origins, exact typed tool registrations, capability/risk/origin rules, bounded resource estimators, atomic per-principal/global budgets, one-shot approvals, exact scheduler grants, and stable redacted audit records. - Added non-forgeable AuthorizedAction production wiring so world backends cannot accept raw calls or caller-created policy decisions; non-idempotent ambiguous outcomes are never retried. - Added bounded UntrustedData JSON records for every prompt-injection-capable source and prohibited L$ spend, estate/parcel changes, permanent deletion, arbitrary inventory acceptance, and generated-code execution. - Added the complete origin/tool matrix (including public LSL), spoof/name/UUID-text/injection/smuggling/confusable/replay/expiry/scheduler escalation tests, concurrency/restart budget tests, audit backpressure tests, and external integration tests proving public mutation denial and authorized execution. - Documented the policy contract and architecture. Verification: - cargo fmt --all -- --check - cargo clippy --offline -p metacrate-grid-agent --all-targets -- -D warnings - cargo test --offline --locked -p metacrate-grid-agent --all-targets (48 tests green; loopback fake LLM server enabled) - cargo test --offline --locked -p metacrate-grid-agent --doc - RUSTDOCFLAGS=-Dwarnings cargo doc --offline --locked -p metacrate-grid-agent --no-deps - cargo deny check (advisories/bans/licenses/sources green) - cargo machete (only pre-existing unrelated libremetaverse-types md-5 report) - git diff --check Review against every acceptance criterion completed. No credentials or .env content were read or committed.
hugo closed this issue 2026-08-17 21:19:29 +00:00
Sign in to join this conversation.