An AI lab you can break safely, on a machine you own and with data you wrote

Listen to this lesson

Episode 2 · 62:57

Every episode of this course is also a podcast: listen on Spotify.

This episode is a study companion for CompTIA SecAI+ CY0-001 and is not produced by or endorsed by CompTIA.

Supplementary

This lesson maps to no CY0-001 objective. CompTIA does not examine "build a lab", and nothing in it will be asked of you. It exists because the labs attached to every objective in this course, from 1.1 to 4.3, run in the environment it builds. Its parts come straight from the syllabus: retrieval-augmented generation from 1.2, gateway controls from 2.2 and prompt logging from 2.5.

Why this matters

Every later lab in this course asks you to do something you should never do to a production AI system: plant an instruction in a document and watch the model obey it, switch a guardrail off and see what comes back, flood an endpoint until it falls over, or read a prompt log that contains a "secret". Those experiments teach more than any amount of reading, and every one of them is a bad idea against a hosted service, a work account or real data.

So the lab has to satisfy three conditions at once. It must be real enough that what you observe is how these systems actually behave: a real model, real embeddings, a real retrieval step, real token counts. It must be contained, so that nothing you break reaches your own network, your accounts or anybody else's service. And it must be cheap to reset, because an experiment you are afraid to run is one you will not run.

The design below meets all three with free, local components and no API keys. Nothing in it talks to a third-party AI service, and every document it holds is one you wrote. That last rule is the one people are tempted to break, and it is the one that makes the rest safe: a lab that leaks invented data has taught you something, while a lab that leaks your real data has caused an incident.

There is a second payoff. The components here are a miniature of the architecture the exam's scenarios describe: a model behind an endpoint, a retrieval pipeline over a document store, a gateway in front of both, and a log of every interaction. When a question describes a prompt firewall at the gateway, or a poisoned document in the vector store, you will have touched the thing it is describing.

The lesson

A local model runner in an isolated virtual machine, with no route to anything you did not build

The lab lives inside one virtual machine on a hypervisor you already have: VirtualBox, VMware Workstation, Hyper-V, KVM through virt-manager, or UTM on a Mac. The choice does not matter to anything later in the course. A Linux guest is the easiest, because every tool below runs on it and its network state is simple to inspect.

Inside the VM runs a local model runner. Two are widely used and either is fine. Ollama downloads and serves open-weight models behind a local HTTP API and is the quicker start. llama.cpp is the lower-level engine, with a bundled server that also exposes an HTTP API, and suits readers who want to see more of the machinery. Both run quantised models on an ordinary CPU, slowly but usably, which is the trade-off lesson 3 explains.

Pick a small open-weight model, a few billion parameters at most, from one of the families published with downloadable weights. You are not here to get good answers; you are here to watch behaviour. A small model is also more easily misled than a large one, which makes the injection and guardrail labs more instructive rather than less.

The network design is the part that matters. The VM needs the internet exactly once, to fetch the operating system packages, the runner, the Python libraries and the model weights. After that, change its adapter to a host-only or internal network with no default gateway, and turn off every other path a hypervisor offers by default: shared folders, shared clipboard, drag and drop, and any port forwarding. Each of those is a route out that a network diagram does not show.

Some libraries try to reach the network on first use, to download a model or to send usage telemetry. Inside an isolated VM that shows up as a timeout. That is the isolation working. The fix is to fetch what is needed while connected, then disconnect again, and never to leave the VM connected "just for now".

A toy retrieval-augmented app over documents you wrote, so nothing real can leak

Write six to ten short documents for an invented organisation. A useful set: a holiday policy, an expenses policy, an IT acceptable-use policy, a product FAQ, an on-call rota, and one document marked restricted, such as invented salary bands. Give each document front-matter style metadata: a classification label, an owner and a department. Later lessons on data access and classification (lessons 11 and 14) filter on exactly those fields.

Put a canary string in the restricted document: a made-up token that appears nowhere else, such as a nonsense project name followed by a number. Every leakage experiment in the course then has an unambiguous test. If that string appears in a response or a log line where it should not, something leaked, and a text search proves it.

The app itself is a short Python script, and building it is worth the evening because it makes lesson 5 concrete:

  • Chunk each document into passages of a few sentences.
  • Embed each chunk with a local embedding model. Ollama serves embedding models as well as chat models, or the sentence-transformers library will run one directly in Python.
  • Store the vectors with their metadata in a local vector store. Chroma keeps a persistent collection in a directory on disk; FAISS is a library that holds an index you save to a file yourself. Either is enough.
  • Retrieve the closest few chunks for a question, assemble them into a prompt template beneath a system prompt, and send the result to the model.

Keep the assembly step visible in the code. Later labs inject content through the documents, and the moment where retrieved text is pasted into the prompt is where that attack lands.

Logging prompts, responses and token counts from the first request onwards

Put a gateway in front of the model before you send the first request: a small local HTTP proxy, written in Python with the standard library or a light web framework, listening on its own port inside the VM and forwarding to the runner. Bind the runner to the loopback address and check that it really is listening there, rather than assuming it, so the gateway is the only way in.

