In August 2025, a threat actor group tracked as UNC6395 stole OAuth refresh tokens from a popular sales platform integration. OAuth (Open Authorization) is a system that lets one application access another on your behalf — a refresh token is a long-lived credential that keeps that access alive indefinitely without re-prompting the user. Using those tokens — which never expired and were never rotated — they silently accessed Salesforce data from over 700 customer environments. No malware. No phishing. No brute force. Just a forgotten token doing exactly what it was designed to do: authenticate quietly and automatically.
Nobody had noticed the token. It wasn’t in the password manager. It wasn’t in the identity provider. It existed in a configuration file, authorized years earlier by an employee who had since left the company.
This is the NHI problem.
TL;DR
- Non-human identities (service accounts, API keys, OAuth tokens, machine credentials) now outnumber human identities 144 to 1 in the average enterprise
- 97% of these identities have excessive privileges; 71% are never rotated
- Attackers are actively pivoting to NHIs because they’re easier to abuse and harder to detect than compromising human accounts
- Most organizations have no inventory of their NHIs, no rotation policy, and no monitoring
- This is fixable — but only if you start treating machine credentials with the same seriousness as human ones
What Is a Non-Human Identity?
A non-human identity (NHI) is any credential, token, or secret that allows a piece of software — not a person — to authenticate to a system. You probably have thousands of them and don’t know where most of them are.
Common NHI types:
| Type | Example | Where It Lives |
|---|---|---|
| API keys | GitHub token, AWS access key | Code repos, config files, env vars |
| Service accounts | AD service account for backup software | Active Directory, Azure/Entra ID |
| OAuth tokens | Google Workspace app authorization | SaaS platform settings |
| Certificates | TLS client cert for internal service | Certificate store, HSM (Hardware Security Module) |
| CI/CD secrets | GitHub Actions secret, GitLab CI variable | Pipeline configuration |
| Database credentials | App user connecting to PostgreSQL | Application config, secrets manager |
| Cloud IAM roles | EC2 instance role, Lambda execution role | Cloud provider IAM (Identity and Access Management) |
These identities are created constantly — by developers spinning up new integrations, by SaaS platforms during onboarding, by cloud automation scripts. They accumulate silently. Nobody deletes them when the project ends or the employee leaves.
The Scale Is Hard to Comprehend
The numbers from 2026 research make this concrete:
- NHIs grew 44% from 2024 to 2025
- They now outnumber human identities at a ratio of 144:1 — up from 92:1 just a year earlier
- 97% of NHIs have excessive privileges (Entro Security, 2025 State of NHI Report)
- 71% are not rotated within recommended timeframes
- SpyCloud’s 2026 Identity Exposure Report documented 8.6 billion stolen cookies and session artifacts actively circulating among threat actors
The 144:1 ratio deserves some context. If your organization has 500 employees, you likely have 72,000 non-human identities — service accounts, API keys, tokens, machine certificates. How many of them can you list right now? How many have admin-level permissions? How many haven’t been touched in over a year?
Most security teams, if honest, would admit the answer to all three questions is: we don’t know.
Why Attackers Love NHIs
Human identity security has improved dramatically over the past decade. Multi-factor authentication is now standard. Conditional access policies flag unusual logins. UEBA (User and Entity Behavior Analytics — software that flags suspicious patterns by comparing activity against a baseline) systems detect when a user logs in from an unusual location. Password managers and SSO (Single Sign-On — logging into multiple services with one set of credentials) have reduced credential reuse.
Machine identities have none of this.
NHIs rarely have MFA. An API key authenticates with a single string. There’s no second factor. There’s no login prompt. The key works from anywhere.
NHIs aren’t covered by conditional access. A service account connecting from an unexpected IP at 3 AM typically generates no alert. It’s a machine — it’s supposed to connect at odd hours.
NHIs have long or infinite lifetimes. Human passwords expire. OAuth tokens can be configured to never expire. API keys are often generated once and never rotated. A key generated in 2019 might still be valid in 2026.
NHIs are over-privileged by default. Developers provisioning credentials tend to grant broad permissions to avoid debugging access errors later. “We’ll tighten this up before production” is a sentence that typically never resolves to action.
Compromised NHIs are silent. When a human account is compromised, the victim may notice — suspicious login emails, MFA prompts they didn’t initiate, IT Help Desk calls. When a service account is compromised, the attacker just uses it. There are no humans to notice.
Real-World Attack Chains
The Cloudflare Incident
During incident response following the Okta breach in 2023, Cloudflare reset thousands of credentials. They missed a few — specifically, one Atlassian service account token and some supporting credentials that had been compromised during the initial Okta attack. Attackers who had been dormant came back in November 2023 using exactly those overlooked credentials, accessing Cloudflare’s internal Atlassian environment including source code repositories.
The lesson: one unrotated NHI survived a thorough incident response and provided attackers a second entry point months later.
Salesloft / SaaS Supply Chain (2025)
UNC6395 compromised OAuth refresh tokens for a sales integration platform. Because these tokens authorized access to connected Salesforce instances — and because Salesforce trusted them by design — the attackers could read emails, files, and support records across 700+ customer environments. No Salesforce vulnerability was exploited. The tokens were working exactly as intended.
BeyondTrust API Key Theft (2024)
Attackers breached BeyondTrust’s systems using zero-day vulnerabilities, then used a stolen API key to compromise 17 Remote Support SaaS instances. The API key provided the attackers with the access they needed to pivot into customer environments. A single key, properly secured and monitored, could have significantly contained the blast radius.
2,800 Live Google API Keys in Public Web Data (2025)
TruffleSecurity scanned the November 2025 Common Crawl dataset — a snapshot of publicly accessible web content — and found 2,800+ live, functioning Google API keys belonging to real organizations, including major financial institutions and security companies. These weren’t keys in private repos. They were in publicly accessible code, documentation, or web content. They had never been rotated or revoked.
The AI Agent Multiplier
This problem is about to get significantly worse. AI agents — autonomous software systems that call APIs, read files, send emails, and take actions on behalf of users — are being deployed at scale across enterprises.
Each AI agent needs credentials. An agent that summarizes emails needs OAuth access to your mail system. An agent that manages cloud infrastructure needs IAM permissions. An agent that queries your CRM needs an API key.
An AI agent is, by definition, a non-human identity. It’s also typically:
- Authorized with broad permissions (“we’ll scope this down later”)
- Running continuously without human oversight
- Difficult to audit (“what exactly did the agent do between 2 AM and 4 AM?”)
The NHI ratio, currently at 144:1, will accelerate sharply as AI agent adoption grows through 2026. The organizations that haven’t solved the NHI inventory problem today will face a significantly harder version of that problem in 12 months.
What Good Looks Like
Step 1: Build an Inventory
You cannot protect what you cannot see. The first step is a complete inventory of NHIs across your environment. This means:
For cloud environments (AWS, Azure, GCP):
# List all IAM users (non-human service accounts) in AWSaws iam list-users --query 'Users[?contains(UserName, `svc-`) || contains(UserName, `service`)]'
# Find access keys older than 90 daysaws iam generate-credential-reportaws iam get-credential-report --query 'Content' --output text | base64 -d | \ awk -F',' 'NR>1 && $9 != "N/A" {print $1, $9}'For Active Directory service accounts:
# Find service accounts with passwords that never expireGet-ADUser -Filter {PasswordNeverExpires -eq $true -and Enabled -eq $true} ` -Properties PasswordNeverExpires, LastLogonDate, Description | Select-Object Name, LastLogonDate, DescriptionFor GitHub / GitLab secrets: Use tools like TruffleHog or Gitleaks to scan repositories for committed credentials:
trufflehog git https://github.com/your-org/your-repo --only-verifiedStep 2: Apply Least Privilege — Actually
The default pattern is over-provisioning followed by “we’ll fix it later.” Later never comes. For every NHI in your inventory, ask:
- What resources does this identity actually need to access?
- What actions does it actually need to perform?
- What’s the minimum permission set that allows those actions?
An API key that only needs to read from one S3 bucket should not have s3:* on *. A service account that only needs to query one database table should not be a DBA.
Step 3: Rotation Policy
The NIST recommendation for API credentials is rotation every 90 days at maximum. Reality is different — 71% of NHIs never rotate.
A rotation policy has two parts:
Automated rotation where possible:
- AWS IAM credentials → use IAM roles with temporary credentials via STS (AWS Security Token Service — issues short-lived access tokens automatically) instead of long-lived access keys
- Database passwords → AWS Secrets Manager, HashiCorp Vault, or Azure Key Vault with automatic rotation
- Service account passwords → Group Managed Service Accounts (gMSA) in Active Directory — a special account type that automatically rotates its own password on a set schedule, no human involvement needed
Enforced rotation where automation isn’t possible:
- API keys for third-party services: quarterly rotation minimum, tracked in a secrets manager
- OAuth tokens: implement token expiration and refresh flows; never use non-expiring tokens in production
Step 4: Monitor for Anomalies
Once you have an inventory, you can build detection. NHI abuse has a distinct fingerprint:
- Service account logging in from an unexpected IP or geographic location
- API key usage outside normal business hours when automation doesn’t run
- Credentials accessing resources they’ve never accessed before
- Sudden spike in API calls from a single service account
In AWS CloudTrail:
# Find access key usage from unusual IP rangesaws cloudtrail lookup-events \ --lookup-attributes AttributeKey=Username,AttributeValue=svc-backup-account \ --start-time 2026-03-01 | jq '.Events[] | {time: .EventTime, ip: .CloudTrailEvent | fromjson | .sourceIPAddress, event: .EventName}'In Azure/Entra ID Sign-in logs, filter for service principals and look for:
signInActivityfrom IPs not in your expected ranges- Authentication to resources not previously accessed
Step 5: Eliminate Credentials Where Possible
The best credential is one that doesn’t exist. Modern cloud platforms offer identity federation that eliminates the need for long-lived secrets:
- AWS IAM Roles for EC2 instances, Lambda functions, and ECS tasks — no access keys, temporary credentials via instance metadata
- Workload Identity Federation in GCP — Kubernetes workloads authenticate to Google APIs without service account keys
- Azure Managed Identities — VMs and Azure services authenticate without stored credentials
- GitHub Actions OIDC (OpenID Connect — a federated identity protocol that lets services verify each other’s identity without exchanging static secrets) — CI/CD pipelines authenticate to cloud providers without storing API keys as secrets
If you’re still creating long-lived API keys for cloud service integrations, there’s usually a keyless alternative available.
Detection Cheat Sheet
| Behavior | Detection Signal | Tool |
|---|---|---|
| Service account used from new IP | SignIn from unfamiliar IP | Azure Sentinel / Splunk |
| API key used after long dormancy | First use after 30+ days silence | CloudTrail / SIEM |
| Credentials accessing new resources | New resource ARN (Amazon Resource Name)/object in logs | CloudTrail / GuardDuty |
| Unusual volume of API calls | Spike > 3σ from baseline | CloudWatch / Datadog |
| Key found in public repo | TruffleHog / Gitleaks scan hit | CI/CD pipeline check |
| Non-expiring OAuth token in use | Token age > 90 days | OAuth audit report |
The Uncomfortable Inventory Exercise
Before you read the next article, open a new tab and answer these questions about your organization:
- How many service accounts exist in your Active Directory / Entra ID?
- How many AWS IAM users (not roles) exist with access keys?
- When did you last audit GitHub repository secrets?
- Do you have a list of every OAuth application authorized to access your Google Workspace or Microsoft 365 tenant?
- Do any of your service accounts have passwords that never expire?
If you answered “I don’t know” to more than two of these, you have an NHI problem — and statistically, so does every other organization your size.
The good news: this is a solvable problem. It requires inventory, policy, automation, and monitoring. It doesn’t require a new product category or a six-figure budget. It requires treating machine credentials with the same discipline you (hopefully) apply to human ones.
The attackers already treat them that way.
What You Can Do This Week
- Audit IAM users in your cloud environments — identify any with long-lived access keys older than 90 days
- Run TruffleHog or Gitleaks against your internal repositories
- Pull the OAuth app list for your Microsoft 365 or Google Workspace tenant and flag anything you don’t recognize
- Check for service accounts with
PasswordNeverExpires = Truein Active Directory - Review CI/CD secrets — confirm all pipeline secrets are stored in a secrets manager, not hardcoded
- Identify one over-privileged service account and scope down its permissions
Related Posts
- GitHub Secrets Management Crisis — Deep dive into credential exposure in source code repositories
- Identity-First Attacks in the Cloud — How attackers pivot from initial access to cloud dominance using identity
- Entra ID Attacks: Device Code, PRT, and Conditional Access Bypass — OAuth and token abuse techniques in Microsoft environments
- Kerberoasting Deep Dive — How service account credentials get cracked from Active Directory
Sources
- SpyCloud 2026 Identity Exposure Report — Security Boulevard
- Why Non-Human Identities Are Your Biggest Blind Spot in 2026 — CSO Online
- 2026 NHI Reality Report: 5 Critical Identity Risks — Cyber Strategy Institute
- SaaS Breaches Start with Tokens — The Hacker News
- Why Machine Identity Sprawl Is Now a DevSecOps Problem — Security Boulevard
- Third-Party Supply Chain Token Management — Unit 42
- Non-Human Identities Push Identity Security Into Uncharted Territory — Help Net Security
- State of Non-Human Identity and AI Security — Cloud Security Alliance