This hunt targets adversaries exploiting AI agents with exposed hard-coded credentials to facilitate unauthorized access and lateral movement via MITRE techniques T1552 and T1078. Proactively identifying these static secrets within Azure Sentinel is critical because compromised agent configurations often serve as persistent entry points for attackers seeking to pivot across cloud environments without triggering standard authentication alerts.
let suspicious_patterns = @"(AKIA[0-9A-Z]{16})|(AIza[0-9A-Za-z_\-]{35})|(xox[baprs]-[0-9a-zA-Z]{10,48})|(ghp_[A-Za-z0-9]{36,59})|(sk_(live|test)_[A-Za-z0-9]{24})|(SG\.[A-Za-z0-9]{22}\.[A-Za-z0-9]{43})|(\d{8}:[\w\-]{35})|(eyJ[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+)|(Authorization\s*:\s*Basic\s+[A-Za-z0-9=:+]+)|([A-Za-z]+:\/\/[^\/\s""']+:[^\/\s""']+@[^\/\s""']+)";
let IdentityIdtoUPN = materialize (
IdentityInfo
| where isnotempty(AccountObjectId) and isnotempty(AccountUpn)
| summarize arg_max(Timestamp, AccountUpn) by AccountObjectId
| project AccountObjectId = tostring(AccountObjectId), AccountUpn);
AgentsInfo
| summarize arg_max(Timestamp, *) by AgentId
| where LifecycleStatus != "Deleted"
| extend ToolsStr = tostring(DeclaredTools), TriggersStr = tostring(Triggers), McpStr = tostring(McpServers), SkillsStr = tostring(Skills), CapsStr = tostring(Capabilities), RawStr = tostring(RawAgentInfo)
| where ToolsStr matches regex suspicious_patterns
or TriggersStr matches regex suspicious_patterns
or McpStr matches regex suspicious_patterns
or SkillsStr matches regex suspicious_patterns
or CapsStr matches regex suspicious_patterns
or RawStr matches regex suspicious_patterns
or Instructions matches regex suspicious_patterns
| extend OwnerId = tostring(Owners[0])
| join kind=leftouter IdentityIdtoUPN on $left.OwnerId == $right.AccountObjectId
| project-rename OwnerUpn = AccountUpn
| project-away OwnerId, AccountObjectId, RawStr
| project-reorder CreatedDateTime, AgentId, Name, Platform,Instructions, ToolsStr, TriggersStr, McpStr, SkillsStr,CapsStr, OwnerUpn
id: fdc8a7ec-586d-4021-a78a-d27544986178
name: AI Agents - Hard-coded credentials in Tools or Configuration
description: |
This query identifies AI agents that contain hard-coded credentials in their declared tools, triggers, MCP servers, skills, capabilities, or raw agent configuration.
Storing credentials in clear text within agent logic creates a security risk because these secrets can be exposed to unintended users or attackers.
If compromised, credentials could allow unauthorized access to external systems, APIs, or sensitive data.
Recommended Action: Avoid embedding credentials directly in tools or configuration. Use secure alternatives
such as Azure Key Vault with environment variables or enable secured input options for sensitive fields.
Regularly audit agents for hard-coded secrets and rotate any exposed credentials immediately.
requiredDataConnectors: []
tactics:
- CredentialAccess
- InitialAccess
relevantTechniques:
- T1552
- T1078
query: |
let suspicious_patterns = @"(AKIA[0-9A-Z]{16})|(AIza[0-9A-Za-z_\-]{35})|(xox[baprs]-[0-9a-zA-Z]{10,48})|(ghp_[A-Za-z0-9]{36,59})|(sk_(live|test)_[A-Za-z0-9]{24})|(SG\.[A-Za-z0-9]{22}\.[A-Za-z0-9]{43})|(\d{8}:[\w\-]{35})|(eyJ[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+)|(Authorization\s*:\s*Basic\s+[A-Za-z0-9=:+]+)|([A-Za-z]+:\/\/[^\/\s""']+:[^\/\s""']+@[^\/\s""']+)";
let IdentityIdtoUPN = materialize (
IdentityInfo
| where isnotempty(AccountObjectId) and isnotempty(AccountUpn)
| summarize arg_max(Timestamp, AccountUpn) by AccountObjectId
| project AccountObjectId = tostring(AccountObjectId), AccountUpn);
AgentsInfo
| summarize arg_max(Timestamp, *) by AgentId
| where LifecycleStatus != "Deleted"
| extend ToolsStr = tostring(DeclaredTools), TriggersStr = tostring(Triggers), McpStr = tostring(McpServers), SkillsStr = tostring(Skills), CapsStr = tostring(Capabilities), RawStr = tostring(RawAgentInfo)
| where ToolsStr matches regex suspicious_patterns
or TriggersStr matches regex suspicious_patterns
or McpStr matches regex suspicious_patterns
or SkillsStr matches regex suspicious_patterns
or CapsStr matches regex suspicious_patterns
or RawStr matches regex suspicious_patterns
or Instructions matches regex suspicious_patterns
| extend OwnerId = tostring(Owners[0])
| join kind=leftouter IdentityIdtoUPN on $left.OwnerId == $right.AccountObjectId
| project-rename OwnerUpn = AccountUpn
| project-away OwnerId, AccountObjectId, RawStr
| project-reorder CreatedDateTime, AgentId, Name, Platform,Instructions, ToolsStr, TriggersStr, McpStr, SkillsStr,CapsStr, OwnerUpn
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: OwnerUpn
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: Name
version: 1.0.0
| Sentinel Table | Notes |
|---|---|
IdentityInfo | Ensure this data connector is enabled |
Here are 4 specific false positive scenarios for the AI Agents - Hard-coded credentials rule, including suggested filters and exclusions:
DevOps CI/CD Pipeline Integration via GitHub Actions
GITHUB_TOKEN within its raw JSON configuration. This token is used by the “GitHub MCP Server” tool to authenticate API calls for fetching repository metadata during scheduled nightly builds, but it is intentionally static to avoid complex secret rotation logic in this specific sandbox environment.tool_name equals "github-mcp-server" AND the credential field matches the regex pattern ^ghp_[A-Za-z0-9]{36}$, provided the agent’s environment_tag is set to "sandbox" or "ci-cd".Internal Knowledge Base Search via Microsoft Graph
Microsoft Graph tool to query the internal SharePoint document library for policy updates during business hours (08:00–18:00 UTC). The credentials are static because they belong to a dedicated service account with limited scope permissions, not requiring frequent rotation.capability_name contains "sharepoint-search" AND the credential string includes "client_secret", restricted to execution windows between 08:00 and 18:00 UTC on weekdays.Legacy Data Ingestion via AWS S3 Connector
AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY embedded in its tool