Changelog¶
Info
This page mirrors the project CHANGELOG.md. See the Releases page for downloads.
2.0.0 [2026/07/31] - Black Hat Arsenal USA 2026 Release¶
New Features:
- Added the
azure-timelinecommand to create a DFIR timeline for Azure logs. (#109) (@fukusuket) - New
aws-ct-searchcommand to search through CloudTrail logs. (#117) (@fukusuket) - Added support for an ignore-list file (
config/aws_ignore_rule_list.txt) to skip loading rules by UUID, so superseded/duplicate rules can stay in the repo without being loaded. (#136) (@YamatoSecurity) - Added Parquet (
.parquet) input support to the AWS commands (aws-ct-timeline,aws-ct-metrics,aws-ct-summary,aws-ct-search) for both-fand-d. Each row is converted to one JSON event: nested struct columns become nested objects, the known CloudTrail envelope fields (userIdentity,requestParameters,responseElements, …) stored as serialized JSON strings — the shape Athena CTAS / Glue / Firehose pipelines produce — are parsed back into objects so rules can match nested values, and timezone-lesseventTimeTIMESTAMP columns are marked as UTC so time filtering and summaries keep working. Snappy, gzip, zstd, and lz4 compression are supported. (@nishikawaakira)
Enhancements:
- Replaced the wildcard (
"*") version requirements on ten dependencies with explicit floors, so a future breaking release is a deliberate bump rather than something acargo updateaccepts silently. Six of them are pre-1.0, where every minor is a breaking change under Cargo's semver rules. This is the failure mode behind #131, where a wildcard-pinnedcidr-utilsshipped a backend that stopped accepting abbreviated CIDR and--geo-ipbegan panicking at startup with nothing in Suzaku having changed. No resolved version changes:cargo updateproduces an identicalCargo.lockwith and without the floors. (#189) (@YamatoSecurity) - Errors that end the run are now all printed in red and all honor
--no-color. Previously the color was inconsistent: some (a nonexistent input path, an invalid-m, --min-level, a missing rules folder or output profile, an existing output file without-C, a failedupdate-rules) were printed in the default terminal color, and a few others were hard-coded red that ignored--no-color. They now share a singleerror_msg()helper withfatal_error(). (@fukusuket) - Warnings and errors raised while processing logs (skipped files, a failed directory scan, correlation-event errors, a missing abused-AWS-API list) are now written to
logs/errorlog-<YYYYMMDD_HHMMSS>.loginstead of the terminal, so they no longer interleave with the progress bar or bury the results summary. The file is created only when there is something to report, its first line is the command line that produced it, and the run ends with a singleWarnings and errors: <n> messages saved to <path>pointer. Fatal errors that abort the run are still printed to the terminal as well. (@fukusuket) - Reworked
-t, --output-typeforaws-ct-summaryto take format names like the timeline commands, and added DuckDB output. Passcsv,json,jsonl, and/orduckdb(comma-separated or repeated), e.g.-t csv,duckdb. Because the CSV folds each principal's API calls and attributes into multi-line cells that cannot be queried, the DuckDB output stores them relationally across three tables —summary(one row per principal),summary_api_calls(one row per principal/API, labelledabused_success/abused_failed/other_success/other_failed) andsummary_attributes(one row per principal/value, labelledaws_region/src_ip/access_key_id/user_agent) — so questions the CSV cannot answer, such as which source IPs were used by the principals that called an abused API, become ordinary joins. (Breaking: the numeric-t 1..5form is replaced by names, matching the other commands.) (@YamatoSecurity) - Reworked
-t, --output-typeforaws-ct-timelineandazure-timelineto take format names instead of numbers, and added DuckDB output. Passcsv,json,jsonl, and/orduckdb(comma-separated or repeated) to write any combination at once, e.g.-t csv,duckdb; DuckDB output is a self-contained.duckdbdatabase with atimelinetable whose columns are the output-profile fields. (Breaking: the numeric-t 1..5form is replaced by names;aws-ct-searchshares the option and gains the same named formats.) (@YamatoSecurity) - Added a
Tagscolumn to theaws-ct-timelineandazure-timelineoutput that renders a rule's Sigmatagslist as a single¦-separated string (like Hayabusa) instead of dropping the list. ATT&CK tactics are abbreviated using the editableconfig/mitre_tactics.txttable shared with Hayabusa (e.g.attack.credential-accessbecomesCredAccess), while techniques and groups are shortened (attack.t1562.001becomesT1562.001,attack.g0035becomesG0035); both the hyphen and underscore tactic spellings are handled. JSON output keeps the value as a flat string. (#62) (@YamatoSecurity) - Added a
-l, --localtimeoption to theaws-ct-timelineandazure-timelinecommands that outputs event timestamps in the machine's local timezone with an explicit UTC offset (e.g.2023-07-10 12:27:45becomes2023-07-10 21:27:45+09:00in JST) instead of UTC. Unparseable timestamps fall back to the existing UTC rendering. (#34) (@YamatoSecurity) - Bumped
sigma-rustto the releasedv0.7.1and updated all other dependencies to their latest versions.sigma-rustv0.7.1 keeps the Sigma correlation support suzaku relies on while moving its YAML backend off the deprecatedserde_yml/noyalib(which parsed large unsigned 64-bit values in rules/events as lossy floats) to the actively maintainedyaml_serde, restoring correctu64parsing. (@YamatoSecurity) - Code refactored for easier handling of different log sources. (@fukusuket)
- Added support for Microsoft Graph API JSON format for Azure logs. (#113) (@fukusuket)
azure-timelinenow unwraps the{ "records": [...] }batch envelope used by Azure Monitor diagnostic-settings blobs and Event Hub messages (both whole-file and per-line), so those exports are read record-by-record instead of as a single event, and it now loads/matches theidentity_protection(riskdetection) andprivileged_identity_management(pim) rule types, which were previously dropped at load. (#130) (@YamatoSecurity)azure-timelinenow loads and matches SigmaHQ's Microsoft 365 rules, which declarelogsource.serviceasaudit/exchange/threat_detection/threat_management— onlym365was recognized before, so every upstream m365 rule was dropped at load. These services are routed through the sameWorkload/RecordTypeUnified Audit Log discriminator. (#137) (@YamatoSecurity)- Added support for the M365 Unified Audit Log to
azure-timeline: readsSearch-UnifiedAuditLogCSV exports (and JSON) by unwrapping theAuditDatacolumn/wrapper, folds UAL Name/Value property bags (ExtendedProperties/Parameters/…) into objects so rules can match nested values (e.g.ExtendedProperties.UserAgent), parses single/pretty-printed record objects, no longer drops events when no time filter is set, parses theCreationTimetimestamp, and adds anm365log-source service. The Azure output profile now surfaces DFIR-relevant M365 fields (Workload,Operation,Result,User,SrcIP,TargetObject,UserAgent,AppId,LogonError, and aDetailssummary of the change'sParameters/ModifiedProperties) instead of the previously empty Azure-Monitor-only columns. (#129) (@YamatoSecurity) - Added
--file-date-from/--file-date-tooptions that filter objects by their S3 key date prefix, distinct from the existing--timeline-start/--timeline-endoptions, which operates on in-file event timestamps. (#118) (@fukusuket) - Added
-output-typeoption for theaws-ct-summarycommand to output in JSON. (#123) (@fukusuket) aws-ct-metricscan now aggregate several fields in a single scan and enrich the results.-F, --field-nametakes a comma-separated list (e.g.-F sourceIPAddress,userAgent,userIdentity.arn,awsRegion,userIdentity.accessKeyId) and tallies every field in one pass over the logs, instead of requiring a full scan per field; each value additionally reports theFirstSeen/LastSeenof that value;-G, --geo-ipaddsSrcASN/SrcCity/SrcCountrycolumns for values that parse as IP addresses;-t, --output-typewrites csv/json/jsonl/duckdb (the DuckDB output is a single queryablemetricstable); and-s, --include-sts-keysmatchesaws-ct-summaryby excluding temporaryASIA...STS keys unless asked for. Events that do not have the requested field are now counted as-rather than dropped, so the percentages are a share of every event scanned.-Fis also validated against the CloudTrail record fields before the scan starts, so a mis-cased name fails immediately with'sourceIPaddress' is not a CloudTrail field. Did you mean 'sourceIPAddress'?instead of scanning the whole dataset to report-for every event; any sub-path of an API-specific container (requestParameters,responseElements,additionalEventData, ...) is still accepted as-is. (Breaking: the CSV columns changed fromEventName,Percent,TotaltoField,Value,Count,Percent,FirstSeen,LastSeen.) (@fukusuket)
Bug Fixes:
--geo-ipreported every routable IPv6 address asPrivateand never looked it up:2000::/3, the entire IPv6 global unicast space, was listed as a private range. Public addresses such as a Japanese consumer ISP or an Azure sign-in from anywhere renderedSrcASN: Private/SrcCountry: -, which does not just omit the geolocation but asserts something untrue — an analyst readingPrivateconcludes the traffic was internal. IPv6 is now geolocated like IPv4; unspecified, link-local, unique-local and multicast addresses keep their placeholders. (#182) (@YamatoSecurity)--geo-ipleft the geolocation columns empty whenever an earlier field in the profile'sSrcIPfallback list was present but unusable. The lookup took the first candidate that existed and only then tried to parse it, so aclaims.ipaddrholding"","-", ahost:portpair (the common M365ClientIPshape) or any other non-IP ended the search and the routable address sitting incallerIpAddresswas never consulted —SrcASN/SrcCity/SrcCountryrendered-for a record that plainly carried a public IP. The search now takes the first candidate that parses as an IP address, and theSrcIPcolumn resolves through the same selector, so the address displayed and the address geolocated are always the same field. When no candidate parses,SrcIPstill shows what the log recorded (an AWS-service event writescloudtrail.amazonaws.comthere) and the geo columns show-. (#183) (@YamatoSecurity)- The
aws-ct-metricstable and CSV always labelled the first columnEventName, even when-Faggregated a different field, so a run oversourceIPAddressproduced a column of IP addresses headedEventName. The column is now named after the field that was actually aggregated. The command also silently overwrote an existing-ofile; overwriting now requires-C, --clobber, as it does for every other command. Values with equal counts are additionally sorted by value, so repeated runs produce byte-identical output instead of shuffling rows inHashMaporder. (@fukusuket) - The
Results Summary"Data reduction" line panicked (attempt to subtract with overflow) in debug builds — or printed a nonsensical ~1.8×10¹⁹ count in release, orNaN%on empty input — becauseevent_with_hits(which correlation results increment for events already counted by the base scan) could exceedtotal_events. The count now saturates and the percentage is guarded against an empty dataset. (#163) (@YamatoSecurity) aws-ct-summaryreported the wrong per-entry time range: thefirst_seen/last_seenof every summarized region, source IP, access key, user agent, and API were seeded once from the dataset-global min/max at the moment the key was first inserted and never updated, so they showed the whole dataset's span rather than that entry's own first/last occurrence. Each entry now tracks the first/last event time of the events that actually hit it. (#160) (@YamatoSecurity)- Scanning now warns (
[WARNING] Skipping <file>: <reason>) when it skips an input file it could not read — permission denied, non-UTF-8 content, a file removed mid-scan, or a corrupt/oversized.gz— instead of silently dropping it. Previously such a file was counted in the total but skipped with no indication, so the reported coverage was overstated. Applies to both the directory scan and single-file input, and the gzip size-cap warning was moved to this single call-site path. (#161) (@YamatoSecurity) aws-ct-searchno longer panics on an invalid--regexvalue (it was compiled with.expect()); an invalid pattern now prints a clear error and exits cleanly. A malformed--filtermissing theFIELD:VALUEcolon — previously silently ignored — is now rejected up front. Andaws-ct-summary's warning when the abused-AWS-API list can't be opened now names the path it looked for and states that all API calls will be classified as non-abused. (#162) (@YamatoSecurity)--geo-ipenrichment (SrcASN/SrcCity/SrcCountry) was a silent no-op forazure-timeline/M365 logs: the source IP was resolved from a hardcodedsourceIPAddressfield, which only exists in AWS CloudTrail. The Azure/M365 profile mapsSrcIPtocallerIpAddress/ClientIP/etc., so those columns always rendered-even for events with a routable public IP. The lookup now resolves the source IP from the profile'sSrcIPfield spec (the same|-separated fallback used for other columns), so Azure/M365 enrich just like AWS. (#159) (@YamatoSecurity)- Malformed
--timeline-start/--timeline-end/--time-offsetvalues are now rejected up front with a clear error, instead of being parsed per-event and silently dropping every event (empty timeline, no warning) — e.g. a plain--timeline-start 2024-01-01instead of full RFC 3339. Also fixed aparse_offsetpanic on an empty offset, trailing whitespace, or a multibyte trailing character (the split index was taken from the untrimmed length). (#150) (@YamatoSecurity) - Fixed a panic (
byte index 24 is not a char boundary) when the end-of-scan "Rule Authors" summary truncated an author name longer than 27 bytes whose 24th byte fell mid-codepoint — routine for Japanese/CJK and other non-ASCII author names common in Sigma rule packs. Truncation now counts and cuts by characters, not bytes, so the completed run's output is no longer discarded. (#148) (@YamatoSecurity) - Neutralized CSV/spreadsheet formula injection (CWE-1236) in report output. CSV cells come from attacker-influenceable cloud-log fields (
userAgent, principal ARNs, error strings, …); a value beginning with=,+,-,@, tab, or CR would be evaluated as a formula when the report is opened in Excel/LibreOffice/Sheets. Such values are now prefixed with an apostrophe (spreadsheets treat it as a force-text marker) at all CSV sinks; JSON/JSONL and stdout are unchanged. (#146) (@YamatoSecurity) - Bounded gzip decompression to stop a decompression-bomb OOM: a crafted or corrupt
.gzfile anywhere in the scanned tree could inflate to many GB (DEFLATE reaches ~1032:1) and get the entire scan OOM-killed..gzinputs are now capped at 3 GiB decompressed, and an over-limit file is skipped with a warning instead of aborting the run. (#147) (@YamatoSecurity) --geo-ipcorrupted the timeline output: when a record'ssourceIPAddresswas not a parseable IP address (routine for AWS-service events such ascloudtrail.amazonaws.com), the GeoIP lookup returned that raw string for every output column, overwritingTimestamp,EventName,RuleTitle, etc. Enrichment is now scoped to theSrcASN/SrcCity/SrcCountrycolumns only, which fall back to-when the address cannot be resolved. (#145) (@YamatoSecurity)- Hardened the input/filesystem edge cases that previously aborted a scan with a Rust panic and backtrace: a non-UTF-8 filename anywhere in the scanned tree (which killed the initial file count before any results), an unreadable subdirectory or a file removed mid-scan, and an unwritable
--outputpath now produce a clean, actionable error instead — the walk errors are reported and the output error exits non-zero with aCannot write to output file …message. Applies acrossaws-ct-timeline,azure-timeline,aws-ct-search,aws-ct-metrics, andaws-ct-summary. Non-UTF-8 filenames are now read (the real path is kept through the scan pipeline) instead of being counted but skipped, andaws-ct-summary's JSON/JSONL output also reports an unwritable--outputpath cleanly. (#149) (@YamatoSecurity) - The
aws-ct-timeline,aws-ct-metrics,aws-ct-search, andaws-ct-summarycommands silently dropped JSONL input (one CloudTrail event, or a{ "Records": [...] }batch, per line): the parsers read the whole file as a single JSON document and returned no events when that failed. They now fall back to per-line JSONL parsing, and.jsonlfiles are discovered and read. (#139) (@YamatoSecurity) -T, --no-frequency-timelineoption was not working so we removed it. Also fixed a logic bug in the authors display. (#110) (@fukusuket)- Output file would get saved even if there were no results. (#114) (@fukusuket)
aws-ct-summarywould panic when processing a corrupt or imcomplete log file. (#119) (@fukusuket)--geo-ipwould panic at startup (invalid IP address syntax) because the abbreviated CIDR strings used for the private-IP check (e.g.10/8,172.16/12,2000::/3) are no longer accepted by thecidrcrate. Dropped thecidr-utilsdependency and check private ranges directly withstd'sIpv4Addr::is_private()and a manual IPv6 prefix match; also populated the previously unused GeoIP country/city caches. (#132) (@fukusuket)
1.1.0 [2025/08/14] - Obon Release¶
Enhancements:
-R, --raw-outputnow outputs raw logs to the terminal when-ois not specified. (#101) (@fukusuket)
1.0.1 [2025/08/07] - Black Hat Arsenal USA 2025 Release¶
Bug Fixes:
- Better error handling for invalid file and directory input. (#99) (@fukusuket)
1.0.0 [2025/07/31] - Black Hat Arsenal USA 2025 Release¶
New Features:
- Added support for correlation rules (
event_count,value_count,temporal,temporal_order) for theaws-ct-timelinecommand. (#97) (@fukusuket)
Enhancements:
- Level names are now abbreviated in
aws-ct-timeline. (#68) (@fukusuket) - Error message output when no rules are found. (#76) (@fukusuket)
- Added
--timeline-offset,--timeline-startand--timeline-endoptions to theaws-ct-timelinecommand. (#58) (@fukusuket) aws-ct-timelinenow runs with multi-threading. (#32, #93) (@hach1yon)
0.2.1 [2025/05/25] - AUSCERT/SINCON Release 2¶
- Fixed the release name and updated the readme. (@yamatosecurity)
0.2.0 [2025/05/22] - AUSCERT/SINCON Release¶
New Features:
aws-ct-summary: for each unique ARN, creates a summary of total events, regions used, user types, access keys, user agents, etc... (#53) (@fukusuket)
Enhancements:
- Added Maxmind geolocation information to source IP addresses for the
aws-ct-timelineandaws-ct-summarycommands. (#16) (@fukusuket) - Added a
-R, --raw-outputoption to theaws-ct-timelinecommand to output the original JSON data when there is a detection. (#67) (@fukusuket)
Bug Fixes:
- The CSV headers for the
aws-ct-metricscommand were incorrect. (#72) (@fukusuket)
0.1.1 [2025/04/24] - AlphaOne Release¶
Bug Fixes:
- Some Sigma fields were not being outputted properly. (#61) (@fukusuket)
Initial Release¶
0.1.0 [2025/04/20] - AlphaOne Release¶
New Features:
aws-ct-metrics: create metrics for AWS CloudTrail eventsaws-ct-timeline: perform sigma detection on AWS CloudTrail logsupdate-rules: update sigma rules