Back to Intelligence

9,300 Leaked AWS Access Keys Still Active: Detection and Remediation Guide for Exposed IAM Credentials

SA
Security Arsenal Team
August 22, 2026
12 min read

Security researchers have confirmed that more than 9,300 Amazon Web Services access keys exposed publicly between August 2022 and August 2026 are still active and valid — and hundreds of them grant full administrative control over corporate AWS accounts. These are not stale, expired artifacts rotting in old GitHub gists. They are live credentials, harvested from public code repositories, container images, CI/CD logs, developer forums, and misconfigured S3 buckets, sitting in plaintext where any threat actor with a scraper can pick them up and authenticate.

This is not a theoretical exposure problem. Access key leakage is one of the most reliable initial access vectors into cloud environments, and it feeds directly into the playbooks we've responded to for years: cryptomining deployment within hours of a key hitting GitHub, data exfiltration from S3, IAM privilege escalation, and in the worst cases, full account takeover followed by ransomware-style destruction of cloud resources and backups. If a valid AKIA-prefixed key with AdministratorAccess attached is floating around in a public repo, your incident clock started the moment it was committed — not the moment you found out.

Every organization running workloads on AWS needs to treat this as a forcing function: inventory your long-lived credentials, hunt for anomalous use of existing keys, and kill static access keys wherever federation or IAM Roles Anywhere can replace them. This post gives you the detection content and remediation procedures to do exactly that.

Technical Analysis

What Was Exposed and Why It Matters

AWS access keys consist of two parts: an access key ID (prefixed AKIA for long-lived IAM user keys, or ASIA for temporary session credentials from STS) and a 40-character secret access key. Together they authenticate API calls with the exact permissions of the IAM principal they belong to. There is no additional factor. No MFA prompt stands between an attacker holding a leaked key and your control plane unless you've explicitly enforced MFA via IAM policy condition keys (aws:MultiFactorAuthPresent) — which almost nobody does for programmatic access.

The keys identified in this research were scraped from the usual suspects:

  • Public Git repositories — keys committed in source code, config files, .env files, Terraform variable files, and hardcoded in application logic. GitHub's own secret scanning and AWS's proactive key quarantine (AWSCompromisedKeyQuarantineV2 policy) catch many, but coverage is incomplete, especially on GitLab, Bitbucket, self-hosted repos, and forks.
  • CI/CD build logs and artifacts — keys echoed into pipeline output, baked into Docker image layers, or stored as plaintext pipeline variables.
  • Misconfigured public storage — exposed S3 buckets, public AMIs, and EBS snapshots containing credentials files.
  • Developer forums, pastebins, and issue trackers — keys pasted into troubleshooting posts.

The critical finding is dwell time and continued validity: keys leaked as far back as August 2022 still authenticate today. That tells us two things. First, organizations are not rotating or deactivating long-lived keys — many teams don't even have an inventory of which keys exist. Second, AWS's automatic quarantine mechanism only fires when AWS detects the exposure (typically via GitHub scanning partnerships); keys leaked anywhere else live indefinitely until the owner acts.

Attack Chain From a Leaked Key

From an IR perspective, the exploitation chain is deterministic and fast:

  1. Validation — The attacker runs aws sts get-caller-identity (or the equivalent raw API call) to confirm the key is valid and identify the account ID, ARN, and principal. This call is nearly free and appears in CloudTrail as a low-signal event most environments ignore.
  2. Enumerationiam list-attached-user-policies, iam get-user, s3 ls, and service-specific Describe*/List* calls map the key's effective permissions. Tools like Pacu, ScoutSuite, and enumerate-iam automate this in minutes.
  3. Exploitation aligned to permissions — With AdministratorAccess (the 'full control' scenario highlighted in the reporting): create a new IAM user and access key for persistence, enable regions the victim doesn't use, spin up GPU instances for cryptomining, exfiltrate S3/RDS data, or in destructive scenarios, delete resources and snapshots.
  4. Persistence — Attackers commonly create additional access keys on existing IAM users (iam:CreateAccessKey — note the two-key-per-user limit often requires deleting an existing key first, which is itself a high-fidelity signal), backdoor IAM roles by modifying trust policies, or plant Lambda functions with permissive execution roles.

Exploitation Status

This is confirmed active abuse at scale. Credential-based initial access against cloud environments is a standing threat, not an emerging one — cryptojacking crews and initial access brokers monitor public leak sources continuously, and automated validation of freshly committed keys occurs within minutes on monitored platforms like GitHub. There is no CVE here; this is an operational hygiene failure with a well-documented exploitation pattern mapped to MITRE ATT&CK techniques T1078.004 (Valid Accounts: Cloud Accounts), T1552.001 (Unsecured Credentials: Credentials In Files), and T1098.001 (Account Manipulation: Additional Cloud Credentials).

