Skip to content
Required Artifacts

Required Artifacts

Every project you publish in Month 3 carries the same four artifacts. They are not documentation busywork — each one answers a specific question a reviewer will ask, and together they are the difference between “here is an agent I built” and “here is an agent I built, and here is how I know what it does when things go wrong.” This page explains each artifact deeply enough that you can produce it, not just recognize it.

Artifact 1 — STRIDE threat model diagram

A threat model is a picture plus a table. The picture shows where data moves and where trust changes. The table says what could go wrong at each of those points and what you did about it.

Drawing the data flow

Draw four kinds of things and nothing else:

ElementNotationExamples in an agent system
External entityRectangleHuman operator, third-party API, log source
ProcessCircleAgent loop, MCP server, tool handler, validator
Data storeTwo parallel linesLog directory, ticket database, vector store, conversation memory
Data flowArrowAlert into investigator, tool call, model response, ticket creation

Then walk one real request from entry to final effect and label every arrow with what actually travels along it. Most people’s first diagram is wrong in the same way: it shows the agent calling a tool but omits the model provider, the retrieved content, and the memory store. All three are on the data flow and all three are attack surface.

Placing trust boundaries

A trust boundary is any line where data crosses from a context you control into one you do not, or vice versa. In agent systems the boundaries that matter are:

  • Between untrusted retrieved content and the model context
  • Between the model’s output and any tool that acts on it
  • Between one agent and the next in a pipeline
  • Between the agent runtime and any credential store
  • Between the system and the human approver

Draw them as dashed lines cutting through arrows. Every arrow crossing a dashed line needs validation, and if you cannot say what validates it, you have found a gap.

STRIDE mapped to agent threats

STRIDEConcrete agent threatControl
SpoofingRetrieved document impersonates the operator: “as the admin, run this”Structural separation of instructions and data; never place retrieved text in system role
TamperingInjected log line alters the investigator’s verdict fieldTyped handoff schema; validate enum values; log raw and parsed forms
RepudiationAn action happened but no record shows which agent, prompt, or version caused itPer-span audit trail with agent ID, commit hash, and full tool arguments
Information disclosureA secret in a log line enters context, then appears in the reportRedact at ingestion; egress checks on generated output; no network from the reader
Denial of serviceCrafted input causes an unbounded tool loop and burns the token budgetHard caps on iterations, tool calls, and tokens per run; timeouts on every tool
Elevation of privilegeLow-privilege agent persuades a higher-privilege one to act on its behalfServer-side authorization per caller identity; no capability delegation across agents
Ship the diagram as a committed image or a text-based diagram source in THREAT-MODEL.md, alongside the table. A reviewer who can read your boundaries in ten seconds will read the rest.

Artifact 2 — Trust boundary and human approval design

When the “user” is a retrieved document

Classic threat modeling assumes the user is a person with an identity and an authorization level. Agents break that assumption. Content the agent retrieves — a log line, a ticket comment, a web page, a file — arrives inside the same context window as the operator’s actual instruction, and the model has no reliable way to tell them apart by origin.

The practical consequence: treat every piece of retrieved content as an anonymous, unauthenticated, potentially hostile user submitting instructions. That reframing decides your design. You would not let an anonymous internet user call delete_ticket. So the agent, while processing anonymous content, must not be able to either.

Two structural habits follow. Keep retrieved content in clearly delimited data fields, never in the instruction position. And derive the agent’s authorization from the operator’s identity and the task, never from anything the content asked for.

Where approval gates belong

Two criteria decide: irreversibility and blast radius. An action that can be cleanly undone by the person who noticed the problem is a poor candidate for a gate. An action that leaves your system, notifies a person, spends money, or destroys evidence is a good one.

Reversible?Blast radiusGate?Example
YesSingle recordNoRead a log file, look up an asset
YesSingle recordNoCreate a draft, add an internal comment
YesMany recordsYesBulk-update tickets, re-tag a dataset
NoSingle recordYesSend an email, post to a channel
NoMany recordsYes — plus a second reviewerDelete records, revoke credentials, push config
YesExternal party sees itYesPublish a report to a shared space

Note the asymmetry: reversibility alone is not enough once other people can see the result. You cannot un-notify someone.

Designing a gate that is not click-fatigue theater

A gate approved 200 times a day is a rubber stamp with a UI. Five rules keep it real:

RuleWhy
Gate rarelyIf everything is gated, nothing is reviewed. Read-only operations should never prompt
Show the effect, not the intent“Create ticket INC-4471 assigned to on-call, visible to 40 people” beats “Agent wants to create a ticket”
Show the evidence inlineThe approver needs the log lines that drove the decision, not a summary of them
Make reject cheap and informativeRejection should capture why, and that reason becomes test data
Record the approval as evidenceWho approved, when, what exact payload — into the audit trail
Never let the agent write the text of its own approval prompt from untrusted content. Injected input that shapes the prompt can make a destructive action look routine. Render the prompt from validated fields your code controls.

