I Leaked My AWS Access Key to GitHub: An Incident Response Playbook
Accidentally committing an AWS Access Key to a public GitHub repository is one of the most common — and most dangerous — cloud security incidents. Automated bots scan GitHub commits in near real-time, meaning your credentials can be harvested and abused within minutes of exposure.
TL;DR — Immediate Action Checklist
| # | Action | Priority | Tool |
|---|---|---|---|
| 1 | Deactivate the leaked access key immediately | 🔴 Critical | AWS Console / CLI |
| 2 | Audit CloudTrail for unauthorized API calls | 🔴 Critical | CloudTrail / Athena |
| 3 | Revoke any active sessions spawned by the key | 🔴 Critical | IAM / STS |
| 4 | Delete the compromised key permanently | 🟠 High | IAM Console / CLI |
| 5 | Rotate all secrets and audit IAM permissions | 🟠 High | Secrets Manager |
| 6 | Remove the key from Git history | 🟡 Medium | git-filter-repo / BFG |
| 7 | Implement preventive controls | 🟡 Medium | git-secrets / GuardDuty |
Understanding the Threat Timeline
Before diving into remediation, understand what you are up against. Credential-harvesting bots monitor GitHub's public event stream via the GitHub API. The window between a commit being pushed and a bot attempting to use the key is measured in seconds to minutes, not hours.
- Commit Push: Developer accidentally includes
~/.aws/credentialsor hardcoded keys in source code and pushes to a public repo. - Bot Detection: Automated scanners polling the GitHub Events API detect the new commit containing key patterns (e.g.,
AKIA...). - Credential Abuse: The bot attempts API calls — typically probing IAM (
GetCallerIdentity), then escalating to EC2, S3, or Lambda to mine crypto or exfiltrate data. - AWS Detection: GuardDuty (if enabled) flags anomalous API calls. CloudTrail records every action.
- Incident Response: You execute the remediation playbook outlined below.
Phase 1: Immediate Containment (Do This First)
Step 1 — Deactivate the Key (Not Delete — Yet)
Deactivating first (rather than immediately deleting) preserves the key ID for your CloudTrail forensic audit. Deletion is irreversible and removes the audit anchor.
# Identify the leaked key ID (e.g., AKIAIOSFODNN7EXAMPLE)
aws iam list-access-keys --user-name <IAM_USERNAME>
# Deactivate it immediately
aws iam update-access-key \
--user-name <IAM_USERNAME> \
--access-key-id AKIAIOSFODNN7EXAMPLE \
--status Inactive
If the key belongs to the root account, go directly to the AWS Console → Account Settings → Security Credentials and delete it. Root access keys should never exist in the first place.
Step 2 — Invalidate Active STS Sessions
Even after deactivating the key, any temporary credentials (AssumeRole tokens) already issued using that key remain valid until their natural expiry (up to 12 hours). You must explicitly revoke them.
# Attach an inline deny policy to the IAM user to invalidate all active sessions
# This uses the aws:TokenIssueTime condition key
aws iam put-user-policy \
--user-name <IAM_USERNAME> \
--policy-name RevokeActiveSessions \
--policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"DateLessThan": {
"aws:TokenIssueTime": "2024-01-15T00:00:00Z"
}
}
}]
}'
Set the aws:TokenIssueTime value to the current UTC timestamp. This denies all requests from tokens issued before this moment, effectively invalidating any active sessions spawned by the compromised key.
Phase 2: Forensic Audit with CloudTrail
Step 3 — Determine the Blast Radius
CloudTrail is your forensic source of truth. Query it to understand exactly what the attacker did — or attempted to do — using the compromised key.
Analogy: CloudTrail is the security camera footage of your AWS account. Even if the attacker is gone, the footage tells you exactly which doors they opened, which files they touched, and what they tried to steal.
🔽 [Click to expand] — CloudTrail Lookup: Find all API calls by the compromised key
# Look up events by the specific access key ID
# CloudTrail event history covers the last 90 days
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=AccessKeyId,AttributeValue=AKIAIOSFODNN7EXAMPLE \
--start-time 2024-01-01T00:00:00Z \
--end-time 2024-01-15T23:59:59Z \
--query 'Events[*].{Time:EventTime,Event:EventName,User:Username,IP:CloudTrailEvent}' \
--output table
Key API Calls to Investigate
Focus your audit on these high-risk API calls that indicate privilege escalation or data exfiltration:
iam:CreateUser,iam:AttachUserPolicy,iam:CreateAccessKey— Attacker creating backdoor accountsiam:AssumeRole— Lateral movement to other rolesec2:RunInstances— Crypto mining infrastructures3:GetObject,s3:ListBuckets— Data exfiltrationlambda:CreateFunction,lambda:InvokeFunction— Malicious function deploymentsts:GetCallerIdentity— Initial reconnaissance (almost always the first call)
- Reconnaissance:
sts:GetCallerIdentityandiam:GetUserto understand the identity and its permissions. - Privilege Escalation: Attempt to create new IAM users, attach admin policies, or assume higher-privileged roles.
- Persistence: Create new access keys or backdoor Lambda functions to maintain access even after the original key is rotated.
- Impact: Launch EC2 instances for crypto mining, exfiltrate S3 data, or pivot to other services.
Phase 3: Eradication
Step 4 — Delete the Compromised Key
Once your forensic audit is complete, permanently delete the key.
aws iam delete-access-key \
--user-name <IAM_USERNAME> \
--access-key-id AKIAIOSFODNN7EXAMPLE
Step 5 — Remediate Attacker-Created Resources
Based on your CloudTrail audit, systematically remove any resources the attacker created:
- Delete any IAM users, roles, or policies created after the key exposure timestamp.
- Terminate unauthorized EC2 instances.
- Delete unauthorized Lambda functions.
- Audit S3 bucket policies for newly added public access or cross-account grants.
- Check for new SNS/SQS subscriptions that could be used for data exfiltration.
Step 6 — Issue a New Key and Store It Securely
Never hardcode credentials again. Use AWS Secrets Manager or IAM Roles for compute workloads.
# Generate a new access key
aws iam create-access-key --user-name <IAM_USERNAME>
# Store it in Secrets Manager — never in code or .env files
aws secretsmanager create-secret \
--name prod/myapp/aws-credentials \
--description "Rotated IAM credentials post-incident" \
--secret-string '{"AccessKeyId":"NEWKEYID","SecretAccessKey":"NEWSECRET"}'
Phase 4: Remove the Key from Git History
Deleting the file or adding a new commit does not remove the secret from Git history. Anyone can still access it via git log or by browsing old commits on GitHub.
🔽 [Click to expand] — Purge secrets from Git history using git-filter-repo
# Install git-filter-repo (preferred over the deprecated git filter-branch)
pip install git-filter-repo
# Remove the specific file containing the secret from ALL history
git filter-repo --path path/to/credentials-file --invert-paths
# Force push all branches to overwrite remote history
# WARNING: This is a destructive operation — coordinate with your team
git push origin --force --all
git push origin --force --tags
# After purging, GitHub's cache may still serve old commits.
# Contact GitHub Support to purge cached views of the exposed data.
Important: After a force push, all collaborators must re-clone the repository. Old local clones still contain the secret in their local history.
Phase 5: Preventive Controls
Remediation without prevention is incomplete. Implement these controls to ensure this never happens again.
Control 1 — Pre-commit Hooks with git-secrets
# Install git-secrets
brew install git-secrets # macOS
# Register AWS credential patterns
git secrets --register-aws
# Install hooks into the current repository
git secrets --install
# Now any commit containing AWS key patterns will be blocked
git secrets --scan # Manual scan of current working tree
Control 2 — Enable AWS GuardDuty
GuardDuty provides continuous threat detection and will alert you to findings such as UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration and anomalous API call patterns from unexpected geographic locations.
# Enable GuardDuty in your account (regional service — run per region)
aws guardduty create-detector --enable --finding-publishing-frequency FIFTEEN_MINUTES
Control 3 — Use IAM Roles Instead of Long-Lived Keys
For EC2, Lambda, ECS, and other AWS compute services, never use access keys. Attach an IAM Role directly to the compute resource. The AWS SDK automatically retrieves short-lived credentials from the instance metadata service (IMDS).
# Attach an IAM role to an EC2 instance (no access keys needed)
aws ec2 associate-iam-instance-profile \
--instance-id i-0abcdef1234567890 \
--iam-instance-profile Name=MyAppInstanceProfile
Control 4 — Enable AWS Config Rule for Access Key Age
# Deploy the managed Config rule to flag access keys older than 90 days
aws configservice put-config-rule --config-rule '{
"ConfigRuleName": "access-keys-rotated",
"Source": {
"Owner": "AWS",
"SourceIdentifier": "ACCESS_KEYS_ROTATED"
},
"InputParameters": "{\"maxAccessKeyAge\":\"90\"}"
}'
Control 5 — GitHub Secret Scanning (for Organizations)
GitHub natively integrates with AWS to automatically revoke detected AWS access keys via its Secret Scanning feature. For public repositories, this is enabled by default. For private repositories, it requires a GitHub Advanced Security license. When a key is detected, GitHub notifies AWS, which can automatically quarantine the key.
Glossary
| Term | Definition |
|---|---|
| IAM Access Key | A long-lived credential pair (Access Key ID + Secret Access Key) used to authenticate programmatic AWS API requests. |
| STS (Security Token Service) | AWS service that issues short-lived, temporary security credentials for IAM roles and federated identities. |
| CloudTrail | AWS service that records all API calls made in your account, providing an immutable audit log for forensic investigation. |
| Blast Radius | The scope of resources and data potentially accessed or compromised as a result of a security incident. |
| GuardDuty | AWS managed threat detection service that continuously monitors for malicious activity and unauthorized behavior using ML and threat intelligence. |
Comments
Post a Comment