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
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."
- Network. Is the port, the bucket, the cluster API, or the function URL on a path from the internet, from a partner, or only from inside a network you control? A security group of
0.0.0.0/0on a database port is reachable. The same port on a private subnet with no route is not, until someone adds the route. - Identity. If the network is closed, who can still call the API? An over-privileged role that any workload in the account can assume is reachable by every person who can compromise any workload. An over-privileged role that nothing trusts is a loaded gun in a drawer. Still worth unloading. Not the same page as the first one.
- Data. What does the reachable thing grant? A public bucket of a marketing site is a different finding from a public bucket of database backups. The configuration defect can be identical. The reach, in the sense that matters, is not.
- Code. For a vulnerability, reachability is whether the vulnerable function is on a path the process actually takes, with an input an outsider can influence. KEV and EPSS tell you whether the bug is being used in the world. They do not tell you whether your build calls it. Both facts belong in the ticket. Neither one replaces the other.
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.
- The cloud identity on the event or the resource: the role, the service account, the managed identity, the access key's user.
- 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.
- 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.
- 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."
- Remove the permission the identity does not need. A detective control that fires when the identity reads the bucket is a worse fix than deleting
s3:GetObjectfrom a role that deploys code. - Close the path. Block public access, delete the
0.0.0.0/0rule, make the cluster API private. Do not "monitor" a path you are allowed to close. - Shorten the credential instead of rotating a long-lived key forever. Federation, workload identity, or an OIDC trust for the pipeline. Rotation is what you do for the keys you have not eliminated yet.
- Upgrade or remove the dependency when the vulnerable function is actually reachable. Pinning a scanner exception on a library you can bump is how the exception becomes the permanent state.
- An exception with an expiry when the business truly needs the condition. The expiry is part of the fix. An exception with no date is a finding you have agreed to stop looking at.
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.
- A service control policy, an Azure Policy deny, a GCP organization policy, or an admission policy that makes the bad shape undeployable. The scanner will go quiet because the shape cannot return, not because someone promised.
- A pipeline check on the module that produced the resource, so the next apply fails in review instead of in production.
- An alert on the control itself being detached. A policy exemption, a detached SCP, or an organization policy set to "not enforced" is the new finding, and it is a smaller list than the original one.
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.
- Reach. One sentence. Who can exercise this, from where, and what it grants.
- Owner. The team, the repository, and the identity. "Unowned" is an acceptable value and it changes the first task.
- Fix. The smallest change, where it will be made (pull request, policy, console), and what it will break if you are wrong.
- 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
- Logging and telemetry is how you know whether the condition was used, and whether your control is still attached.
- Vulnerability management is the longer version of reachability for bugs in code and images.
- IAM and identity is the longer version of "who owns this role."
- Cloud SOC is where findings and detections get an owner and a clock.
- Detection and response on the topic map.