Releases: dotgibson/htpx
Release list
v2.4.0
Added
- GCP parity — 2 new red↔blue pairs (+4 entries) and a recon entry (+1). Brings
GCP up from a single pair to rough parity with the other big-three clouds.
Persistence (T1098): IAM policy backdoor —setIamPolicybinding a rogue
principal — detected on theSetIamPolicyADDbinding delta in Cloud Audit
Logs. Defense Evasion (T1562.008): Cloud Audit log tamper —DeleteSink/
auditConfigsstrip — detected via the self-witnessing Admin Activity events
(plus a Data Access gap monitor). Also adds an unpaired Discovery
(T1580/T1526/T1069.003)gcp-enum-reconentry (projects / Asset Inventory /
IAM blast-radius mapping), mirroring the unpaired on-premsmb-enum-nxc.
Changed
asrep-probing-4771retargeted to the real AS-REP roast artifact. The
detection now keys primarily on a successful4768with pre-authentication
type 0 (the AS-REP etype is negotiated — often RC40x17, AES where RC4 is
disabled — so the clause keys on the type-0 invariant, not the cipher) — the
roastable AS-REP its red mate actually emits — and keeps
the4771 0x18one-source-many-accounts burst as a secondary Kerbrute
enumeration/spray tell. Previously it only saw the collateral4771probing, not
the roast itself.
v2.3.0
Added
- Command & Control + Impact corpus (14 new red↔blue pairs, +28 entries). Fills
the two tactics that had zero coverage.TA0011Command & Control (8 pairs):
HTTPS beacon sleep+jitter, DNS tunneling, domain fronting, mutual-TLS/JA3, ICMP
tunneling, web-service C2 (Telegram/Slack/Gist), DGA rendezvous, and reverse
tunnels (chisel/ligolo) — each attack paired with the network/host detection that
survives its evasion (inter-arrival regularity, Sysmon-22 query shape, SNI/Host
mismatch, JA3 fingerprints, NXDOMAIN entropy).TA0040Impact (6 pairs):
recovery inhibition (vssadmin/wbadmin/bcdedit), mass file encryption, pre-
encryption service kills, cloud data destruction (CloudTrail delete burst),
cryptojacking (Stratum), and account access removal (4724/4725/4726). Corpus-only
(no flat-view markers); every new entry carries a valid, non-deprecated ATT&CK
technique ID.
v2.2.0
Added
/corpus-reviewmaintenance routine (.claude/commands/corpus-review.md+
.github/workflows/claude-routines.yml). A weekly, report-first Claude routine that
reviews the judgment layerci.ymlcan't gate: ATT&CK-ID validity (against live
MITRE), red↔blue semantic pairing fidelity, coverage holes, and detection
quality. Files a deduplicated issue and changes nothing. Inert by default —
scaffolded but dormant until aCLAUDE_CODE_OAUTH_TOKENrepo secret is added. Runs
Thu 08:00 UTC, off the rest of the fleet's routine crons./release-readiness+/release-notesroutines (.claude/commands/+ two new
dispatch-only jobs inclaude-routines.yml). The htpx twin of Core's release
routines:release-readinessreads the Conventional Commits + CHANGELOG since the
last tag and files a go/no-go verdict with the recommended next SemVer;
release-notesdrafts the CHANGELOG entry from those commits. Both report-first and
dispatch-only — run them at release time via Actions → claude-routines → Run
workflow → routine. Same inert-by-default token gate.
Fixed
- ATT&CK tactic corrections surfaced by the first
/corpus-reviewrun (T1195.002,
T1047), both verified against live MITRE:T1195.002(Compromise Software Supply Chain) is an Initial Access technique,
not Execution — retaggedTA0002→TA0001(+ phase) in the npm/pypi
malicious-publish pair (4 entries).T1047(WMI) is filed by MITRE only under Execution, not Lateral Movement —
retaggedTA0008→TA0002(+ phase) in the wmiexec pair (2 entries).
Red↔blue tags stay in agreement; pairings unchanged, soci.yml's pairing/slot/drift
gates are unaffected.
Internal
- Hardened the report-first routines' "change nothing" guarantee into a mechanical one
(read-only--permission-mode default; read-only Bash allowlists; tightened git
allowlist) and fixed async-fanouttag-resolve race that could throw a spurious red
X on CHANGELOG-only merges. Renovate action-pin bumps.
v2.1.0
Added
renovate.json- configuration for Renovate app.
v2.0.0
Changed
- README second-pass polish. The
dotgibsonshield now tracks the
dotfiles-corerelease version; dropped the showcase and LinkedIn shields for a
one-line header (LinkedIn moved to Contact); the docs links now point at the
documentation hub root (/docs); and About gainedLanguages(Markdown) +
Tools(MITRE ATT&CK, fzf) subsections. - README rebuilt as a lean showcase landing page. Brought the README up to the
dotgibsonexemplar bar — a reference-style shields header, the org logo, a
collapsible TOC, then a lean body (what htpx is and how it's vendored into
dotfiles-Kali, Getting Started, a representative corpus slice, and the
entry-first contribution workflow). The full 70+-row corpus table is trimmed to
a representative sample that points atentries/and the on-site red↔blue view.
Added a.markdownlint.jsonc(mirrored from Core) scoping the showcase HTML via
MD033allowed_elements.
Added
-
Slack platform (3 companion-only red↔blue pairs) — the SaaS-collaboration seam, detected
over the Slack (Enterprise Grid) audit logs (product: slack, fieldaction):slack-malicious-app↔slack-app-audit— install a broad-scope OAuth app for durable
message/file access; detectapp_installed(T1098).slack-external-share↔slack-external-share-audit— invite an attacker-controlled
workspace into a channel via Slack Connect to exfil its history; detect
shared_channel_invite_sent/_accepted(T1567).slack-2fa-disable↔slack-2fa-audit— turn off enforced 2FA to weaken workspace auth;
detectpref.two_factor_auth_changedwith 2FA off (T1562.001).
-
PyPI registry platform (3 companion-only red↔blue pairs) — the Python mirror of the npm
round, detected over the PyPI project journal (product: pypi, fieldaction):pypi-malicious-publish↔pypi-publish-audit— upload a trojanized release via a stolen
API token (bypassing trusted publishing); detectnew releasenot via a trusted publisher
(T1195.002).pypi-role-add↔pypi-role-audit— add a rogue Owner/Maintainer for durable publish
rights; detect journaladd Owner/add Maintainer(T1098).pypi-trusted-publisher↔pypi-trusted-publisher-audit— register an attacker-controlled
OIDC trusted publisher for a credential-less publish backdoor; detect an add-trusted publisherjournal entry (T1098).
-
npm registry platform (3 companion-only red↔blue pairs) — the software supply-chain
seam, detected over the npm account/org audit log (product: npm, fieldaction):npm-malicious-publish↔npm-publish-audit— publish a trojanized package version via
a compromised maintainer token; detectpackage.publishby an off-CI actor (T1195.002).npm-owner-add↔npm-owner-audit— add a rogue maintainer for durable publish rights;
detectpackage.owner_add/team.user_add(T1098).npm-2fa-disable↔npm-2fa-audit— disable require-2FA-to-publish (npm access set mfa=none) so a stolen token ships quietly; detectpackage.editmfa=none(T1562.001).
-
Cloudflare edge platform (3 companion-only red↔blue pairs) — detections over the
Cloudflare account audit log (product: cloudflare, fieldsaction.type/resource.type):cf-api-token↔cf-api-token-audit— mint a long-lived API token for durable
control-plane access after account compromise; detectresource.type=api_token
action.type=create(T1098).cf-waf-disable↔cf-waf-disable-audit— delete/disable a WAF or firewall rule to
expose the origin; detectfirewall_rule/rulesetdelete/update(T1562.001).cf-worker-deploy↔cf-worker-deploy-audit— deploy a malicious Worker to skim/proxy
live edge traffic; detectresource.type=workercreate/update(T1648).
-
Google Workspace platform (3 companion-only red↔blue pairs) — detections over the
Google Workspace admin/token/user audit logs (product: google_workspace, field
eventName):gws-oauth-grant↔gws-oauth-audit— consent-phish a malicious OAuth app into
Gmail/Drive scopes; detect tokenauthorize(T1528).gws-super-admin↔gws-admin-audit— promote a controlled user to super admin;
detectGRANT_DELEGATED_ADMIN_PRIVILEGES/ASSIGN_ROLE(T1098.003).gws-mail-forward↔gws-mail-forward-audit— external auto-forwarding for BEC
exfil; detectemail_forwarding_out_of_domain(T1114.003).
-
Snowflake data cloud platform (3 companion-only red↔blue pairs) — mirrors the
2024 Snowflake credential-attack TTPs, detected viaACCOUNT_USAGE.QUERY_HISTORY
(product: snowflake,query_type/query_text):snowflake-exfil-stage↔snowflake-exfil-audit—COPY INTOexternal stage bulk
unload; detectQUERY_TYPE=UNLOAD(T1567.002).snowflake-rogue-user↔snowflake-user-audit— backdoor user + ACCOUNTADMIN grant;
detectCREATE_USER/ privilegedGRANT(T1136.003).snowflake-network-policy↔snowflake-network-policy-audit— open/drop the IP
allowlist so stolen creds work anywhere; detectNETWORK POLICYchanges (T1562.007).
-
Jenkins CI/CD platform (3 companion-only red↔blue pairs) — the self-hosted
counterpart to the GitHub/GitLab SaaS rounds, detected via the Jenkins Audit Trail
plugin log (product: jenkins, keyword/URI matches):jenkins-script-console↔jenkins-script-console-audit— Groovy Script Console
RCE + in-memory credential dump; detect/script//scriptText(T1059).jenkins-api-token↔jenkins-api-token-audit— mint a user API token for durable
non-interactive access; detectgenerateNewToken(T1098).jenkins-job-backdoor↔jenkins-job-backdoor-audit— create/reconfigure a job to
run attacker code on the controller + agents; detect/createItem//job/<name>/configSubmit
(T1072).
-
Terraform Cloud / IaC platform (3 companion-only red↔blue pairs) — detections
are Terraform Cloud audit-trail SPL (product: terraform, nestedresource.type/
resource.action):tfc-agent-hijack↔tfc-agent-audit— rogue agent pool routes plans/applies to
attacker infra (captures cloud creds + state); detectagent_poolcreate(T1543).tfc-token-backdoor↔tfc-token-audit— mint an org/team API token for durable
API + state access; detectauthentication_tokencreate(T1098).tfc-var-injection↔tfc-var-audit— inject a workspace env variable to run code
/ exfil at apply; detectvariablecreate/update(T1072).
-
HashiCorp Vault platform (3 companion-only red↔blue pairs), opening the
secrets-management seam — detections are Vault audit-device SPL (product: vault
on the Sigma side):vault-secret-exfil↔vault-secret-read-audit— bulk-read KV secrets to drain
the credential store; detectreadbreadth oversecret/paths (T1555).vault-approle-backdoor↔vault-approle-audit— create a rogue AppRole for
durable machine auth; detect create/update onauth/approle/role/(T1098).vault-audit-disable↔vault-audit-device-audit— disable a Vault audit device
to blind the SIEM; detectdeleteon asys/audit/path (T1562.001).
-
GitLab CI/CD platform (3 companion-only red↔blue pairs), mirroring the GitHub
Actions round on GitLab audit-event telemetry (product: gitlab, field
event_type):gl-runner-hijack↔gl-runner-audit— attach an attacker-controlled runner to
the project to capture CI jobs + masked variables; detect
set_runner_associated_projects(T1543).gl-protected-branch-off↔gl-protected-branch-audit— remove protected-branch
rules to land unreviewed code; detectprotected_branch_removed/
protected_branch_created(T1562.001).gl-token-backdoor↔gl-token-audit— mint a project access / deploy token for
durable access; detectproject_access_token_created/
personal_access_token_created/deploy_token_created(T1098).
-
Harbor container registry platform (3 companion-only red↔blue pairs), opening
the container-image / registry supply-chain seam — detections are Harbor
registry audit-log SPL (product: harboron the Sigma side):harbor-image-backdoor↔harbor-image-push-audit— push a trojanized image
over a trusted tag to poison downstream pulls; detectoperation=push
artifact (T1525, Implant Internal Image).harbor-robot-backdoor↔harbor-robot-audit— mint a long-lived robot
account for durable registry access; detectoperation=create
resource_type=robot(T1098).harbor-artifact-delete↔harbor-artifact-delete-audit— delete the trusted
artifact to force a poisoned re-pull + erase evidence; detectoperation=delete
artifact/repository (T1070).
-
GitHub Actions CI/CD platform (3 companion-only red↔blue pairs), opening a
new logsource the way the Okta round did — detections are GitHub Enterprise
audit-log SPL (product: githubon the Sigma side):gh-self-hosted-runner↔gh-runner-audit— rogue self-hosted runner
harvests job source + secrets; detectself_hosted_runner.created(T1543).gh-branch-protection-off↔gh-branch-protection-audit— disable/override
branch protection to land unreviewed code; detectprotected_branch.destroy/
protected_branch.policy_override(T1562.001).gh-deploy-key-backdoor↔gh-cred-audit— writable deploy key / fine-grained
PAT for durable access; detectrepo.create_deploy_key/
personal_access_token.access_granted(T1098).
-
Corpus is now 71 paired concepts + 1 unpaired recon entry.
v1.4.0
Fixed
sync-fanout.ymlSync step: call Kali'ssync-companion.shwith NO argument.
It was passedmainas a positional, but that arg is the REMOTE (URL), not a
branch so it tried to pull from a remote namedmain(fatal: 'main' does not appear to be a git repository). The script derives both the htpx remote
and the branch (main) fromcompanion.lockitself.sync-fanout.ymlauth: the Sync step now injects all git auth + the bot identity
via step-scopedGIT_CONFIG_COUNT/KEY/VALUEinstead ofgit config --global
(no token written to~/.gitconfig; consistent with the Resolve step).
htpx is read with the built-inGITHUB_TOKENvia a more-specific,
.git-anchoredurl.insteadOf(longest match wins, and the anchor avoids
rewriting same-prefix repos like<owner>/htpx-tools), so the
git subtree pullworks withoutFLEET_SYNC_TOKENever needing htpx access;
FLEET_SYNC_TOKENstays scoped to the dotfiles-Kali clone/push/PR.
v1.3.0
Fixed
sync-fanout.ymlResolve step: the htpx clone /ls-remotereads are now
authenticated with the built-inGITHUB_TOKEN(contents: read). They were
unauthenticated, so on a private htpx the fan-out died at the first clone with
could not read Username for 'https://github.com'. Auth is injected via
GIT_CONFIG_COUNT/KEY/VALUEenv (anurl.insteadOfrewrite scoped to that
step), so the token is never written to~/.gitconfigand can't shadow the next
step'sactions/checkout;FLEET_SYNC_TOKENstays reserved for the cross-repo
writes to dotfiles-Kali.- Release + fan-out workflows hardened (PR review):
auto-tag.shnow fails loud
when--releaseis requested butghis absent;auto-tag.ymlcuts
tags/releases only from the default branch;sync-fanout.ymlresolves and
verifies the tag exists before checkout (a bad dispatch input is a clean no-op),
aborts the sync ifgen-views.shfails (no PR), and fails on ANYcore.lock
diff versus the base branch — not just thecore_shafield.