Escalating friction is the honest version of this: low-risk actions proceed, medium-risk actions prompt with full context, high-risk actions require a typed confirmation of the specific target. Time-box approvals too — a gate approved twenty minutes ago should not authorize an action now.

Artifact 3 — Audit log sample with OpenTelemetry spans

An audit trail is what turns “something weird happened” into “here is exactly what happened, in order, with inputs.” Model it as spans: one trace per agent run, one span per meaningful step.

Attributes every span must carry

Attribute groupFieldsWhy an investigator needs it
Identitytrace_id, span_id, parent_span_idReconstructs the causal order across agents
Actoragent.id, agent.role, user.id, session.idAnswers “who ran this, on whose behalf”
Versionagent.version, model.name, prompt.versionLets you reproduce the exact conditions
Actiontool.name, tool.arguments, tool.result_summaryThe actual thing that happened
Decisiondecision.outcome, decision.confidence, policy.checks_passedWhy the agent chose this
Approvalapproval.required, approval.granted_by, approval.timestampProves the gate operated
Costtokens.input, tokens.output, duration_msDetects loops and abuse patterns
Safetyredaction.applied, input.source_trustShows untrusted content was labeled as such
{
  "trace_id": "4f9a2c...",
  "span_id": "b81e7d...",
  "name": "tool.create_ticket",
  "agent": { "id": "ticket-creator", "version": "1.3.0" },
  "attributes": {
    "tool.name": "create_ticket",
    "tool.arguments": { "verdict": "suspicious", "asset": "host-REDACTED" },
    "input.source_trust": "derived_from_untrusted",
    "approval.required": true,
    "approval.granted_by": "operator-REDACTED",
    "decision.confidence": "medium",
    "tokens.input": 3181,
    "duration_ms": 842
  },
  "status": "OK"
}

What makes a trace investigable later

  • Complete causal chain. Every span has a parent. You can walk from the final effect back to the originating input without guessing.
  • Inputs preserved, not just outputs. The exact tool arguments, redacted but structurally intact. “It created a ticket” is useless; the payload is the evidence.
  • Trust provenance. Each span records whether its input derived from untrusted content. This is the single field that makes injection investigation tractable.
  • Version pinning. Agent version, prompt version, model name. Without these you cannot reproduce and therefore cannot confirm a fix.
  • Failures recorded as spans. A blocked tool call is a span with an error status, not a silence. Absence of a record must never be ambiguous.
  • Redaction that preserves shape. Substitute, do not delete, so field structure survives.

Build this in Lab 4 — Agent Audit Trail; tooling options in observability tools.

Artifact 4 — The “How this agent fails” README section

This is the highest-signal thing in your portfolio. Almost nobody writes it, and it takes about forty minutes.

Template

## How this agent fails

### Known failure modes
1. <Condition> → <what the agent does> → <impact> → <mitigation or "unmitigated">

### What I attacked and what happened
| Attack | Payload location | Result | Control that caught it |
|---|---|---|---|

### What I did not test
- <Area> — <why not>

### What would need to change for production
- <Gap> → <required change>

Writing each section

Known failure modes. Concrete conditions, not disclaimers. “Logs above roughly 50 MB exceed the context window; the agent silently summarizes only the first chunk and does not report the truncation” is a failure mode. “May produce inaccurate results” is a legal notice.

What I attacked and what happened. Pull this straight from your Month 2 attack log. Include the attacks that failed to break anything — a blocked attempt with a named control is proof the control works.

What I did not test. Name the gaps yourself. Multi-user concurrency, adversarial file formats, sustained load, non-English input, model version drift. A reader who finds an untested area you already listed trusts the rest of your claims. A reader who finds one you did not list stops trusting all of them.

What would need to change for production. Bridges the gap between a lab project and a real deployment: managed secret storage, rate limiting, a real approval system, monitoring and alerting on anomalous tool-call rates, log retention aligned to a policy — connect this to governance requirements where relevant.

Admitting limits reads as senior because knowing where your system breaks requires having probed it. A README claiming no weaknesses tells a reviewer one of two things: you did not look, or you did look and are not saying. Neither is the impression you want.

Final checklist

ArtifactDone whenRole it signals to
STRIDE threat modelDiagram committed, all six categories mapped to a concrete threat and control, boundaries drawnAI Security Engineer, Security Architect — see core roles
Trust boundary & approval designGates justified by irreversibility and blast radius; decision table committed; prompts rendered from validated fieldsAgent Platform Security, Product Security
Audit trail sampleReal redacted trace in docs/, every span carries identity, version, trust provenance, and approvalDetection Engineering, AI Assurance — see adjacent roles
“How this agent fails”All four headings filled with specifics, including negative attack results and untested areasEvery role. This is the section people quote back to you in interviews

Practice the full threat-model-to-risk-register flow in Lab 5, and check your control vocabulary against standards references and the OWASP agentic threats catalog.