Skip to content

feat(cso): Phase 8 Tier 3 — mini-shai-hulud campaign rules (comprehensive mode)#1523

Open
slash9494 wants to merge 5 commits into
garrytan:mainfrom
slash9494:feat/cso-mini-shai-hulud-phase8
Open

feat(cso): Phase 8 Tier 3 — mini-shai-hulud campaign rules (comprehensive mode)#1523
slash9494 wants to merge 5 commits into
garrytan:mainfrom
slash9494:feat/cso-mini-shai-hulud-phase8

Conversation

@slash9494
Copy link
Copy Markdown

@slash9494 slash9494 commented May 15, 2026

Summary

  • Adds 4 rules to Phase 8 (Skill Supply Chain) detecting the 2026-05-11
    "mini-shai-hulud" npm/PyPI supply chain campaign
    (GHSA-g7cv-rxg3-hmpx / CVE-2026-45321, severity critical, reviewed).
  • All rules comprehensive-mode-only — surface as TENTATIVE under the 2/10
    gate. Daily mode's 8/10 zero-noise contract is preserved (no rule fires
    in daily mode).
  • Closes existing Phase 8 gaps for: Claude Code settings hook injection,
    obfuscated payloads under .claude/**/.vscode/**, auto-run persistence
    bridges, Session-protocol C2.
  • No new skill, no new phase, no scope-flag changes. Per feat: /fortress - 1001-vector security audit with auto-fix #1011 closure
    ("methodology depth over feature count").

Rules (Phase 8, comprehensive mode only)

R1 [TENTATIVE] — Any Claude Code settings file (.claude/settings.json,
.claude/settings.local.json, ~/.claude/settings.json, or
~/.claude/settings.local.json) hooks.*.command field containing a
/proc/.*/mem read pattern. Direct process-memory introspection from a Claude Code hook has
no legitimate use; it is a known credential-exfiltration technique against
runner processes.

R2 [TENTATIVE].claude/**/*.{js,mjs,ts,cjs} or
.vscode/**/*.{js,mjs,ts,cjs} containing both the _0x[0-9a-f]{4,}
variable pattern (≥3 distinct occurrences) and at least one of
createDecipheriv, gunzip, gunzipSync, inflateRawSync,
inflateSync. Do not alert on ordinary minified bundles or inline
sourcemap output unless both halves match.

R3 [TENTATIVE] — File under .claude/** or .vscode/** where all
three
hold: (a) referenced from any Claude Code settings file
(.claude/settings.json, .claude/settings.local.json,
~/.claude/settings.json, or ~/.claude/settings.local.json)
hooks.*.command via node|bun|python3?|bash|sh <path>,
node --require <path>, node -e <inline-require>, or direct path
invocation, OR from a tasks.json task with
runOptions.runOn: "folderOpen"; (b) not present in package manifest
evidence (package.json files array, npm tarball, or installed
locked-package artifacts); (c) not exempt by the Tier 3 FP guards below.
Auto-run persistence bridge in TTP form — renaming the payload file does
not evade.

R4 [TENTATIVE] — Strings filev2.getsession.org, seed1.getsession.org,
seed2.getsession.org, or seed3.getsession.org appearing inside an
executable context:
a hooks.*.command value, a tasks.json command/args field, or a
fetch/http.get/axios/socket.connect/curl/nc call inside a
.{js,mjs,ts,cjs,sh,py} file under .claude/**/.vscode/**.
Documentation / README / IOC-note mentions do not fire.

FP guards (Phase 8 "FP rules" section)

  • gstack-installed paths trusted: ~/.claude/skills/gstack/,
    ~/.claude/skills/gstack-*/, ~/.claude/hooks/ when content matches
    distributed checksums.
  • R3 excluded under .vscode/extensions/ and inside any directory listed
    in the root package.json workspaces field.

Where this lands

