Skip to content

Chapter 53 Secrets, Permissions, Tenant Isolation, and Supply Chain Security

Mira asks for order A-104. The assistant returns “shipped,” a perfectly plausible status—but it belongs to Leo in another tenant. Nothing in the sentence looks like a jailbreak, and a content-safety filter may find no problem. The defect is that the query selected the wrong person’s record.

A second failure can look equally ordinary: a useful Skill changes by one line and starts reading a secret file. The tool name is still allowed. These failures ask questions that answer quality cannot settle: whose authority is in use, which objects it covers, and which exact code or asset is being trusted? We will follow those questions through the same local assistant, completing KA-8 without adding a multi-agent platform.

53.1 Identity comes from the host, not the proposed arguments

Section titled “53.1 Identity comes from the host, not the proposed arguments”

A tenant is a separately administered group whose data must remain within its access boundary. Our new, versioned fixture has two tenants. North contains Mira’s A-104, status processing; south contains Leo’s A-104, status shipped. The repeated order ID is intentional. Mira and Leo are display names; their stored user IDs are mira and leo. Earlier read-only examples keep their original fixtures unchanged.

Example 53.1 — An ID is not a complete access decision. Mira’s trusted host context says tenant north, user Mira, audience orders-local, and scope orders:read:own. The allowed tool argument supplies only order_id: A-104. A correct lookup must match tenant, order ID and owner:

SELECT * FROM orders
WHERE tenant = ? AND id = ? AND owner = ?;

The values are bound as parameters: north, A-104, mira. A parameter is a data value passed separately from the SQL structure; the model does not construct this query. The result is processing. The intentionally unsafe query instead accepts south from untrusted content and returns shipped. Adding an ownership check while still letting the model choose identity would not fix the underlying trust problem.

The guarded dispatcher rejects the unexpected tenant argument. Storage independently enforces the tenant and owner from the principal. Actual tests also change the host test principal to north/Leo or south/Mira; both fail because neither owns the selected row. A legitimate south/Leo principal gets shipped. Isolation means correct separation, not making south’s service unusable.

The simulator’s principal is a host-created identity record. Arbitrary Python with access to the process could construct one; this is not a real authentication service. In production, verifying a credential and establishing trusted request context must happen before these checks. A model saying “I am Mira” is no such verification.

53.2 Use credentials only where authority is exercised

Section titled “53.2 Use credentials only where authority is exercised”

A secret is information whose disclosure would violate a boundary; a credential is evidence used to establish access authority. Some secrets, such as access tokens, are credentials. The fictional cabinet code from Chapter 52 demonstrates a disclosure rule but is not our application’s authentication mechanism.

Credentials should reach the component that needs them through a controlled host path. They should not be copied into model context, retrieved documents, Skill instructions or routine logs. A token’s audience identifies the service it is meant for. Its scopes describe permitted operations, and its expiry limits duration. Passing a token intended for one service to another does not make it valid there.

Table 53.1 — Permission matrix for the local assistant. These are enforced simulation rules, not real OAuth grants.

Principal and requestAutomatic operation?Additional requirementActual behavior
Current north/Mira reader; read own A-104YesCorrect audience, scope, tenant and ownerReturns processing
Reader; cancel own A-104NoCancellation scope plus matching approvalMissing write scope rejects
Writer; cancel own A-104Only after approvalApproved exact action, subject, tenant, version and expiryValid approval produces one effect
Writer; missing, denied or expired approvalNoA valid approval is absentZero effects
North reviewer with approval role/scopeMay create an approval recordSame tenant and explicit decisionCan approve or deny; cannot thereby read or cancel orders
Expired credential, wrong audience, missing read scope, or wrong ownerNoEstablish valid authority firstRequest rejected
Model supplies another tenant or arbitrary network toolNoThose proposals are outside the interfaceSchema or allowlist rejects

Least privilege means giving a component only the authority it needs for its role. A read-only assistant does not need a cancellation credential. An approver needs authority to record a decision, not unrestricted order access. A source-verification helper needs its inputs and reviewed resources, not the user’s credential.

An approval is also bounded. Approval for north/Mira to cancel A-104 at version 1 does not approve A-105, south’s A-104 or a later changed version. Chapter 49’s action fingerprint binds the operation and arguments; the approval record also binds subject, tenant and expiry. The tests reject changed arguments, expired approvals and a writer attempting to act as approver. A human-looking sentence in a tool response cannot populate that record.

53.3 Check the bytes, then ask who vouched for them

Section titled “53.3 Check the bytes, then ask who vouched for them”

Example 53.2 — A useful Skill changes after review. We review version 1.0.0 of the source-verification package and store its file paths and SHA-256 digests in an independently retained inventory. SHA-256 produces a fixed-length digest from file bytes. If the file changes, the comparison is expected to fail; this is an integrity check, not an explanation of whether the file is safe.

The regression copies the reviewed Skill, helper script and local MCP implementation into separate temporary files. Each first matches its recorded digest. Appending an unreviewed line makes each fail. The runner rejects the changed bytes before executing them. A symlink pointing outside the permitted root is rejected as well, so a seemingly harmless path cannot silently select an unreviewed target.

Do not calculate the “expected” digest from the offered file immediately before comparing it with itself. The expected inventory must be the previously reviewed snapshot. Our normal record runner loads that inventory and stops on mismatch; it does not refresh approvals automatically. An intentional update needs review, a new snapshot and rerun evidence.

Table 53.2 — Provenance questions differ across dependencies.

DependencyEvidence retained hereWhat remains unproved
Source Skill and its assetsOrigin in this project, version, license, reviewed file digests, helper testsA hash cannot prove the original author’s decisions were safe
MCP server implementationLocal source digest, read-only contract, protocol reference, existing testsProtocol compatibility does not authenticate every server operator
Python packagesExact installed versions and distribution metadata; inherited requirements lockPinning does not prove the registry, maintainer or installation artifact was uncompromised
Local modelRegistry/tag, installed manifest digest, five verified content blobs, upstream license referenceNo independently verified conversion/build attestation linking the quantization to upstream weights
Model runtime/serviceRecorded runtime version, API settings and local CPU observationsNo production service security assessment or provider-retention guarantee

The installed Qwen manifest digest is 458ce03a21878025d072b8740d0e0e3b34abec3585fdadb0b5ab92d1e85dfb61. All five installed blobs match their manifest sizes and digests in the actual local inspection. A separate offered digest of 64 zeroes is rejected by comparison with the pinned value. We do not corrupt or execute modified weights, and no weight files are redistributed.

These checks establish local identity and consistency, with an explicit provenance gap. A malicious publisher could supply both malicious bytes and a matching digest. A compromised reviewer could approve the wrong inventory. Stronger build provenance needs trusted builder identity and verified expectations, as SLSA explains; this unsigned teaching inventory claims no SLSA level. A working Skill, MCP connection or model is evidence of availability, not evidence that its source is trustworthy.

53.4 Test confinement without confusing it with authorization

Section titled “53.4 Test confinement without confusing it with authorization”

A sandbox restricts what a process can access or change. It operates at a different boundary from “may Mira cancel this order?” A process can be well confined and still misuse records it is allowed to access. Conversely, a correctly authorized operation can run in an unnecessarily powerful process.

Example 53.3 — A real, limited process experiment. In an optional macOS probe, create a public fixture file, a protected directory containing only DEMO-SECRET-ORCHID, and a loopback listener on the same computer. Run the same Python subprocess once normally and once under a confinement profile. No external destination is contacted.

Table 53.3 — Observed process behavior.

AttemptWithout the profileWith the profile
Read permitted fixtureReads public-fixtureReads public-fixture
Read designated protected fixtureReads the fictional secretPermissionError, errno 1
Connect to local listenerConnectsPermissionError, errno 1