Detection & Response

The detections below focus on the highest-fidelity signals in the leaked-key attack chain: key creation/deletion events (persistence), credential validation from suspicious contexts, and discovery of exposed keys on endpoints. Tune the account/IP allowlists before deployment — a key creation rule with no allowlist in a mature AWS environment should be quiet; in a chaotic one, build the allowlist first.

YAML
---
title: AWS IAM Access Key Created or Deleted on Existing User
tid: 8f3a2c91-4b7e-4d5a-9c1e-6f2a8b3d4e5f
status: experimental
description: Detects creation or deletion of IAM access keys, a common persistence and anti-forensics technique after credential compromise. Attackers delete existing keys to bypass the two-key-per-user limit before creating their own.
references:
  - https://attack.mitre.org/techniques/T1098/001/
  - https://www.bleepingcomputer.com/news/security/hundreds-of-leaked-aws-keys-give-full-control-over-corporate-accounts/
author: Security Arsenal
date: 2026/04/06
tags:
  - attack.persistence
  - attack.t1098.001
logsource:
  product: aws
  service: cloudtrail
detection:
  selection:
    eventSource: iam.amazonaws.com
    eventName:
      - CreateAccessKey
      - DeleteAccessKey
      - UpdateAccessKey
  filter_iam_roles:
    userIdentity.type: AssumedRole
  condition: selection and not filter_iam_roles
falsepositives:
  - Legitimate key rotation by administrators or automation
  - IaC pipelines (Terraform/CloudFormation) managing IAM users; filter on known pipeline principal ARNs
level: high
---
title: AWS GetCallerIdentity From Non-AWS Network
tid: 2b7d4e18-9a3c-4f6b-8d2e-1c5a7b9e3f4d
status: experimental
description: Detects STS GetCallerIdentity calls sourced from IP addresses outside AWS infrastructure. This is the canonical first step in validating a leaked access key and is rarely performed by legitimate users from arbitrary internet hosts.
references:
  - https://attack.mitre.org/techniques/T1078/004/
  - https://www.bleepingcomputer.com/news/security/hundreds-of-leaked-aws-keys-give-full-control-over-corporate-accounts/
author: Security Arsenal
date: 2026/04/06
tags:
  - attack.initial_access
  - attack.t1078.004
logsource:
  product: aws
  service: cloudtrail
detection:
  selection:
    eventSource: sts.amazonaws.com
    eventName: GetCallerIdentity
    userIdentity.type: IAMUser
  filter_aws_internal:
    sourceIPAddress|endswith:
      - '.amazonaws.com'
  filter_known_useragent:
    userAgent|startswith:
      - 'aws-cli/'
  condition: selection and not filter_aws_internal and not filter_known_useragent
falsepositives:
  - Developers running scripts with custom SDK user agents from corporate egress; build a corporate IP allowlist rather than relying on user agent
level: medium
---
title: AWS IAM Privilege Enumeration Burst by IAM User
tid: 5c9e1f74-2d8a-4b3c-a7f6-9e4d2c8a1b5e
status: experimental
description: Detects rapid succession of IAM read/enumeration API calls typical of post-compromise permission mapping with tools such as Pacu or enumerate-iam.
references:
  - https://attack.mitre.org/techniques/T1069/
  - https://www.bleepingcomputer.com/news/security/hundreds-of-leaked-aws-keys-give-full-control-over-corporate-accounts/
author: Security Arsenal
date: 2026/04/06
tags:
  - attack.discovery
  - attack.t1069
logsource:
  product: aws
  service: cloudtrail
detection:
  selection:
    eventSource: iam.amazonaws.com
    userIdentity.type: IAMUser
    eventName:
      - ListAttachedUserPolicies
      - ListAttachedRolePolicies
      - ListUserPolicies
      - ListGroupsForUser
      - GetUser
      - GetPolicyVersion
      - SimulatePrincipalPolicy
  filter_automation:
    userAgent|contains:
      - 'Terraform'
      - 'cloudformation'
  condition: selection and not filter_automation
falsepositives:
  - Security tooling (ScoutSuite, Prowler) running legitimate audits; allowlist the scanner principal ARNs and scheduled windows
level: medium

The third rule will require per-environment tuning — the intent is to baseline IAM enumeration against your known automation and security tooling, then alert on the residue. If your environment runs continuous IaC, consider scoping the rule to IAM users who have not performed these calls in the trailing 30 days (implementable as a Sentinel watchlist join).

