A Python tool that parses AWS CloudTrail logs and hunts for suspicious API activity — failed-login bursts, logins without MFA, IAM persistence, security groups opened to the world, and logging being switched off to cover tracks.
Every detection is mapped to a MITRE ATT&CK (Cloud) technique, and the tool runs fully offline against exported logs, so it is safe to drop into a CI pipeline or run during an incident review.
In cloud-native environments the evidence trail is not a disk image — it is the
control-plane log. CloudTrail records every API call, and most attacks leave a
recognisable shape in it: a brute-force burst, a new access key, an admin policy
attached to a fresh user, then StopLogging to go dark. This tool surfaces that
shape automatically instead of scrolling through thousands of JSON records.
| ID | Severity | Detection | MITRE ATT&CK |
|---|---|---|---|
| CT001 | Critical | Root account activity | T1078.004 Valid Accounts: Cloud |
| CT002 | High | Console login without MFA | T1078 Valid Accounts |
| CT003 | Critical | CloudTrail tampering | T1562.008 Disable Cloud Logs |
| CT004 | Critical | Security monitoring disabled | T1562.001 Disable Tools |
| CT005 | High | IAM persistence / privilege esc. | T1098 / T1136 |
| CT006 | High | Security group opened to 0.0.0.0/0 | T1562 Impair Defenses |
| CT007 | High | S3 bucket exposure change | T1530 Data from Cloud Storage |
| CT008 | Medium | Login from untrusted network | T1078 Valid Accounts |
| CT009 | High | Console brute-force burst | T1110 Brute Force |
| CT010 | Medium | Unauthorized API probing | T1087 Account Discovery |
CT001–CT007 inspect individual events; CT009/CT010 correlate events by actor and source IP to catch patterns a single record cannot show. CT008 only runs when an allow-list of trusted CIDRs is supplied.
git clone https://github.com/yektaduran/cloudtrail-hunter.git
cd cloudtrail-hunter
pip install -r requirements.txtRequires Python 3.10+.
# Hunt the bundled sample (no AWS account needed) and print a colored report
python hunt.py --input samples/cloudtrail-sample.json
# Add an allow-list so logins from outside corporate ranges are flagged
python hunt.py --input samples/cloudtrail-sample.json \
--trusted-cidr 10.0.0.0/8 --trusted-cidr 192.168.0.0/16
# Point at a directory of gzipped CloudTrail logs and write JSON for a SIEM
python hunt.py --input ./cloudtrail-logs/ --format json \
--min-severity high --output findings.jsonThe input can be a single .json / .json.gz file or a directory — the
loader walks it recursively and merges every Records[] it finds.
[CRITICAL] CT003 CloudTrail tampering
T1562.008 Impair Defenses: Disable Cloud Logs
actor=alice ip=203.0.113.42 time=2024-03-11T08:14:02Z
'StopLogging' on CloudTrail — likely anti-forensics to hide activity
[HIGH] CT009 Console brute-force attempt
T1110 Brute Force
actor=alice ip=203.0.113.42 time=2024-03-11T08:02:05Z
5 failed console logins for 'alice' from 203.0.113.42
The tool exits 2 when findings at or above --min-severity are present, so it
can fail a CI pipeline on a critical detection.
hunt.py CLI: args, exit codes
hunter/
loader.py read JSON / .json.gz, single file or directory
models.py Event wrapper + Finding + Severity
detections.py CT001–CT010, each mapped to MITRE ATT&CK
report.py terminal / markdown / json renderers
samples/ a CloudTrail log telling one end-to-end attack story
tests/ unit tests for every detection
The design mirrors a SIEM detection pipeline: normalise raw events into a model, run independent detection rules against them, then render the findings. Adding a detection means writing one small function and registering it.
This is a hunting/triage aid, not a full detection-and-response platform. Tune the thresholds and allow-lists to your environment, and validate findings against full context before acting.
MIT