At first the gateway does one thing: it writes a record of every request to a local file, one JSON object per line. Each record should hold the time, a request identifier, the caller, the model name, the full prompt as sent to the model (after the template and retrieved chunks were added, not just the user's question), the identifiers of the retrieved chunks, the response, the prompt and response token counts, the latency and the gateway's decision. The runner reports token counts in its responses, so the gateway records what the model says it used rather than estimating.

Why from the first request: every monitoring, cost and incident lab later on reads this file, and a baseline of normal traffic is only possible if the logging predates the experiments. Lessons 15 and 16 build monitoring and cost alerting on it, and lesson 10 adds the controls that live at this choke point: a prompt firewall, rate limits, token limits and input quotas.

Notice what the log now contains: your restricted document's canary, quoted verbatim inside every prompt that retrieved it. That is not a mistake in the lab. It is the problem lesson 15 solves, and you will have created it yourself.

Snapshots, so a broken guardrail experiment costs thirty seconds

Once the VM is built, isolated and proven (next section), take a baseline snapshot and name it so you will recognise it in a month. Then adopt one habit: snapshot before every lab, revert after it. Reverting a VM takes seconds, whereas diagnosing what a half-finished poisoning experiment left behind in a vector store can take an afternoon.

Three practical points:

  • A snapshot captures everything: the model weights, the vector store and the log file. Reverting therefore discards that lab's logs. Either write findings down before reverting, or keep logs and notes on a separate virtual disk excluded from snapshots, where your hypervisor supports that.
  • A snapshot is not a backup. It lives on the same disk as the VM, and a long chain of snapshots slows the VM and consumes space. Delete the ones you no longer need.
  • Take a fresh baseline when you deliberately change the build, for example after adding a second model, so later reverts do not undo it.

The snapshot is what makes the course's labs safe to get wrong. A guardrail you misconfigured, a document store you corrupted, a gateway rule that blocks everything: all of them cost one revert.

Proving the isolation before the first lesson that changes a setting

"The VM is isolated" is a claim, and a claim about your own conduct needs evidence. Prove it once, from both sides, and record the result next to the baseline snapshot.

From inside the VM:

  • The routing table has no default route, and the only interface is the host-only or internal one.
  • Name resolution of a public domain fails, and a request to a public address by number fails with no route or times out. A "connection refused" is not a pass: a refusal means something on the path answered.
  • The address of your home router and of another device on your real network are unreachable.
  • Shared folders, clipboard sharing and drag and drop are off, checked in the hypervisor's settings for this VM rather than remembered.

From the host and your network:

  • The runner's port and the gateway's port are not reachable from the host except through the host-only adapter, and not at all from another device on your network.
  • No port forwarding rule exists for the VM.

Then plant a check that proves the test can fail: temporarily reconnect the adapter, rerun the "public address" test, and watch it succeed. A test that has never been seen to fail has not shown that it detects anything. Disconnect again, rerun, record both results, and only then take the baseline snapshot.

Repeat the proof whenever you change the VM's network settings, and before any lab that tells you to plant hostile content. The proof takes five minutes; its absence is the one way this lab could hurt something you care about.

Practise what you just read

1. The lab VM has fetched its packages, runner and model weights. How should its network adapter then be set?

Select one

  1. Host-only or internal, with no default gateway
  2. Bridged to a separate guest Wi-Fi network
  3. NAT behind the host’s own software firewall
  4. NAT, forwarding only the runner’s port inward
Show answer

A. The VM needs the internet exactly once. After that a host-only or internal network with no default gateway leaves no route to anything you did not build. A guest Wi-Fi network still reaches the internet, and port forwarding is one of the hidden routes the lesson says to turn off.

2. Why does the lab plant a made-up canary string in the one restricted document?

Select one

  1. So the embedding model can rank that chunk higher
  2. So the model learns to refuse to quote that file
  3. So any leak can be proven by a plain text search
  4. So the gateway can encrypt that document’s chunks
Show answer

C. The canary is a token that appears nowhere else, so if it turns up in a response or a log line where it should not, something leaked, and a text search proves it. It gives every leakage experiment an unambiguous test. It does nothing to the document’s ranking or to the model’s behaviour.

3. During the isolation proof, a request from inside the VM to a public address returns “connection refused”. How should this be recorded?

Select one

  1. As a fail, as something on the path answered
  2. As a pass, since the connection did not succeed
  3. As a pass, provided DNS resolution also failed
  4. As inconclusive until the runner port is tested
Show answer

A. A pass is no route or a timeout. A refusal means some device on the path answered, so a route out exists even though this one port was closed. Failed name resolution is a separate check and cannot turn a refusal into a pass.

7 more questions on this objective are part of the full course.

Practise the full question bank in the exam simulator

Hands-on labs

All hands-on labs

This is an independent study companion for CompTIA SecAI+ CY0-001 and is not produced by or endorsed by CompTIA.