This profile denies all network access, denies reads in the designated protected fixture directory, and restricts writes to the temporary work directory and /dev/null. General runtime reads remain allowed. It is a macOS-specific diagnostic profile, not a general filesystem allowlist or a production sandbox. An earlier profile prevented Python from starting; that failed attempt is retained separately instead of being counted as successful confinement. A process that cannot do its legitimate job is not a sufficient positive test.

The measured result establishes those specific file and network boundaries on the recorded platform. It does not prove resistance to escapes, protect every file on the host, or test another operating system. The portable CPU suite checks dispatch and authorization separately; it does not silently pretend to recreate this OS-level experiment.

Request → data
  1. Application recordHost: north / mira
  2. An operationWHERE tenant=north AND owner=mira
  3. Outside the modelA-104: processing

The same ID in south belongs to leo and is shipped; an order ID alone is insufficient.

Code → effect
  1. Application recordReviewed source + expected digest
  2. An operationAllowlist + sandbox + approval
  3. Application recordScoped effect + audit receipt

An unchanged malicious package can pass a hash check. An isolated process can still misuse an authorized credential.

Figure 53.1 — Check four different conditions before execution. Original teaching diagram · CC BY-SA 4.0

Figure 53.1 keeps the controls separate: host identity selects authority; approval permits a specific write; provenance selects reviewed bytes; confinement limits process reach; audit records preserve decisions and effects. Removing any one can leave a different path open. Audit does not prevent an unauthorized action by itself, but without it we may be unable to reconcile an uncertain result.

53.5 Complete the project by stating its acceptance boundary

Section titled “53.5 Complete the project by stating its acceptance boundary”

The assistant now has a finite RAG workflow with one bounded model choice, a reusable source-verification Skill, durable simulated action recovery, layered evaluation and a governance/security record. Its original Keyword, BoW Count and TF-IDF comparisons remain intact. The prior Mini GPT decision remains intact too; using Qwen for separate local probes did not change that model’s acceptance status.

Table 53.4 — KA-5 through KA-8 handoff evidence.

MilestoneObservable resultResidual responsibility
KA-5One allowed choice; current 750; empty evidence and exhausted budgets stopMore tasks need their own evidence and transition contracts
KA-6Skill trace; rejected approvals cause zero effects; lost-reply recovery leaves one effect; replay makes zero mutationsRemote services need their own idempotency/reconciliation contract
KA-7Two systems both 3/4 with different first failures; four travel human cases agree; public human slice agrees 0/4Automatic Judge release remains disabled; more independent domain review is needed
KA-8Minimized fields, four-store deletion, expiry, local attack blocking, tenant/approval tests, changed-byte rejection and bounded OS probeReal identity, operational retention, backups, source rights, incident response and secure deployment remain human/system duties

The project is a local teaching system, not an operational service. Its core notebooks run on CPU using small fixtures and saved optional-model records. Model calls, human judgments, hand-given examples and actual host execution remain distinguishable. Small security regressions can prevent known mistakes from returning; they cannot prove that no unknown attack exists.

53.6 Part checkpoint: explain the control without naming a framework

Section titled “53.6 Part checkpoint: explain the control without naming a framework”

Try these six transfer questions before reading the answers below. They connect the entire part rather than require memorizing component names.

  1. Evidence is empty and a model asks to search forever. Which component stops the request, and which state should be retained?
  2. A new source-verification package has the same name but different bytes. What must happen before it can run?
  3. A cancellation reply is lost. Which evidence distinguishes “not done” from “done but not reported,” and why is a new key dangerous?
  4. Two systems each pass 3/4 requests. What additional record tells you where to repair them?
  5. A cited source is authentic but wrong. Who resolves the substantive dispute, and which current/historical checks should follow?
  6. A sandboxed tool receives a valid north credential and a model-supplied south tenant. Which controls still have to reject the request?

