@gendigital/sage-opencode 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/mcp-server.cjs +38 -10
  2. package/dist/mcp-server.cjs.map +2 -2
  3. package/dist/tool-handler.d.ts.map +1 -1
  4. package/dist/tool-handler.js +5 -3
  5. package/dist/tool-handler.js.map +1 -1
  6. package/package.json +3 -3
  7. package/resources/threats/_macros.yaml +193 -0
  8. package/resources/threats/agent-layer.yaml +19 -1
  9. package/resources/threats/commands.yaml +165 -31
  10. package/resources/threats/credentials.yaml +24 -4
  11. package/resources/threats/dummy.yaml +30 -0
  12. package/resources/threats/files.yaml +38 -0
  13. package/resources/threats/mac-commands.yaml +118 -27
  14. package/resources/threats/mac-credentials.yaml +34 -8
  15. package/resources/threats/mac-files.yaml +20 -0
  16. package/resources/threats/mac-obfuscation.yaml +28 -6
  17. package/resources/threats/mac-persistence.yaml +30 -4
  18. package/resources/threats/mac-supply-chain.yaml +12 -3
  19. package/resources/threats/mitre.yaml +325 -62
  20. package/resources/threats/obfuscation.yaml +33 -8
  21. package/resources/threats/persistence.yaml +40 -5
  22. package/resources/threats/prompt-injection.yaml +58 -0
  23. package/resources/threats/self-defense.yaml +15 -2
  24. package/resources/threats/supply_chain.yaml +6 -1
  25. package/resources/threats/urls.yaml +10 -0
  26. package/resources/threats/win-commands.yaml +294 -60
  27. package/resources/threats/win-credentials.yaml +68 -9
  28. package/resources/threats/win-files.yaml +20 -0
  29. package/resources/threats/win-obfuscation.yaml +56 -8
  30. package/resources/threats/win-persistence.yaml +45 -7
  31. package/resources/threats/win-supply-chain.yaml +5 -1
