Service accounts, API keys and OAuth apps fail in a small number of repeating ways. None of them is a vulnerability, all of them are decisions nobody made, and each one has a fix that is a change to access.
Published Last reviewed
Non-human identity security is the practice of knowing which machine identities exist, who owns them, what they can reach and how to change that without breaking the systems that depend on them. It is an access problem rather than a malware problem: almost every incident in this area is made of valid credentials used by the wrong thing.
That is why the seven risks below are not vulnerabilities. None of them has a patch. Each one is a decision that was never made, and each one has a fix that is a change to access rather than to code.
Nothing here is exploited. All of it is granted, then forgotten.
Ordered by how often they turn a single compromised credential into an incident that reaches data.
An API key or client secret with no expiry is a password that never changes and that nobody types, so nobody notices it leaking. It sits in a config file, an environment variable, a CI secret and a developer laptop at the same time. The fix: issue short-lived credentials from the platform where the system supports it, and give every remaining static key an owner and a rotation date you can check.
An identity without an owner cannot be reviewed, because there is nobody who can say what it is for. The safe-looking choice is to leave it alone, which is how a service account keeps broad access for years. The fix: require a named owner as a field on the identity itself, not in a wiki, and treat an identity whose owner has left as an open item rather than a background risk.
Each new task adds a permission and no task ever removes one. After two years a reporting account can write where it only ever needed to read. The fix: derive the permissions the identity actually used over the last ninety days, propose that as the new scope, and keep the difference visible so the reduction is a decision rather than a guess.
One key used by four jobs cannot be rotated without breaking three of them, and its log lines cannot be attributed to any of them. Sharing turns a small change into an outage risk. The fix: split the identity per consumer before you need to rotate it, starting with the ones that touch production.
An employee clicks Allow once and a third-party app holds mail, drive or CRM access from then on. The grant survives password changes and shows up in no access review. The fix: list every grant with its scopes and its approver, revoke what is unused, and review the rest on a schedule rather than after a vendor incident.
A credential is not only exposed where it is used. Anything running in the same shell, container or CI job can read it, which is how a coding agent inherits a deploy token it was never given. The fix: keep production credentials out of jobs and machines that do not need them, and check what else can read a secret before deciding it is safely stored.
Most systems log that a key was used. Few record which workload used it, so after an incident you cannot say which of the four consumers made the call. The fix: make identity per consumer the precondition for useful logs, then keep the log long enough to cover the window an incident is usually discovered in, which is months rather than days.
The same table read from the other end: not what the risk is, but what you cannot do once an incident has started.
| Risk | What it costs you in an incident | First move |
|---|---|---|
| Static credentials | The leaked key still works, so containment means finding every copy. | Expiry and a rotation date |
| No owner | Nobody can say what breaks if you revoke it, so revocation waits. | Owner as a required field |
| Grown permissions | The blast radius is far wider than the job the identity does. | Scope to ninety days of real use |
| Shared identity | Rotating it breaks systems you did not know depended on it. | Split per consumer |
| Stale OAuth grant | A vendor breach reaches your data through access you forgot about. | List grants with scopes |
| Readable secrets | An agent or job inherits access it was never granted. | Separate what runs together |
| Thin audit trail | You cannot answer which workload made the call. | One identity per consumer |
In an environment with hundreds of identities, the order matters more than the completeness.
A policy for identities you cannot list changes nothing. Pull the identities from cloud IAM, CI secrets, SaaS admin panels and local agent configuration, and accept that the first list is incomplete.
Rank what you found by the sensitive data it can get to, through roles it can assume as well as its own permissions. A key with production data behind it outranks fifty keys that reach a wiki.
Take the few identities with real reach and change one step each: scope a role, split a shared key, revoke a grant. Measure the result by paths closed, not by findings resolved.
Put the owner field, the expiry and the per-consumer split into how identities are created, so the same work does not come back next quarter.
Short answers on securing service accounts, keys and the agents that use them.
Secrets management stores and delivers credentials safely. NHI security asks what the credential is allowed to reach once it has been delivered. A vault is necessary and does not answer the second question: the AWS AgentCore case is an example where the vault held and the process around it did not.
Four places cover most of them: OAuth consent and token logs in Google Workspace or Microsoft Entra ID, CI secret stores and workflow files, MCP and agent configuration on developer machines, and model provider keys billed to the organisation. Each one is a list somebody can export today.
The controls are the same: owner, scope, expiry, separation. What changes is the speed and the direction. An agent can walk several steps in seconds, and it can be steered by its input, so a path that looked theoretical on a cron job becomes reachable on an agent.
The pages that belong to the same picture.
Book a demo and we walk through the access paths in an environment like yours.