KQL — Microsoft Sentinel / Defender
// Hunt for leaked-key attack chain behaviors in AWS CloudTrail (Sentinel AWS connector)
// Looks for: key validation from rare IPs, enumeration bursts, and persistence via new access keys
let Lookback = 14d;
let KnownCorpEgress = dynamic(["203.0.113.10", "198.51.100.25"]); // Replace with corporate egress / VPN ranges
// Stage 1: GetCallerIdentity by IAM users from IPs not seen for that principal in prior 30 days
let HistoricalIPs = AWSCloudTrail
    | where TimeGenerated between (ago(Lookback + 30d) .. ago(Lookback))
    | where EventName == "GetCallerIdentity"
    | summarize by SourceIpAddress, UserIdentityArn;
AWSCloudTrail
| where TimeGenerated > ago(Lookback)
| where EventName in ("GetCallerIdentity", "CreateAccessKey", "DeleteAccessKey", "UpdateAccessKey", "ListAttachedUserPolicies", "SimulatePrincipalPolicy")
| where UserIdentityType == "IAMUser"
| extend SourceIP = tostring(SourceIpAddress)
| where not (SourceIP in (KnownCorpEgress))
| where SourceIP !startswith "10." and SourceIP !startswith "192.168." and SourceIP !startswith "172.16."
| summarize EventCount = count(),
            EventNames = make_set(EventName),
            FirstSeen = min(TimeGenerated),
            LastSeen = max(TimeGenerated),
            UserAgents = make_set(UserAgent)
    by UserIdentityArn, UserIdentityUserName, SourceIP, RecipientAccountId
| where array_length(EventNames) >= 2 or EventNames has "CreateAccessKey"
| extend NewSourceIP = iff(SourceIP in (toscalar(HistoricalIPs | summarize make_set(SourceIpAddress))), "No", "Yes")
| where NewSourceIP == "Yes"
| order by FirstSeen asc
VQL — Velociraptor
-- Hunt for exposed AWS long-lived access keys on endpoints
-- Searches standard credential locations and common project paths for AKIA key IDs
-- Deploy as a hunt across developer workstations and build agents
LET cred_paths = SELECT FullPath, Size, Mtime
FROM glob(globs=[
  '/home/*/.aws/credentials',
  '/root/.aws/credentials',
  'C:/Users/*/.aws/credentials',
  '/home/*/.aws/config',
  'C:/Users/*/.aws/config'
])

SELECT FullPath, Size, Mtime,
       read_file(filename=FullPath, length=100000) AS Content
FROM cred_paths
WHERE Content =~ 'AKIA[0-9A-Z]{16}'

-- Second artifact: scan common repo/env files for hardcoded keys
LET env_hits = SELECT FullPath
FROM glob(globs=[
  '/home/*/**/.env',
  '/home/*/**/terraform.tfvars',
  '/home/*/**/credentials',
  'C:/Users/*/**/.env'
], accessor='file')
WHERE NOT IsDir

SELECT FullPath,
       read_file(filename=FullPath, length=100000) AS Content
FROM env_hits
WHERE Content =~ 'AKIA[0-9A-Z]{16}'
   OR Content =~ 'aws_secret_access_key'

For immediate scoping in your own environment, run the following to enumerate every access key in an account, identify keys older than 90 days, and check last-used data. This requires credentials with iam:ListUsers, iam:ListAccessKeys, and iam:GetAccessKeyLastUsed.

Bash / Shell
#!/bin/bash
# audit-aws-keys.sh - Enumerate IAM access keys, flag age and last use
# Usage: ./audit-aws-keys.sh [aws-profile]
PROFILE=${1:-default}
CUTOFF_DAYS=90
NOW=$(date +%s)

echo "=== AWS Access Key Audit (profile: $PROFILE) ==="
echo ""

aws iam list-users --profile "$PROFILE" --query 'Users[].UserName' --output text | tr '\t' '\n' | while read -r USER; do
  KEYS=$(aws iam list-access-keys --user-name "$USER" --profile "$PROFILE" \
    --query 'AccessKeyMetadata[].[AccessKeyId,Status,CreateDate]' --output text)
  [ -z "$KEYS" ] && continue
  echo "$KEYS" | while read -r KEYID STATUS CREATED; do
    CREATED_EPOCH=$(date -d "$CREATED" +%s 2>/dev/null || date -j -f "%Y-%m-%dT%H:%M:%S" "${CREATED%%.*}" +%s)
    AGE_DAYS=$(( (NOW - CREATED_EPOCH) / 86400 ))
    LASTUSED=$(aws iam get-access-key-last-used --access-key-id "$KEYID" --profile "$PROFILE" \
      --query 'AccessKeyLastUsed.LastUsedDate' --output text)
    FLAG=""
    [ "$AGE_DAYS" -gt "$CUTOFF_DAYS" ] && FLAG="[KEY OLDER THAN ${CUTOFF_DAYS}d]"
    [ "$LASTUSED" = "None" ] && FLAG="$FLAG [NEVER USED]"
    printf "%-24s %-16s %-8s age=%-5dd last_used=%-25s %s\n" "$USER" "$KEYID" "$STATUS" "$AGE_DAYS" "$LASTUSED" "$FLAG"
  done
