Documentation is not a control
In vulnerability management there is a distinction I have used for years without thinking about it. A control is a thing that restricts behavior. Documentation is a statement that a control exists. When an assessor finds a documented control that was never verified, that is not a pass. It is a finding, and often a worse one than having no documentation, because everyone downstream relied on the claim.
Then I wrote one of those findings myself, about my own home lab.
The claim
The CI runner on my home server is the thing that picks up jobs when I push code. Hardening it was one of the first things I did, and the notes I wrote said it was registered against a single repository. That sounds small and safe. I repeated it in two places: a comment in the example environment file telling the next person to register from the repo's own settings "so the runner is scoped to this repo only", and a line in the runner's README.
I also repeated it in a security table in the website's README, as a control that was holding.
I had never checked it.
How it surfaced
The recipe app lives in its own repository, and I wanted CI build checks for it. The app's side of the project wrote a request to the infrastructure side: please re-register the runner so it also accepts jobs from this second repository. It scored the change against my own mitigation table and reported one control as unchanged and holding: "runner registered repo-scoped".
It had reasoned correctly from what I published. That is the uncomfortable part. The request was careful, and the error was entirely in my docs.
The infrastructure side did what I should have done in the first place before answering. It did not trust the README. It read the runner's registration record from the Git server's own database. The record has fields for which user and which repository the runner belongs to, and the repository field was empty. The runner was never tied to one repository. It had been registered at a wider level from the start, and had accepted jobs from the recipe app's repo before anyone asked.
So the request needed no action, and the control in my table did not exist.
Why it mattered
A runner executes whatever a workflow tells it to. The question of which repositories are allowed to send it work is the question of whose code runs on your hardware, with whatever that runner has been granted. I had written down a small answer to that question and the true answer was larger.
I am not going to describe the specifics of what the runner can reach, because this is my live infrastructure and a blog post is a poor place for a map. The shape is enough: a privilege I had reasoned about as belonging to one repository was available more widely than I thought.
What I did
I changed the docs first, and I made the correction checkable instead of believable. The new text quotes the database record and says when it was read, so the next reader can run the same check instead of trusting me.
Then I made a decision, and wrote it down as a decision. I looked at the realistic threat, which is that I author every repository involved, so the likely failure is a buggy workflow and not a hostile one. I looked at the cost of narrowing it, which is another runner. I accepted the risk, dated it, and recorded the conditions that would reopen it. I want to be plain about this: the scope is not narrowed today. It is documented accurately, accepted on purpose, and on the backlog.
That is a different thing from what I had before. An accepted risk with a reason and a trigger is a control decision. A false claim of a control is a hole with a label on it.
The same mistake twice
It was not the only time. A note in my Pi-hole docs listed which devices on my network used it for
DNS, and it was wrong. My workstation was listed and was not actually using it. That mattered
because Plex clients connect through names under plex.direct, which are public names that
resolve to private addresses. My ISP's gateway has DNS rebinding protection, and it refuses to
answer exactly that pattern. A machine using the router for DNS simply could not reach the server
on my own network.
What settled it was not rereading the note. It was reading the DNS server's query log and seeing which source addresses actually appeared. Two did.
What changed in how I write
I now separate what I verified from what I intended. Anything I assert as a fact gets the command or the record that proves it, and the date. Anything I only meant to do is labeled as an intention.
An assessor would call that the difference between a statement of work and evidence. I should have held my own docs to the standard I hold everyone else's.