Authority follows a verified principal and a scoped operation, not persuasive text or an order ID alone. Reviewed digests detect changes relative to a known inventory; they do not create trustworthy provenance. A sandbox limits reach but does not grant authorization. KA-8 combines these controls with audit and explicit remaining duties. Chapter 54 asks how to turn this local design into a usable service while preserving those boundaries.

  1. North and south both have A-104. A cache uses only order ID as its key. Explain a possible leak and specify the additional identity and version information needed when using cached results.
  2. A credential permits reads and cancellation, but its audience is another service. Should an approved cancellation proceed? Identify the first failing condition.
  3. A reviewer approves version 1, but the order reaches version 2 before execution. What should happen, and why does “same order ID” not preserve approval?
  4. A changed helper comes with a new matching checksum from its own download page. Which integrity check can pass, and which trust question remains?
  5. The sandbox blocks the fake secret but permits a database containing both tenants. Does Table 53.3 establish tenant isolation? Propose the necessary separate test.
  1. South’s cached shipped result can be returned to north/Mira. Partition cache access by trusted tenant and authorized subject/scope as appropriate; validate current authorization on retrieval. Include object/source version and relevant request conditions so stale or differently scoped entries are not reused. A cache hit is not an exemption from access checks.
  2. No. Audience validation fails before the requested scope or approval can authorize this service. An approval does not repair an invalid credential; obtain a valid service-specific authority through the host’s authentication path.
  3. Reject the stale version or request a fresh review of the changed action context. The approved object state has changed; the version guard prevents an old approval from silently covering it.
  4. The downloaded bytes may match the download page’s checksum. That does not establish who controls the page, whether the helper was reviewed, or whether its build is trustworthy. Compare against separately trusted expectations and review the update before changing them.
  5. No. A process may misuse everything it can legitimately read. Test identical IDs across two tenants, authenticated owner checks, cross-tenant argument rejection and cache separation at the application/storage boundary. The OS probe answers a different question.

Part checkpoint answers.

  1. The host’s deterministic transition and budget rules stop or abstain; empty evidence leads to ABSTAINED without a model call in our workflow. Keep the reason and observed evidence state. A model request cannot extend the graph or budget.
  2. Reject the mismatch, review origin, instructions, scripts, assets and dependencies, then deliberately approve a new version/inventory and run its tests. A familiar name does not approve changed behavior.
  3. Inspect a durable receipt tied to tenant, subject, action and idempotency key, then reconcile current state. In our single database, effect and receipt commit together. A new key can represent a new action and duplicate a remote side effect; replaying saved events executes nothing.
  4. Request-level outcomes plus retrieval, packed context, proposed answer/support and tool trajectory show the first observed failure. Equal totals discard those positions. Rerun the affected and downstream checks after repair.
  5. The policy owner investigates source correctness; the service owner applies the resulting source/index/cache change. Preserve both current 750 and valid historical 600 under their respective dates. Citation matching alone cannot settle the dispute.
  6. Reject the unexpected tenant argument and scope storage/cache access to the authenticated tenant and authorized owner. Check audience, expiry and operation scope as well. Confinement neither changes identity nor grants cross-tenant access.
  • MCP authorization, 2026-07-28 and official security best practices, scope/audience, confused-deputy and token-passthrough sections. These support service-specific authority and independent authorization checks; the local principal is not OAuth.
  • Agent Skills specification, resources and progressive disclosure. Packaging reusable instructions does not establish trusted origin or execution permissions.
  • OWASP GenAI 2025, LLM03 Supply Chain, mitigation items 5–9. These motivate inventories, licenses, integrity and continuing review across dependencies and model assets.
  • SLSA 1.2, Verifying artifacts, verification steps and forming expectations. Authentic build provenance requires more than a matching artifact digest; this project claims no SLSA certification.