Lab — Governed AI Tool Gateway
Learning objective: Practice preserving host-owned execution authority when an AI system proposes a consequential tool action, and threat-model the trust boundaries between model output, authoritative host context, governance, acknowledgment, scoped capability, and execution.
Difficulty: Advanced
Prerequisites: Complete the Governed AI Tool Gateway tutorial, run the Governed AI Tool Gateway sample, and be comfortable with the first four foundational patterns.
This is the capstone lab for the foundational ASI Backbone Learning path.
The baseline sample uses a simulated proposal generator and a dry-run notification.send handler.
No real model provider or external notification service is required.
The central rule is:
The model may propose. The host retains execution authority.
This lab asks you to break that rule in controlled ways, observe what becomes possible, repair the boundary, and document the remaining risk.
Starting Architecture
The companion sample begins with this flow:
Simulated model proposal
↓
Host tool registry
↓
Proposal validation
↓
Host-built authoritative context
↓
Governance decision
↓
Acknowledgment when required
↓
Re-evaluation
↓
Scoped capability
↓
Execution-boundary validation
↓
Single-use consumption
↓
Host-owned dry-run handler
↓
Audit residue
Important baseline invariants include:
Unknown tool
↓
Rejected
↓
Handler invocation count = 0
Model claims external recipient is internal
↓
Host rebuilds classification
↓
AcknowledgmentRequired
Expired or mismatched capability
↓
Execution blocked
Same capability identity used twice
↓
Second use rejected
Valid governed flow
↓
WouldExecute = true
↓
No real external side effect
Prepare the Lab
Create a temporary branch or disposable copy:
git switch -c lab/governed-ai-tool-gateway
Run the sample and focused tests before making changes:
dotnet run --project samples/governed-ai-tool-gateway/GovernedAiToolGateway/GovernedAiToolGateway.csproj
dotnet test samples/governed-ai-tool-gateway/GovernedAiToolGateway.Tests/GovernedAiToolGateway.Tests.csproj
Locate these types in the sample:
AiToolProposalToolRegistryProposalValidatorHostPolicyContextFactoryNotificationPolicyAcknowledgmentServiceExecutionCapabilityIssuerExecutionCapabilityValidatorInMemoryCapabilityUseStoreRecordingNotificationHandlerInMemoryAuditSinkGovernedAiToolGateway
Before modifying anything, explain which component owns:
Proposal
Tool availability
Argument validation
Security-sensitive context
Policy decision
Acknowledgment
Execution authority
Credential boundary
Side effect
Evidence
Part 1 — Let the Model Define the Tool Surface
The baseline host uses a fixed registry containing the narrow semantic operation:
notification.send
Temporarily replace that boundary with logic that dynamically accepts any model-provided tool name.
For example, imagine a resolver that maps arbitrary strings to application methods:
Model output
↓
Reflection / dynamic invocation
↓
Matching method executes
Then retry a proposal such as:
finance.transfer_unlimited
or invent another operation that should not exist in the teaching host.
Explain the Failure
Answer:
- Who now defines the executable vocabulary?
- Which review boundary disappeared?
- Can a hallucinated tool name become authority?
- Could a prompt injection expand the available action surface?
- Why is a narrow host-owned registry easier to reason about than arbitrary reflection or command dispatch?
Restore the fixed tool registry.
The lesson is:
A model may select from a host-defined action surface. It should not silently create that surface.
Part 2 — Trust Model-Supplied Security Context
The sample deliberately allows a proposal to contain:
classification = internal
but the host ignores that claim and reconstructs destination classification from RecipientDirectory.
Temporarily modify HostPolicyContextFactory to trust:
proposal.Arguments["classification"]
instead of the host directory.
Run the existing test:
ModelSuppliedClassificationDoesNotOverrideHostClassification
It should expose the boundary failure.
Now submit:
recipient = partner@example.net
classification = internal
Observe whether the external-recipient acknowledgment requirement disappears.
Explain the Trust Error
Answer:
- Which participant benefits if the classification is lowered?
- Which participant can manipulate the proposal?
- Which source is authoritative for destination classification?
- What other fields should normally be reconstructed by the host?
- What changes if the model is highly reliable but still processes untrusted documents?
Restore host-built classification.
The lesson is:
Model output can contribute facts to a proposal without becoming the authority for security-sensitive facts.
Part 3 — Treat Prompt Text as Enforcement
Imagine the system prompt contains:
Never send notifications to blocked.example.
Delete or bypass the host-side blocked-domain rule in NotificationPolicy.
Assume the model follows the prompt in normal conditions.
Then deliberately construct a proposal for:
recipient@blocked.example
The sample proposal can represent:
- Model error.
- Prompt injection.
- Adversarial retrieval content.
- Tool-description confusion.
- A future model behavior change.
If the host no longer checks the destination, what prevents the operation from proceeding?
Restore the host-side rule.
Compare the Two Controls
Document the difference between:
Prompt instruction
and:
Host execution control
A useful distinction is:
Prompt
=
Influences model behavior
Host policy / gateway
=
Controls whether a side effect may occur
The two can complement each other.
They should not be confused.
Part 4 — Let the Model Satisfy Acknowledgment
The baseline external flow requires a host-owned acknowledgment response associated with the actor.
Create an intentionally weak variant where the model can emit:
{
"acknowledged": true
}
and the gateway treats that as equivalent to the actor accepting the host challenge.
Try an external recipient again.
Explain the Responsibility Collapse
Answer:
- Who proposed the action?
- Who satisfied the acknowledgment?
- Is there still a distinct human or system responsibility boundary?
- Which actor identity is preserved?
- Could an injected instruction cause both proposal and acknowledgment?
Restore the separate host-owned acknowledgment response.
Then run:
WrongAcknowledgmentActorDoesNotBecomeExecutionAuthority
The lesson is:
The component proposing an action should not automatically satisfy a separate responsibility boundary merely by generating affirmative text.
Part 5 — Turn Acknowledgment into a Policy Override
The baseline flow is:
Acknowledgment accepted
↓
Context updated with acknowledgment identity
↓
Policy re-evaluated
Temporarily replace that sequence with:
Acknowledgment accepted
↓
Execute
Now imagine the recipient becomes blocked after the challenge was issued but before execution.
Modify the sample or test harness so the second evaluation would return:
Denied
Then bypass re-evaluation.
Explain the Failure
An acknowledgment can satisfy a specific condition.
It should not automatically erase:
- New policy restrictions.
- Changed resource state.
- Revoked actor access.
- Changed destination trust.
- Policy-version changes.
Restore re-evaluation.
The lesson is:
Acknowledgment satisfies an acknowledgment requirement; it does not become universal permission.
Part 6 — Broaden the Capability
The baseline capability is bound to:
Actor
Operation
Recipient
Audience
Scope
Policy version
Acknowledgment identity when applicable
Expiration
One use
Temporarily weaken one or more bindings.
Examples:
ResourceId = *
Scope = notification.*
ExpiresUtc = +24 hours
MaximumUses = unlimited
Audience check removed
Then ask:
If this capability leaked, what is the maximum authority it would expose?
Compare that answer with the original approved action.
Restore narrow bindings.
Required Experiment — Recipient Substitution
Issue a capability for:
partner@example.net
then validate it against current context containing:
other@example.net
The baseline should return:
capability.resource-mismatch
Remove the resource check and observe the difference.
The lesson is:
The follow-on authority should remain no broader than the decision that justified it.
Part 7 — Move Capability Validation Away from the Side Effect
Create a weak flow:
Validate capability
↓
valid = true
↓
Wait
↓
Context changes or capability expires
↓
Handler trusts cached boolean
Test at least one of these cases:
Capability expires after early validation
Recipient changes after early validation
Policy version changes after early validation
Explain why the old validation result does not prove authority at the later side-effect boundary.
Restore validation immediately before capability consumption and handler invocation.
The lesson is:
Validate as close as practical to where authority becomes action.
Part 8 — Break Single-Use Enforcement
Use Replay Protection and Bounded-Use Authority for the canonical distributed-state treatment. The sample's InMemoryCapabilityUseStore demonstrates the state transition but does not provide a durable or cross-instance replay guarantee.
The sample uses InMemoryCapabilityUseStore to demonstrate bounded use.
Remove this check:
TryConsume(capabilityId)
Run the replay test.
The same capability identity should now be able to reach the handler more than once.
Restore the use store.
Identify the Remaining Production Gap
The in-memory store is intentionally not a production replay guarantee.
Answer:
- What happens after process restart?
- What happens with two application instances?
- What happens if both instances check before either writes?
- What persistence and atomicity properties are required for true single-use semantics?
- How would regional deployment affect the design?
The correct conclusion is not:
HashSet = replay protection solved
It is:
The sample demonstrates the state transition.
Production replay guarantees require host-owned durable atomic state.
Part 9 — Move Credentials into the Proposal Path
The baseline model proposal contains no infrastructure secret.
The recording handler owns a placeholder credential reference to make the boundary visible.
Create a weak design where the proposal contains:
apiKey
accessToken
connectionString
and the model is expected to return that value when selecting the tool.
Do not use a real credential.
Use a fictional placeholder only.
Evaluate the Expansion
Answer:
- Does the model need the secret to understand the desired action?
- Does the model need the secret to propose the action?
- Which logs or traces might now contain the secret?
- Could conversation history retain it?
- Could retrieved content cause it to be exposed?
- Can the host handler own the credential instead?
Restore the host-owned credential boundary.
The lesson is:
Understanding an action does not require possessing the infrastructure authority used to perform it.
Part 10 — Create a Fail-Open Gateway
The teaching sample uses local deterministic components, so simulate an unavailable governance dependency.
Add a switch such as:
PolicyAvailable = false
Then implement the dangerous fallback:
Policy unavailable
↓
Execute anyway to preserve availability
Run a consequential external proposal.
Compare Failure Policies
Consider these alternatives:
Deny
Defer
Escalate
Queue for later evaluation
Execute
There is no universal failure policy for every operation.
For the sample's consequential notification path, explain why silent execution broadens authority.
Restore a non-executing failure path.
The lesson is:
Infrastructure failure should not accidentally become permission.
Part 11 — Threat-Model the Complete Gateway
Now model the gateway as a set of trust boundaries rather than as one method.
Use this surface list:
| Surface | Trust question |
|---|---|
| Model proposal | What can the proposer influence or fabricate? |
| Tool registry | Who defines the executable action vocabulary? |
| Argument validation | Which malformed or adversarial values may cross the boundary? |
| Host context factory | Which facts are authoritative and where do they come from? |
| Policy evaluator | What happens when rules are wrong, stale, or unavailable? |
| Acknowledgment workflow | Who may respond and what exactly is acknowledged? |
| Capability issuer | What exact authority is created after approval? |
| Capability validator | Which bindings are checked at execution time? |
| Replay/use store | Can the same authority be reused? |
| Tool handler | Where are credentials and real side effects located? |
| Audit sink | Can the governed path be reconstructed afterward? |
For each surface, document at least:
Threat
Precondition
Potential consequence
Preventive control
Detective evidence
Residual risk
Failure behavior
Minimum Threat Cases
Your threat model should include at least these cases.
A. Prompt Injection Influences the Proposal
Example:
Retrieved content instructs the model to send data externally.
Ask:
- Which host controls still execute?
- Can the injected content alter the tool registry?
- Can it alter authoritative destination classification?
- Can it satisfy acknowledgment?
- Can it access host credentials?
B. Hallucinated Tool Name
Example:
finance.transfer_unlimited
Expected baseline property:
Unknown tool
↓
Rejected before execution
C. Argument Substitution
Example:
Policy evaluated recipient A
Execution attempts recipient B
Expected baseline property:
Capability resource mismatch
↓
No handler invocation
D. Stolen Capability
Assume the capability artifact leaks.
Ask:
- Which actor is it bound to?
- Which recipient?
- Which operation?
- Which audience?
- How long is it valid?
- How many uses?
- What production proof mechanism is missing from the teaching sample?
E. Replay
Assume a valid request is captured and retried.
Distinguish:
Capability replay protection
from:
External operation idempotency
A single-use capability does not by itself prove that a remote provider will never perform a duplicate side effect after ambiguous failures.
F. Audit Sink Failure
Suppose the execution decision is valid but audit persistence fails.
Decide whether the host should:
Block
Defer
Execute with degraded evidence
Queue evidence durably
Your answer should depend on the consequence and audit requirement.
Do not silently assume that logging success is equivalent to governance success.
Part 12 — Compare a Simpler Architecture
Not every tool needs this entire sequence.
Design a simpler path for a low-risk local transformation such as:
format_markdown
summarize_local_text
sort_items
Compare it with notification.send.
Document which controls you would remove and why.
A useful comparison might be:
| Concern | Local formatting | External notification |
|---|---|---|
| Tool allowlist | Useful | Important |
| Argument validation | Useful | Important |
| Host authoritative context | Minimal | Important |
| Policy decision | Maybe unnecessary | Appropriate |
| Human acknowledgment | Usually unnecessary | Context-dependent |
| Scoped capability | Usually unnecessary | Useful for consequential action |
| Replay state | Usually unnecessary | Potentially important |
| External credential | None | Host-owned |
| Audit residue | Lightweight | Potentially important |
The objective is to avoid turning governance into ceremony detached from consequence.
The lesson is:
Use the strongest boundary where the side effect justifies it.
Final Validation
Restore the baseline implementation and run:
dotnet test samples/governed-ai-tool-gateway/GovernedAiToolGateway.Tests/GovernedAiToolGateway.Tests.csproj
Then run the full sample suite:
dotnet test samples/Samples.slnx
Confirm that you can explain why all of these statements are different:
The model proposed the tool.
The host recognized the tool.
The proposal arguments were structurally valid.
The host reconstructed authoritative context.
Policy allowed the current operation.
The required acknowledgment was satisfied.
A narrow capability was issued.
The capability remained valid at execution time.
The single-use authority was consumed.
The host dry-run handler would execute.
The evidence trail recorded the governed path.
Also confirm:
- Unknown tools never reach execution.
- Model-supplied classification cannot lower host classification.
- Blocked destinations remain blocked even if prompt behavior fails.
- The model cannot self-satisfy actor acknowledgment.
- Acknowledgment triggers re-evaluation instead of bypassing policy.
- Recipient substitution invalidates authority.
- Expired capability cannot execute.
- Replay does not invoke the handler twice while the sample use state exists.
- Infrastructure credentials remain outside the proposal.
- The sample produces
WouldExecute, not a real external side effect. - Audit stages retain the same correlation identifier.
Completion Criteria
You have completed the lab when you can answer:
- Why is a model-generated tool call a proposal rather than authority?
- Why should the host own the tool registry?
- Which facts in this sample are intentionally reconstructed by the host?
- Why is prompt compliance not equivalent to execution enforcement?
- Why should the proposer not automatically satisfy acknowledgment?
- Why should acknowledgment be followed by re-evaluation when context can change?
- Which capability bindings preserve the original decision scope?
- Why should capability validation occur near the handler?
- What does the in-memory use store demonstrate, and what does it not guarantee?
- Why should credentials remain host-owned?
- Which failure modes should block or defer execution in your environment?
- What evidence would you need to reconstruct a disputed tool invocation?
- Which threats remain outside the scope of this teaching sample?
- When would a simpler architecture be preferable?
Optional Extension — Add a Second Narrow Tool
Add a second semantic operation such as:
case.note.create
Do not add a generic shell or arbitrary HTTP tool.
Give the second tool different:
- Required arguments.
- Policy rules.
- Audience.
- Capability scope.
- Risk level.
Then prove that a capability for:
notification.send
cannot execute:
case.note.create
This reinforces the relationship between tool design and least authority.
Optional Extension — Simulate Policy Failure
Introduce a policy provider abstraction that can return:
Available
Unavailable
Create tests for the host's explicit failure behavior.
Do not implement:
Unavailable = Allowed
unless you are deliberately demonstrating a fail-open design and documenting the consequence.
Optional Extension — Durable Replay Design
Do not implement a production database solely for this lab.
Instead, write a short design note describing how you would replace InMemoryCapabilityUseStore with a durable atomic store.
Address:
- Key choice.
- Atomic consume operation.
- Expiration cleanup.
- Multiple instances.
- Regional deployment.
- Failure behavior.
- Observability.
Then compare that design with the teaching HashSet.
Resetting the Sample
Inspect your work before discarding lab changes:
git status
git diff
To restore the baseline sample:
git restore samples/governed-ai-tool-gateway
Related Content
- Governed AI Tool Gateway tutorial — review the complete architectural reasoning behind the capstone pattern.
- Governed AI Tool Gateway sample — return to the executable baseline used by this lab.
- Scoped Capability and Host-Owned Execution lab — revisit capability binding, expiration, stale authority, and replay concepts in isolation.
- Replay Protection and Bounded-Use Authority — distinguish capability replay protection from request idempotency, external retry semantics, and exactly-once execution claims.
- Safe Degraded Mode and Fail-Safe Governance — continue from the gateway's single fail-open exercise into explicit policy, replay, verification, acknowledgment, evidence, and executor failure behavior.
- Acknowledgment and Audit Residue lab — revisit responsibility and evidence boundaries before they are composed into AI tool execution.
- AI Agent Gateway Scenario — compare the teaching gateway with the working framework's scenario documentation.
- Human Approval Before AI Tool Execution — compare acknowledgment handling with the implementation-oriented guidance.
- Capability Grant Hardening — examine production-oriented proof, replay, time, binding, and failure considerations.
- Foundational Tutorial Index — revisit the complete five-tutorial sequence.
Read it. Run it. Question it. Improve it.