@@ -1 +1 @@
1
- {"version":3,"file":"tool-handler.d.ts","sourceRoot":"","sources":["../src/tool-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,aAAa,EAClB,KAAK,QAAQ,EACb,KAAK,iBAAiB,EAOtB,KAAK,MAAM,EAEX,MAAM,uBAAuB,CAAC;AAE/B,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAc/D,CAAC;AA+BF,MAAM,WAAW,kBAAkB;IAClC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,KAAK,IAAI,CAAC;CACrF;AAED,wBAAgB,kBAAkB,CACjC,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa,EAC5B,UAAU,EAAE,MAAM,EAClB,iBAAiB,EAAE,MAAM,EACzB,OAAO,CAAC,EAAE,kBAAkB,EAC5B,QAAQ,GAAE,QAA0B;mCAG5B;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,UAClD;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,KACvC,OAAO,CAAC,IAAI,CAAC;EAyIhB"}
1
+ {"version":3,"file":"tool-handler.d.ts","sourceRoot":"","sources":["../src/tool-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,aAAa,EAClB,KAAK,QAAQ,EACb,KAAK,iBAAiB,EAOtB,KAAK,MAAM,EAGX,MAAM,uBAAuB,CAAC;AAE/B,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAc/D,CAAC;AA+BF,MAAM,WAAW,kBAAkB;IAClC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,KAAK,IAAI,CAAC;CACrF;AAED,wBAAgB,kBAAkB,CACjC,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa,EAC5B,UAAU,EAAE,MAAM,EAClB,iBAAiB,EAAE,MAAM,EACzB,OAAO,CAAC,EAAE,kBAAkB,EAC5B,QAAQ,GAAE,QAA0B;mCAG5B;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,UAClD;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,KACvC,OAAO,CAAC,IAAI,CAAC;EA2IhB"}
@@ -1,4 +1,4 @@
1
- import { canonicalizeToolName, captureEnabled, captureHookInput, defaultBranding, formatDenyMessage, guardToolCall, summarizeArtifacts, } from "@gendigital/sage-core";
1
+ import { canonicalizeToolName, captureEnabled, captureHookInput, defaultBranding, formatDenyMessage, guardToolCall, ruleLabel, summarizeArtifacts, } from "@gendigital/sage-core";
2
2
  export const OPENCODE_TOOL_MAP = {
3
3
  bash: "Bash",
4
4
  webfetch: "WebFetch",
@@ -99,9 +99,11 @@ export function createToolHandlers(logger, approvalStore, threatsDir, trustedDom
99
99
  return;
100
100
  }
101
101
  try {
102
+ const rule = ruleLabel(verdict);
103
+ const ruleSuffix = rule ? ` [rule ${rule}]` : "";
102
104
  const toastMsg = verdict.decision === "deny"
103
- ? `${branding.name} blocked: ${verdict.reasons[0] ?? "Threat detected"} (${verdict.category})`
104
- : `${branding.name} flagged: ${verdict.reasons[0] ?? "Action flagged"} (${verdict.category})`;
105
+ ? `${branding.name} blocked: ${verdict.reasons[0] ?? "Threat detected"} (${verdict.category})${ruleSuffix}`
106
+ : `${branding.name} flagged: ${verdict.reasons[0] ?? "Action flagged"} (${verdict.category})${ruleSuffix}`;
105
107
  options?.showToast?.(toastMsg, verdict.severity === "critical" ? "error" : "warning");
106
108
  }
107
109
  catch {
@@ -1 +1 @@
1
- {"version":3,"file":"tool-handler.js","sourceRoot":"","sources":["../src/tool-handler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tool-handler.js","sourceRoot":"","sources":["../src/tool-handler.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.12.0",
7
+ "version": "0.13.0",
8
8
  "type": "module",
9
9
  "description": "Safety for Agents - ADR layer for OpenCode",
10
10
  "homepage": "https://github.com/gendigitalinc/sage",
@@ -32,8 +32,8 @@
32
32
  ],
33
33
  "dependencies": {
34
34
  "@opencode-ai/plugin": "^1.14.48",
35
- "@gendigital/sage-mcp": "0.12.0",
36
- "@gendigital/sage-core": "0.12.0"
35
+ "@gendigital/sage-core": "0.13.0",
36
+ "@gendigital/sage-mcp": "0.13.0"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/node": "^22.0.0",
@@ -0,0 +1,193 @@
1
+ # Shared pattern vocabulary for Sage threat rules
2
+ # Author: Gen Digital Inc.
3
+ # License: DRL-1.1 (see threats/LICENSE)
4
+ #
5
+ # These macros all serve one purpose: identifying which word in a command string
6
+ # is the program being run. A rule with `match_on: command` receives the whole
7
+ # command line, with no shell parsing and no notion of argv[0], so a rule meaning
8
+ # "this program is being executed" has to express that itself.
9
+ #
10
+ # ls; sudo -u root bash -c " env FOO=1 /usr/bin/ shred -u f"
11
+ # (1) (2) (3) (4) (5) (6) (7)
12
+ #
13
+ # (1) command boundary (5) optional path prefix
14
+ # (2) {{CMD_PREFIX}} (6) the program + {{NOT_FILENAME}}
15
+ # (3) {{DISPATCH_CTX}} (7) {{HAS_ARG}}
16
+ # (4) {{CMD_PREFIX}} again, now inside the dispatched payload
17
+ #
18
+ # {{CMD_POS}} is 1 through 5 — everything to the left of the program name. A rule
19
+ # adds the name, {{NOT_FILENAME}}, and {{HAS_ARG}} when a bare mention of the
20
+ # program must not fire:
21
+ #
22
+ # pattern: "{{CMD_POS}}shred{{NOT_FILENAME}}{{HAS_ARG}}"
23
+ #
24
+ # Mechanics: this is the one file in threats/ the loader reads as a mapping, and
25
+ # every other file must be a rule list. Macros may reference macros; a rule
26
+ # naming an undefined one is skipped with a warning. For the reasoning behind
27
+ # these patterns and the constraints on changing them, see "Writing
28
+ # command-position patterns" in docs/developer-guide.md.
29
+
30
+ # Interpreters that take a command payload as an argument (`bash -c "..."`).
31
+ # Split from {{SHELLS}} below because the two families disagree on what an
32
+ # *unquoted* payload means: POSIX `-c` takes exactly one argument as the
33
+ # command string — anything after it becomes `$0`, `$1`, ... positional
34
+ # parameters, not executed text (`bash -c sudo mkfs -t ext4 /dev/sdb1` only
35
+ # ever runs `sudo`; `mkfs -t ext4 /dev/sdb1` is inert positional params).
36
+ # PowerShell's `-Command` has no such rule — unquoted trailing words are
37
+ # rejoined into one command line. DISPATCH_CTX below relies on this split to
38
+ # require a quote only for the POSIX family.
39
+ POSIX_SHELLS: "bash|sh|zsh|dash|ksh|ash|busybox"
40
+ # powershell/pwsh admit an optional .exe suffix here, same as {{DISPATCH_CTX}}
41
+ # already does for its own inline powershell/pwsh mention below -- real,
42
+ # common Windows invocations. Left off {{POSIX_SHELLS}}'s own members for now:
43
+ # their Windows ports (WSL/git-bash/busybox-w32) exist but are less certain
44
+ # to appear with an explicit .exe suffix in practice; add if evidenced.
45
+ SHELLS: "{{POSIX_SHELLS}}|powershell(?:\\.exe)?|pwsh(?:\\.exe)?"
46
+
47
+ # Tokens that may sit between a boundary and the program name without changing
48
+ # which word is the program: wrapper commands, their flags, `--`, `VAR=value`.
49
+ #
50
+ # Keep it an allowlist. Admitting arbitrary words makes prose that merely
51
+ # mentions a command read as an invocation: `echo use bash -c "..."`.
52
+ #
53
+ # Never bound the loop. No token can match two of its branches, so the loop is
54
+ # already linear — 0.9 ms against a 24 KB run that never reaches a program. A cap
55
+ # would instead hand over an evasion, since inert padding is free: nine
56
+ # assignments in `A0=1 ... A8=1 shred -u f` push the program past a cap of eight
57
+ # and the rule goes quiet.
58
+ CMD_PREFIX: "(?:(?:sudo|doas|env|nohup|time|xargs|wsl(?:\\.exe)?)\\s+|--\\s+|--?[\\w][\\w{}.,:-]*(?:=\\S+|\\s[^\\s\\-=][^\\s=]*)?\\s+|[A-Za-z_]\\w*=\\S*\\s+)*"
59
+
60
+ # Points where a command line starts a *second* command, after which the next
61
+ # word is a program name again: `find ... -exec`, a shell `-c` payload, a
62
+ # `cmd /c` payload, or an `ssh host "..."` payload.
63
+ #
64
+ # Each dispatcher must itself be at program position, which is why every branch
65
+ # sits behind {{CMD_PREFIX}}. A branch that can match anywhere matches inside
66
+ # somebody else's argument, and the rule fires on text about the command rather
67
+ # than the command. Two consequences of the same requirement: `-exec` demands a
68
+ # `find`, and a shell name takes at most a `.exe` suffix — with a looser suffix,
69
+ # `bashful -c "..."` and `shellcheck -c "..."` count as shells.
70
+ #
71
+ # The cmd and PowerShell branches don't require the dispatched payload to be
72
+ # quoted: `cmd /c diskpart` and `powershell -Command shred -u f` are as real
73
+ # an invocation as the quoted forms, since both join unquoted trailing words
74
+ # back into one command line. The POSIX branch mostly keeps the quote
75
+ # mandatory — see {{POSIX_SHELLS}} above for why an unquoted multi-token
76
+ # payload there isn't the same thing — with one exception: a single trailing
77
+ # token with nothing after it (`bash -c diskpart`) has no positional
78
+ # parameters to misattribute, since there is nothing left over for them to
79
+ # be. That token is the entire command string either way, quoted or not.
80
+ #
81
+ # Known misses: a dispatcher named by absolute path (`/bin/bash -c "..."`,
82
+ # `C:\Windows\System32\cmd.exe /c ...`), command-runners that are not shells
83
+ # (`su -c "..."`), and a dispatched payload that is itself another dispatch
84
+ # (`cmd /c powershell -Command shred -u f`) — {{CMD_POS}} models one hop.
85
+ DISPATCH_CTX: "(?:{{CMD_PREFIX}}(?:\\bfind\\s[^;&|(\\n\"']{0,200}?-exec(?:dir)?\\s|\\bcmd(?:\\.exe)?\\s+(?:/[A-Za-z]+(?::\\S+)?\\s+)*/[ckCK]\\s*[\"']?|\\b(?:{{POSIX_SHELLS}})(?:\\.exe)?\\s+(?:-{1,2}[\\w-]+\\s+)*-{1,2}[A-Za-z]*[cC](?:ommand)?\\s*(?:[\"']|(?=[^\\s\"']+(?:$|[;&|(\\n`])))|\\b(?:powershell|pwsh)(?:\\.exe)?\\s+(?:-{1,2}[\\w-]+\\s+)*-{1,2}[A-Za-z]*[cC](?:ommand)?\\s*[\"']?|\\bssh\\s+(?:[^\\s\"']+\\s+){1,6}[\"']))?"
86
+
87
+ # Everything to the left of the program name — items 1 through 5 above.
88
+ #
89
+ # Known gap: `(` and a backtick are boundaries unconditionally, so a quoted
90
+ # mention containing either still matches: `echo "(shred -u f)"`, or a commit
91
+ # message quoting a command in backticks. Closing it means gating them the way
92
+ # quotes are gated, which costs `$(...)` and backtick substitution. Left open
93
+ # deliberately — one decision for every rule that adopts this macro, not one per
94
+ # rule.
95
+ #
96
+ # Used inside a variable-length lookbehind by {{NOT_AFTER_TEXT_CMD}} below --
97
+ # some regex constructs valid outside a lookbehind are invalid inside one, so
98
+ # check that macro's own comment before changing this pattern's shape.
99
+ CMD_POS: "(?:^|[;&|(\\n`])\\s*{{DISPATCH_CTX}}\\s*{{CMD_PREFIX}}(?:[^\\s\"';|&]{0,200}[\\\\/])?"
100
+
101
+ # Right-hand guard: reject longer names, so `shred` does not match `shred.py`
102
+ # or `shred-latency-probe`.
103
+ NOT_FILENAME: "(?![-\\w.])"
104
+
105
+ # Require at least one argument, so a bare mention of the program does not fire.
106
+ HAS_ARG: "(?=\\s+\\S)"
107
+
108
+ # Symmetric guard for identifiers that are legitimately not in command position
109
+ # — cmdlets, WMI class names — but must still not match as a fragment of a
110
+ # longer identifier or hyphenated compound: `Clear-EventLog` must not match
111
+ # `Clear-EventLogViewer` or `Old-Clear-EventLog`. Unlike {{NOT_FILENAME}}, the
112
+ # right-hand side does not also reject a trailing dot.
113
+ NOT_COMPOUND_LEFT: "(?<![-\\w])"
114
+ NOT_COMPOUND_RIGHT: "(?![-\\w])"
115
+
116
+ # Backward-looking guard for argument-position identifiers (used alongside
117
+ # {{NOT_COMPOUND_LEFT}}/{{NOT_COMPOUND_RIGHT}} above, on the left side): an
118
+ # argument value can appear in benign prose or a search command instead of a
119
+ # real invocation — `grep "CommandLineEventConsumer"`, `Select-String -Pattern
120
+ # "CommandLineEventConsumer"`. Neither {{NOT_COMPOUND_LEFT}} nor a filename
121
+ # guard catches this, since the identifier isn't a compound fragment or a
122
+ # filename there — it's a plain, correctly-bounded word, just not one being
123
+ # passed to something that acts on it.
124
+ #
125
+ # This suppresses a match only when the nearest preceding command-position
126
+ # token — found by reusing {{CMD_POS}} itself as the lookbehind's prefix, so
127
+ # any boundary, dispatch context, or wrapper prefix it already recognizes
128
+ # (`cmd /c findstr X`, `powershell -Command "Select-String X"`, `sudo grep
129
+ # X`) also counts here — is a command that only ever consumes its argument as
130
+ # inert text: a search, print, or read command. It is a denylist, and
131
+ # deliberately so: it can only ever remove false positives, never true
132
+ # positives, because nothing on the list executes or creates the thing the
133
+ # identifier names, so "not immediately after one of these" never hides a
134
+ # real invocation.
135
+ #
136
+ # Applies per occurrence, not per line: `Write-Host "mentions X"; New-CimInstance
137
+ # -ClassName X` suppresses the first X (immediately after Write-Host) but not
138
+ # the second (immediately after New-CimInstance), because the bounded span
139
+ # below cannot cross the `;` to misattribute the second occurrence to
140
+ # Write-Host. `(` is excluded from that span for the same reason: {{CMD_POS}}
141
+ # treats it as a command boundary (subshell/group open), so without the
142
+ # exclusion `Write-Host $(New-CimInstance -ClassName X)` would misattribute
143
+ # the real invocation inside the subshell to the outer Write-Host and
144
+ # suppress it.
145
+ #
146
+ # That `(` exclusion is narrowed to exempt one when it's glued directly to a
147
+ # preceding quote character (`(?<=["'])\(`): a real subshell/group open is
148
+ # always `$(` or a bare `(` after whitespace/a boundary, never immediately
149
+ # after `"` or `'`, so a `(` there can only be prose/data inside a quoted
150
+ # argument -- `grep "(CommandLineEventConsumer)"` -- not a nested command.
151
+ # Without the exemption this reintroduces the exact false positive the
152
+ # guard exists to remove.
153
+ #
154
+ # Deliberately does not gate on quotes. Real invocations routinely quote
155
+ # string parameters (`-ClassName "CommandLineEventConsumer"`), so treating
156
+ # "inside quotes" as the signal would hand an attacker a trivial evasion —
157
+ # just quote the real value. This guard keys on what precedes the identifier
158
+ # instead, which indirection through a listed command can still dodge
159
+ # (`$c = echo X; New-CimInstance -ClassName $c`) but quoting cannot.
160
+ #
161
+ # Known gaps, accepted:
162
+ # - The denylist is inherently incomplete — an unlisted benign command
163
+ # (`title X` on Windows) still false-positives. Expand as found, same
164
+ # posture as {{CMD_PREFIX}}'s wrapper list.
165
+ # - The quote-glued exemption above only catches `(` immediately after the
166
+ # opening quote. A `(` deeper inside the same quoted string --
167
+ # `grep "the (CommandLineEventConsumer) tool"` -- still breaks the span
168
+ # and false-positives, since telling that apart from a real subshell open
169
+ # would need actual quote-state tracking, which this no-shell-parsing
170
+ # engine doesn't have (same reason quoting isn't gated on generally,
171
+ # above). Narrower than before the fix, not eliminated.
172
+ #
173
+ # The {0,500} cap on the gap between the denylisted command and the
174
+ # identifier is a lookbehind-width bound, not a semantic limit -- it only
175
+ # needs to comfortably cover realistic flag/argument text before the
176
+ # identifier (e.g. `grep -rn --include=*.ps1 CommandLineEventConsumer`);
177
+ # widen it if a real invocation needs more room. Raised from 200 -> 500
178
+ # after a longer-than-200-char real grep/Select-String invocation was shown
179
+ # to fall outside it and false-positive; 500 is still a small bounded
180
+ # constant, so it doesn't change the linear-time argument below.
181
+ #
182
+ # Embedding {{CMD_POS}} (rather than a bare boundary-char class) costs
183
+ # nothing extra: {{CMD_POS}}'s own quantifiers are already bounded, so
184
+ # nesting it inside a variable-length lookbehind stays linear -- verified
185
+ # against 10-50K character adversarial inputs (repeated near-miss dispatch
186
+ # fragments, VAR=value chains, boundary characters), all well under 2ms.
187
+ #
188
+ # Depth budget: this macro's chain (NOT_AFTER_TEXT_CMD -> CMD_POS ->
189
+ # {DISPATCH_CTX, CMD_PREFIX} -> {CMD_PREFIX, POSIX_SHELLS}) fully resolves in
190
+ # 4 of MAX_MACRO_PASSES's 5 passes -- one pass of headroom. That limit exists
191
+ # to catch a self-referencing cycle, not to cap legitimate depth, so raise it
192
+ # if a real change needs the extra pass rather than working around it here.
193
+ NOT_AFTER_TEXT_CMD: "(?<!{{CMD_POS}}(?:grep|egrep|fgrep|rg|ag|ack|awk|sed|cat|head|tail|less|more|strings|echo|printf|findstr|type|Select-String|sls|Write-Output|Write-Host|Write-Verbose|Write-Debug|Compare-Object)\\b(?:[^;&|(\\n`]|(?<=[\"'])\\(){0,500})"
@@ -38,6 +38,8 @@
38
38
  # ===========================================================================
39
39
 
40
40
  - id: "CLT-MCP-004"
41
+ version: 1
42
+ detection_name: "Other:SageMcp-D [Heur]"
41
43
  category: mcp_poisoning
42
44
  severity: warning
43
45
  confidence: 0.85
@@ -59,6 +61,8 @@
59
61
  # ===========================================================================
60
62
 
61
63
  - id: "CLT-SKL-001"
64
+ version: 1
65
+ detection_name: "Other:SageSkill-A [Heur]"
62
66
  category: skill_compromise
63
67
  severity: critical
64
68
  confidence: 0.85
@@ -78,10 +82,12 @@
78
82
  # CLT-SKL-003 intentionally omitted — dropped for FP risk during ATR curation.
79
83
 
80
84
  - id: "CLT-SKL-002"
85
+ version: 1
86
+ detection_name: "Other:SageSkill-B [Heur]"
81
87
  category: skill_compromise
82
88
  severity: critical
83
89
  confidence: 0.85
84
- pattern: "(eval\\s*\\$\\(\\s*echo\\s+[\"'][A-Za-z0-9+/=]{20,}[\"']\\s*\\|\\s*base64\\s+-d|echo\\s+[\"'][A-Za-z0-9+/=]{20,}[\"']\\s*\\|\\s*base64\\s+(-d|--decode)\\s*\\|\\s*(bash|sh|python|node|ruby|perl))"
90
+ pattern: "(eval\\s*\\$\\(\\s*echo\\s+[\"'][A-Za-z0-9+/=]{20,}[\"']\\s*\\|\\s*base64\\s+-d|echo\\s+[\"'][A-Za-z0-9+/=]{20,}[\"']\\s*\\|\\s*base64\\s+(-d|--decode)\\s*\\|\\s*(?:{{SHELLS}}|python|node|ruby|perl))"
85
91
  match_on: content
86
92
  case_insensitive: true
87
93
  title: "Base64-encoded payload piped to interpreter inside skill content"
@@ -90,6 +96,8 @@
90
96
  # Source: ATR-2026-00121 (pattern unchanged from upstream).
91
97
 
92
98
  - id: "CLT-SKL-004"
99
+ version: 1
100
+ detection_name: "Other:SageSkill-D [Heur]"
93
101
  category: skill_compromise
94
102
  severity: critical
95
103
  confidence: 0.85
@@ -104,6 +112,8 @@
104
112
  # exfil-keyword focus (distinct from CLT-PI-002's instruction-override focus).
105
113
 
106
114
  - id: "CLT-SKL-005"
115
+ version: 1
116
+ detection_name: "Other:SageSkill-E [Heur]"
107
117
  category: skill_compromise
108
118
  severity: critical
109
119
  confidence: 0.95
@@ -118,6 +128,8 @@
118
128
  # injection signature with no legitimate use.
119
129
 
120
130
  - id: "CLT-SKL-006"
131
+ version: 1
132
+ detection_name: "Other:SageSkill-F [Heur]"
121
133
  category: skill_compromise
122
134
  severity: critical
123
135
  confidence: 0.85
@@ -137,6 +149,8 @@
137
149
  # CLT-SKL-007 intentionally omitted — dropped for FP risk during ATR curation.
138
150
 
139
151
  - id: "CLT-SKL-008"
152
+ version: 1
153
+ detection_name: "Other:SageSkill-H [Heur]"
140
154
  category: skill_compromise
141
155
  severity: warning
142
156
  confidence: 0.85
@@ -154,6 +168,8 @@
154
168
  # ===========================================================================
155
169
 
156
170
  - id: "CLT-CTX-003"
171
+ version: 1
172
+ detection_name: "Other:SageContext-C [Heur]"
157
173
  category: context_exfiltration
158
174
  severity: critical
159
175
  confidence: 0.95
@@ -172,6 +188,8 @@
172
188
  # ===========================================================================
173
189
 
174
190
  - id: "CLT-SUPPLY-002"
191
+ version: 1
192
+ detection_name: "Other:SageSupplyChain-B [Heur]"
175
193
  category: supply_chain
176
194
  severity: warning
177
195
  confidence: 0.95