done

echo ""
echo "=== Remediation actions (review before running) ==="
echo "# Deactivate a key:  aws iam update-access-key --access-key-id <KEYID> --status Inactive --user-name <USER> --profile $PROFILE"
echo "# Delete a key:      aws iam delete-access-key --access-key-id <KEYID> --user-name <USER> --profile $PROFILE"
echo "# Check if quarantined: aws iam list-attached-user-policies --user-name <USER> --profile $PROFILE | grep AWSCompromisedKeyQuarantine"

Operational guidance on key deactivation: deactivate first, delete later. AWS keys fail closed — setting a key to Inactive instantly blocks authentication and is reversible, giving you a window to discover what breaks (there is always something, usually a forgotten cron job on someone's laptop). After 7–14 days of silence with no production impact, delete the key permanently.

Remediation

There is no patch to deploy — this is a credential hygiene and architectural debt problem. Prioritize the following:

Immediate (next 24 hours):

  1. Run the audit script above across every AWS account in your organization. If you use AWS Organizations, iterate through all member accounts via an assumable audit role. Flag every key older than 90 days, every key never used, and every key whose last-used date predates its owner's departure from the company.
  2. Check for AWS quarantine policy attachments. AWS proactively attaches AWSCompromisedKeyQuarantineV2 (or V3) to IAM users when it detects a leaked key. Search all IAM users for these managed policy ARNs — if one is attached, you have a confirmed leak and should open an IR ticket, review CloudTrail for the key's usage history, and treat the user as compromised.
  3. Search your own footprint. Run truffleHog, Gitleaks, or GitHub's secret scanning against your organization's repositories — including private repos and their full commit history. Check Docker Hub and private registries for image layers containing credentials. Rotate anything found, immediately.
  4. Alert on the detections in this post. Deploy the Sigma rules via your SIEM pipeline and the Sentinel KQL as a scheduled analytic rule (recommended: 1-hour frequency, 14-day lookback).

Short term (this week):

  1. Enforce key age limits via policy. Attach a Service Control Policy or use AWS Config rules (iam-access-keys-rotated, iam-user-unused-credentials-check) with auto-remediation to deactivate keys over 90 days old. Set a hard organizational maximum.
  2. Scope down permissions. The reason this story is catastrophic rather than merely bad is the word 'full control.' Audit IAM users with AdministratorAccess or PowerUserAccess attached — the vast majority should not exist. Move to least-privilege managed or inline policies.
  3. Review CloudTrail for historical key use. For any key that may have been exposed, pull 90 days (or your full CloudTrail retention in S3/Athena) of events for that access key ID (userIdentity.accessKeyId) and review source IPs, user agents, regions, and event names for anything outside the expected workload pattern.

Structural (this quarter):

  1. Eliminate long-lived credentials. This is the real fix. Migrate human users to IAM Identity Center with short-lived SSO credentials. Migrate workloads to IAM roles (EC2 instance profiles, ECS task roles, Lambda execution roles, IRSA for EKS). For on-premises and third-party systems, use IAM Roles Anywhere with X.509 certificates. Every static key you delete is a leak that can never happen.
  2. Harden the supply side. Enforce pre-commit hooks (Gitleaks, git-secrets) on developer workstations, secret scanning on all CI platforms, and branch protection. AWS access keys should be stored exclusively in a secrets manager (AWS Secrets Manager, HashiCorp Vault) and injected at runtime — never in pipeline variables visible in logs.
  3. Tabletop the scenario. Run an IR tabletop exercise: 'A valid AKIA key with AdministratorAccess is posted to Pastebin.' Walk through detection (would your SOC see the GetCallerIdentity from an unfamiliar ASN?), containment (who can deactivate the key at 2 AM?), and eradication (did the attacker create persistence before you acted?).

The organizations bleeding in this story are not the ones that leaked a key — leaks happen to everyone eventually. They are the ones that never rotated, never monitored, and never noticed. Don't be in the second group.

Related Resources

Security Arsenal Managed SOC Services AlertMonitor Platform Book a SOC Assessment soc-mdr Intel Hub

Is your security operations ready?

Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.