All rules and FP guards are additive into the existing
### Phase 8: Skill Supply Chain section of cso/SKILL.md.tmpl
(generated cso/SKILL.md updated via bun run gen:skill-docs). No phase
renumbering, no scope-flag wiring changes, no fingerprint schema
changes.

Test plan

  • 4/4 rules fire on the GHSA-g7cv-rxg3-hmpx IOC set under
    /cso --comprehensive
  • 0 findings under default /cso daily mode (TENTATIVE-only routing
    confirmed)
  • 0 FP on gstack itself
  • 0 FP on 50 popular Claude Code skill repos sampled from public
    marketplaces, --comprehensive mode
  • R3 monorepo regression: pnpm/yarn workspace package with
    .vscode/setup.mjs referenced by a tasks.json auto-run task —
    0 fire
  • Existing Phase 8 prompt-injection tests — no regression

Coordination

Detection-only. R3 (quarantine file or remove auto-run reference) and
R4 (quarantine the line) are mechanically auto-fixable once #1053
(/cso --fix) lands. If #1053 merges first this PR is purely additive;
different diff area.

References

slash9494 added 5 commits May 15, 2026 20:49
…sive mode)

Adds 4 detection rules for the 2026-05-11 npm/PyPI supply chain campaign
(GHSA-g7cv-rxg3-hmpx / CVE-2026-45321) into Phase 8 (Skill Supply Chain).

- R7 (Claude Code settings hook injection — /proc/*/mem read pattern)
- R8 (obfuscated payload heuristic — _0x patterns + crypto-decode)
- R9 (auto-run persistence bridge — manifest-undeclared file referenced
  by hook or tasks.json runOn: folderOpen)
- R12 (Session-protocol C2 deny-list — executable context only)

All rules surface only under /cso --comprehensive with TENTATIVE marking;
daily mode's 8/10 zero-noise contract is preserved.

Closes Phase 8 gaps for IDE-config infection vectors that the existing
generic-pattern matching (curl/wget/exfiltrat/IGNORE PREVIOUS) does not
catch. No new skill, no new phase, no scope-flag changes (per garrytan#1011).
A static-string IOC match against the shell brace expression
seed{1,2,3}.getsession.org would search for that exact 25-char string
and miss the actual hosts (seed1.getsession.org, seed2.getsession.org,
seed3.getsession.org). Spell them out so comprehensive-mode Grep
hits the real campaign infrastructure.
SKILL.md is executable prompt code, not documentation — campaign
attribution belongs in commit history and PR description, not in the
timeless rule definitions. R7 rationale generalized; Tier 3 intro
pruned of the campaign citation. Rule behavior unchanged.
- R7/R9: replace "user-global equivalents" shorthand with explicit
  ~/.claude/settings.json and ~/.claude/settings.local.json paths
- R8: drop "Matches the campaign's obfuscation" prose (campaign-specific
  decoration) and rewrite the FP rationale as instruction
- R9 (a): add node --require and node -e <inline-require> to the
  interpreter invocation patterns (covers indirect-require evasion)
- R9 (b): replace ambiguous "lockfile integrity hash" with "installed
  locked-package artifacts" — lockfile integrity is per-package, not
  per-file, so the previous wording invited reviewer confusion

Rule trigger surface unchanged for R7 (mem-read) and R12 (Session
domains in executable context). R8's matching condition is unchanged
(_0x density + crypto-decode call). R9 gains two indirect invocation
patterns and clarified manifest wording.
The R7/R8/R9/R12 numbering reflected a 14-rule draft history where R10,
R11, R13, R14 were dropped during review (hash-level IOCs and cloud-SDK
false-positive risks). Renumbering closes the gaps so reviewers see four
contiguous rules instead of wondering what R10/R11 were.

Rule definitions and FP guards are unchanged. Self-ref in the FP guards
section updated (R9 → R3).
@slash9494 slash9494 marked this pull request as ready for review May 15, 2026 13:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant