Get the Zoom link

Working a Finding

A scanner can tell you something is true. It cannot tell you whether anyone can reach it, who would have to change it, or whether your fix will survive the next deploy.

· · Vendor-neutral · View source on GitHub

The 30-second version: Before you open a ticket, answer four questions. Is it reachable by anyone you do not already trust? Who owns the identity that would have to change? What is the smallest fix that removes the exposure, rather than a new alert about it? How will you know it stayed fixed after the ticket is closed? A finding you cannot answer those for is a backlog item, not an incident, and it should be labelled that way.

On this page

  1. What a finding actually is
  2. Is it reachable?
  3. Who owns the identity?
  4. The smallest fix
  5. How you know it stayed fixed
  6. What the ticket should say
  7. Where next

What a finding actually is

A finding is a statement a tool is willing to stand behind: this resource has this property, or this package has this advisory, or this identity took this action. The statement can be right and still be the wrong thing to do next. Public storage with no data, an admin role that nothing can assume, and a critical CVE in a library the process never loads are all "true." They are not the same amount of work, and they are not the same amount of risk.

Tools disagree with each other because they are answering different questions. A CSPM says the configuration allows something. A vulnerability scanner says the code contains something. A detector says something happened. Working the finding starts by writing down which of those three you are holding. The rest of this page is the same four questions for all three. The evidence you need is different. The shape of the decision is not.

Is it reachable?

Reachable means someone you do not already trust can exercise the condition without first becoming you. That is a higher bar than "the resource exists" and a lower bar than "we have seen it exploited."

Write the answer in one sentence a reviewer can check: "internet to TCP 443 on the load balancer, then to this task role, which can read the production bucket." If you cannot write the sentence, you do not yet know that it is reachable, and the next action is to find out, not to declare an incident.

Who owns the identity?

Every finding is attached to an identity, even when the tool shows you a resource. The resource was created by a role. The role is assumed by a pipeline, a person, or a workload. The person is in an IdP group that some team owns. If you cannot name that team, the finding underneath the finding is that the identity has no owner.

Look in this order.

  1. The cloud identity on the event or the resource: the role, the service account, the managed identity, the access key's user.
  2. What is allowed to become that identity. A trust policy, a Kubernetes service-account annotation, a federated issuer, a group membership. This is usually the real owner, because the role itself is a costume.
  3. The deploy path. The repository and the pipeline that last applied the change. A finding in a resource that Terraform owns will come back if you click-fix it in the console. The owner is the module, not the console user.
  4. The human. Only after the three above. "Security team" is not an owner. Neither is the vendor who sold the scanner.

A workload identity with no tag, no repository, and no group is the case to stop and fix the ownership before you fix the permission. Otherwise you will "remediate" it, and the pipeline that nobody owns will put it back on Thursday. The IAM guide covers why these identities sprawl. This page only needs you to name one of them per finding.

The smallest fix

The smallest fix is the change that removes the reach, and nothing else. It is almost never "deploy a new product" and it is almost never "add a detection so we notice next time."

Prefer the fix in the system that owns the resource. If Terraform applied it, the pull request is the fix and the console click is a drift. If a person needs the access once a quarter, just-in-time elevation is the fix and a standing admin role is the finding you are about to recreate.

Watch the blast radius of the fix itself. Tightening a role that a production deploy uses, on a Friday afternoon, without the owner in the room, is how a security change becomes the outage. Smallest means smallest safe change, applied by the owner, with a way back.

How you know it stayed fixed

Closing the ticket because the scanner went green is not the same as the condition staying gone. Scanners look on a schedule. Pipelines apply on a commit. The commit wins.

The control that keeps a fix is preventive, and it lives above the account that has the bad habit.

Where you cannot prevent, you re-detect on purpose and you say so in the ticket: "no org policy exists for this; the scanner runs nightly; reopen if the resource returns." That is an honest residual. Pretending the nightly scan is a control is how the same finding comes back with a new id and a new owner and gets worked from the top.

The log of the fix belongs in the same place as the log of the original change. If you cannot see the policy attachment or the pull request in the control-plane log, you will not be able to answer "who undid this" when it happens.

What the ticket should say

Four lines, matching the four questions. Anything the tool already put in the description can stay as an appendix.

  1. Reach. One sentence. Who can exercise this, from where, and what it grants.
  2. Owner. The team, the repository, and the identity. "Unowned" is an acceptable value and it changes the first task.
  3. Fix. The smallest change, where it will be made (pull request, policy, console), and what it will break if you are wrong.
  4. Stays fixed. The preventive control, or the explicit statement that there isn't one and how it will be reopened.

Severity comes after those four lines, not before. A critical CVE that is not reachable and a low finding that is an anonymous production bucket should not be ordered by the badge the vendor printed. If you need a number for a dashboard, derive it from reach and data, and keep the vendor's number beside it so you can explain the disagreement.

Some findings are incidents. You can tell because the reach has already been used: a credential that authenticated from somewhere it should not, a trail that stopped, a bucket that was listed by an identity you do not know. That is incident response, and the four questions still apply, on a shorter clock, with the owner in the call rather than in the ticket queue.

Where next