Author: Max Luo · October 11, 2026 · Teloa AI Security
An employee may read tickets, an agent may expose a sending tool, and a connector may hold credentials for the entire customer database. Those facts do not authorize sending that database to any address. Authorization must establish which trusted principal, under current rights and task limits, may produce this specific effect on these resources through this execution path.
This article combines V2, V3, and V4 of the baseline into a reference flow covering permission computation, approval drift, revocation races, gateway bypass, and retries. It targets enterprise deployments including L2 controls; individual levels remain defined by the requirements. The code is an educational kernel, not a deployable authorization system or a claim about Teloa's implementation or compliance.
1. Intersect operations and resources, not role names
“User belongs to the project team” and “agent has ticket-read permission” do not authorize a particular invocation. The team may access only one tenant, the agent only one project, the task only one month, and the delegation only a bounded export quantity.
P_effective(t) = P_user(t) ∩ P_agent ∩ P_task ∩ P_delegation
subject to environment, parameter, risk, and quota constraints
This is a reference model. V2.2.1's user/agent intersection is L1; task scope and per-invocation recalculation are L2 controls. Sets represent permitted operations and resources, not an intersection of strings such as admin and reader. Evaluate data labels, amounts, recipients, and time windows as additional conditions.
If the user may read project-a, the agent may read that project's tickets, and the task covers October, the query must satisfy all three scopes. Delegating to a child with a broader connector cannot expand the intersection. Connector privilege is credential capability, not evidence of the user's authority.
Deny requests exceeding user rights. An approval for a wider task or agent scope must follow a valid scope-change or temporary-grant process and recompute permissions. Clicking “confirm” does not create rights the approver never possessed.
2. A runnable kernel for deny precedence and outbound approval
This Python 3.9+ example uses exact operation/resource pairs to illustrate the intersection. A trusted tool catalog and actual arguments determine operation; the control plane supplies scopes and status. Do not pass model-supplied risk categories or user_scope into it. Production also needs tenant isolation, conditional policy, quantity limits, approval state, and audit.
from dataclasses import dataclass
Permission = tuple[str, str]
@dataclass(frozen=True)
class Context:
user_active: bool
agent_active: bool
user_scope: frozenset[Permission]
agent_scope: frozenset[Permission]
task_scope: frozenset[Permission]
delegation_scope: frozenset[Permission]
untrusted_input: bool = False
def decide(operation: str, resource: str, ctx: Context) -> str:
if not ctx.user_active or not ctx.agent_active:
return "deny"
known_operations = {"read", "write", "delete", "send"}
if operation not in known_operations:
return "deny"
effective = (ctx.user_scope & ctx.agent_scope &
ctx.task_scope & ctx.delegation_scope)
if (operation, resource) not in effective:
return "deny"
if operation == "send":
return "require_approval"
if operation in {"write", "delete"} and ctx.untrusted_input:
return "require_approval"
if operation == "delete":
return "require_approval"
return "allow"
from dataclasses import replace
scope = frozenset({("read", "project-a"),
("send", "summary-17")})
ctx = Context(True, True, scope, scope, scope, scope)
assert decide("read", "project-a", ctx) == "allow"
assert decide("read", "project-b", ctx) == "deny"
assert decide("send", "summary-17", ctx) == "require_approval"
assert decide("read", "project-a", replace(ctx, user_active=False)) == "deny"
Requiring approval for every send, internal or external, is a conservative deployment choice. V6.2.1 and V7.5.4 at least require approval by default after consuming untrusted input or nonpublic data. require_approval is a pending state, not permission to dispatch. Preapproved plans need separately controlled state and checks against their approved tools, scopes, and cumulative limits.
Policy-service errors, timeouts, and unrecognized decisions must deny execution under V3.2.4. Filtering the model's tool list reduces proposals for unauthorized calls, but does not replace execution-time checks. Policies and hooks run in controls the agent cannot modify.
3. Bind approval to the actual effect
An attacker may not need to forge approval. It can wait for confirmation of “send the summary,” replace recipients with an external address, substitute the raw database for the summary, or exploit a changed definition of a same-named tool.
The platform first parses actual parameters, expands defaults, and creates an immutable effect description. It generates the approval display from that object. A sending operation could include:
{
"approval_id": "approval-73",
"request_id": "req-17-02",
"principal": ["tenant-a", "user-42", "agent-support", "run-17"],
"tool": "mail.send",
"tool_version": "sha256:reviewed-tool-schema",
"recipients": ["[email protected]", "[email protected]"],
"recipient_resolution_revision": "directory-73",
"content_ref": "blob-summary-17",
"content_sha256": "sha256:immutable-reviewed-content",
"attachments": [],
"policy_version": "policy-23",
"nonce": "single-use-nonce-73",
"status": "approved"
}
Digest strings in this example are placeholders; implementations must calculate actual values using the relevant algorithm. A content hash binds bytes; it does not authenticate the approver, prove approval authority, or protect the whole record. Retain the approver, expiry, approved arguments, and authentication strength. The platform generates the display from actual parameters. Dispatch reads the immutable approved object, not a file whose content changed under the same identifier.
Compute parameter digests after typed parsing, normalization, and default expansion. Resolve duplicate JSON keys, Unicode, paths, amount units, and recipient semantics; hashing uninterpreted text is insufficient. RFC 8785 defines JSON canonicalization, not tool semantics. The tool contract still defines recipient ordering, amount precision, and resource versions.
Recipients can drift semantically: a mailing-group name stays the same while its membership expands. Bind resolved recipients and membership revision in the effect description and recheck them before dispatch, rather than comparing only the string [email protected]. If downstream group expansion cannot be frozen, do not send sensitive content to that group; use a controlled link that authorizes each viewer instead. Recheck recipient permissions when they change.
At dispatch, revalidate the principal, tool version, parameters and content digest, expiry, approval state, and current rights. Changes invalidate approval or require renewed evaluation. Resource-changing tools can bind a version and use supported downstream conditional updates to guard against state changes while approval waits. V3.4.6's preapproved plan requires containment and cumulative-quota checks, not permanent approval for anything that agent proposes.
4. Handle the gap between approval and execution
Approval is not the final state. While waiting, the user may be disabled, policy tightened, the agent stopped, or the approval expired. An unbounded decision cache can turn one permitted request into a long-lived pass.
PROPOSED → NORMALIZED → POLICY_CHECKED
→ AWAITING_APPROVAL → APPROVED
→ REVALIDATED → DISPATCHING → SUCCEEDED
→ FAILED / UNKNOWN
Immediately before dispatch, REVALIDATED checks current rights and identity, approved parameters, and tool version. A policy-version change requires reevaluation rather than reuse of an old allow. Atomically associate single-use approval consumption with a dispatch record so two workers cannot independently spend it.
A local gateway transaction cannot create a common transaction with arbitrary SaaS. If the message was sent but the response was lost, the result is UNKNOWN; blindly sending again to obtain a success response creates duplicate effects. Prefer downstream idempotency support: reuse the same key for the same effect and query the prior result. Without idempotency and result lookup, require manual reconciliation. Deduplication binds principal, tool, and effect; another argument set cannot borrow an existing request ID.
A race can remain between permission revalidation and the external effect. Narrow dispatch windows, prevent renewal after stopping, use constrained short-lived downstream credentials, and integrate revocation where available. Document treatment of already in-flight operations. One permission lookup per call does not eliminate every time-of-check/time-of-use risk.
5. Enforce the real access path and credential destination
V4 governs execution. The environment receives placeholder credentials; the gateway obtains real credentials according to the authenticated principal and verified decision, then injects them only into bound destinations. For platform-hosted environments, outbound networking denies by default and downstream services reject direct access that bypasses the gateway. An HTTP proxy environment variable cannot force arbitrary programs to use that proxy.
A concrete gateway sequence is:
- Authenticate the workload, recover its principal, and check that instance and task remain active.
- Parse operation, arguments, and connector through the controlled tool definition; reject unreviewed versions.
- Bind the decision to the actual request; recheck approval, permissions, quota, and current policy.
- Resolve a registered protocol, host, port, method, and path scope. Constrain DNS and the actual connection destination against substitution and rebinding.
- Retrieve the appropriate user's or non-human principal's connector credential, check destination binding, and inject it.
- Execute, correlate the downstream effect, and sanitize responses so diagnostics do not return credentials to the model.
Do not implement a host allowlist using startswith("https://trusted.example"): other hosts can share that prefix. Apply the service contract's encoding, normalization, and path-boundary rules. Do not automatically follow redirects; a necessary redirected target requires renewed checks and must not inherit credentials across destinations. Allow internal services by registered service and address ranges rather than a blanket internal-network exception.
Credential storage binds a user or agent to a connector and destination. Debug logs must omit Authorization headers, and tool responses must not reflect real secrets. Audit credential-access events and connector references rather than secret values.
Some client-signed cloud API calls cannot use gateway credential injection. V5.2.2 permits short-lived credentials constrained by user, task, permission, and resource. Assess isolation and networking for that exception separately; it does not authorize placing long-lived cloud keys in model context.
6. MCP and legacy systems require different additional controls
A token valid for an MCP server is not automatically valid for a downstream API. MCP's authorization specification requires tokens intended for that server and prohibits passthrough. Under V4.5.5, MCP and downstream APIs are separate authorization hops with their own audiences and authorization forms. Local MCP processes remain subject to outbound restrictions.
Sender binding reduces replay of stolen tokens from other clients. RFC 9700 discusses mTLS, DPoP, and audience restrictions. These mechanisms do not make a compromised instance with access to legitimate keys trustworthy; resource-level policy remains necessary.
When a legacy system supports only shared static credentials, V4.4 requires the gateway to compensate with user-, interface-, and operation-level authorization. A database account with access to every project cannot authorize arbitrary SQL for each employee. Constrain controlled queries to trusted tenant and resource scopes, restrict operations, and prevent alternate paths. When the shared downstream account cannot distinguish users in its logs, correlate gateway audit and applicable signed identity metadata, documenting the compensating control's limitations and review ownership.
7. Twelve denial cases check whether the boundaries close
| Case | Expected handling | Actual effect to inspect |
|---|---|---|
| User allowed, agent denied | Intersection denies | Zero downstream calls |
| Agent allowed, user denied | Deny; approval does not silently grant rights | No unauthorized reads or writes |
| Read-only task proposes full export | Deny or use a valid scope-change process | Existing task scope is not silently expanded |
| Child agent has a broader connector | Root-user and delegation limits still apply | No increased resource visibility |
| Recipients, group membership, content, or attachments change after approval | Effect binding or recipient visibility fails | Old approval does not authorize a different effect |
| Approval expires or tool definition changes | Reapprove or deny | New tool does not inherit old approval |
| Policy service times out or responds incorrectly | Deny by default | No direct-call fallback |
Disabled user reuses an old allow |
Enforce revocation and cache rules | Gateway stops obtaining credentials |
| Two workers consume one approval concurrently | Dispatch one logical effect | Deduplication matches downstream outcomes |
| Downstream succeeds but response is lost | Idempotent lookup or manual reconciliation | Retry does not duplicate the send |
| Sandbox bypasses gateway, changes host, or follows redirect | Access-path or destination checks deny | Credentials never reach the new destination |
| MCP token is reused for the downstream API | Audience checks or separate authorization stop it | Original token is not passed through |
Correlate user, agent, instance, task, operation arguments, policy decision, approval, and downstream outcome under V10.1. Protect sensitive content and identity references according to V10.2. In addition to denial logs, verify the absence of downstream effects. Track UNKNOWN separately; an unknown outcome is not a safe failure.
8. Ask what each implementation can demonstrate
For V2, request evidence of the sources of intersected permissions and delegation scope, including behavior after permission reduction. For V3, examine platform-generated actual-parameter approval, unavoidable checks, and default denial. For V4, inspect the controlled network path, credential-destination binding, and evidence that the execution environment cannot obtain real long-lived credentials.
This division locates defects. Correct argument checks with a direct-access bypass require access-boundary remediation. Controlled egress with an administrator connector standing in for user authority requires authorization remediation. Approval bound only to a model-written summary requires effect-description and consistency remediation. Place responsibility in components that can enforce it, and a design principle becomes a reproducible security baseline.
Revisit threat modeling and assessment and identity, then record evidence in the assessment tool. Teloa AI Security maintains the standard, architectures, and source, derived from Teloa development practice.
