Taming Orphaned AI Agents: The Shadow Access Crisis
Has anyone else noticed a massive spike in "ghost" service accounts since internal AI tool adoption went mainstream? I just read the report on orphaned agents—tools created by staff who have since left the company, leaving API keys and standing privileges wide open.
In our environment, we found a custom Python bot for automated code reviews still running with Write permissions to our core repository, even though the developer who built it left six months ago. The administrative debt is real.
I've started hunting these down by correlating inactive users with active API usage. Here is a KQL query for Microsoft Sentinel that flags successful authentication attempts to known AI services from disabled accounts:
SigninLogs
| where AppDisplayName contains "OpenAI" or AppDisplayName contains "Copilot" or AppDisplayName contains "LangChain"
| where Result == "Success"
| summarize LastSeen = max(TimeGenerated), CallCount = count() by UserPrincipalName, AppDisplayName
| join kind=leftanti (
AADUserStatus
| where AccountEnabled == true
) on UserPrincipalName
We are implementing a policy where all autonomous agents must use Managed Identities with strict expiration dates, but auditing the legacy mess is painful.
How are you handling the lifecycle management for internal AI agents? Are you banning custom agents or forcing them into specific, governed platforms?
This is exactly why we forced all AI development through a centralized gateway. We stopped allowing devs to spin up individual API keys entirely. By routing everything through a proxy, we can kill access instantly upon offboarding. It was painful at first, but the visibility is worth it.
Great query. To expand on this, you should also check for 'Zombie' Webhooks in your Slack and Teams environments. I often find orphaned agents posting notifications to private channels long after the project is dead.
# Get all teams webhooks older than 90 days
Get-TeamChannel -GroupId | Get-TeamChannelWebhook | Where-Object {$_.Created -lt (Get-Date).AddDays(-90)}
We tackled this by integrating our IAM system with our HRIS. When a termination ticket is triggered, an automated script scans for specific tags like 'ai-agent' or 'bot-script' associated with that user's Service Principal and forces a disable. It's not perfect, but it stops the obvious low-hanging fruit.
Spot on. On the offensive side, we often find these dormant keys because admins forget to enforce credential rotation. You should audit for 'LastUsedDate' metadata. If you're on AWS, this Python snippet helps flag service accounts with active keys that haven't been touched in 90 days:
import boto3
from datetime import datetime, timedelta, timezone
client = boto3.client('iam')
threshold = datetime.now(timezone.utc) - timedelta(days=90)
for user in client.list_users()['Users']:
keys = client.list_access_keys(UserName=user['UserName'])['AccessKeyMetadata']
for key in keys:
if key['Status'] == 'Active' and key['CreateDate'] {key['AccessKeyId']}")
Catching these before an attacker does is crucial.
Don't overlook scanning your code repositories. If that Python bot’s credential was committed to Git, revoking the account doesn't remove the key from history. We integrate trufflehog into our CI/CD pipelines to catch these immediately.
docker run --rm -v "$PWD:/pwd" trufflesecurity/trufflehog:latest filesystem --directory /pwd
Finding the key in the source usually reveals the orphaned infrastructure still hosting it.
Verified Access Required
To maintain the integrity of our intelligence feeds, only verified partners and security professionals can post replies.
Request Access