@gendigital/sage-opencode 0.10.0 → 0.11.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.
- package/README.md +5 -5
- package/dist/bundled-dirs.d.ts +1 -1
- package/dist/bundled-dirs.d.ts.map +1 -1
- package/dist/bundled-dirs.js +1 -1
- package/dist/bundled-dirs.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +42 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.cjs +31776 -0
- package/dist/mcp-server.cjs.map +7 -0
- package/dist/startup-scan.d.ts.map +1 -1
- package/dist/startup-scan.js +3 -2
- package/dist/startup-scan.js.map +1 -1
- package/dist/tool-handler.d.ts +1 -1
- package/dist/tool-handler.d.ts.map +1 -1
- package/dist/tool-handler.js +9 -3
- package/dist/tool-handler.js.map +1 -1
- package/package.json +5 -3
- package/resources/threats/agent-layer.yaml +186 -0
- package/resources/threats/commands.yaml +24 -53
- package/resources/threats/credentials.yaml +12 -20
- package/resources/threats/dummy.yaml +22 -33
- package/resources/threats/files.yaml +34 -53
- package/resources/threats/mac-commands.yaml +20 -47
- package/resources/threats/mac-credentials.yaml +4 -12
- package/resources/threats/mac-files.yaml +5 -15
- package/resources/threats/mac-obfuscation.yaml +6 -13
- package/resources/threats/mac-persistence.yaml +11 -20
- package/resources/threats/mac-supply-chain.yaml +5 -8
- package/resources/threats/mitre.yaml +105 -167
- package/resources/threats/obfuscation.yaml +7 -15
- package/resources/threats/persistence.yaml +10 -17
- package/resources/threats/prompt-injection.yaml +92 -43
- package/resources/threats/self-defense.yaml +8 -12
- package/resources/threats/supply_chain.yaml +1 -2
- package/resources/threats/urls.yaml +9 -14
- package/resources/threats/win-commands.yaml +46 -106
- package/resources/threats/win-credentials.yaml +14 -24
- package/resources/threats/win-files.yaml +10 -20
- package/resources/threats/win-obfuscation.yaml +21 -37
- package/resources/threats/win-persistence.yaml +8 -16
- package/resources/threats/win-supply-chain.yaml +2 -3
- /package/resources/{allowlists → trusted-domains}/trusted-installer-domains.yaml +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"startup-scan.d.ts","sourceRoot":"","sources":["../src/startup-scan.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACN,KAAK,QAAQ,EAGb,KAAK,MAAM,EACX,MAAM,uBAAuB,CAAC;AAmB/B,wBAAgB,wBAAwB,CACvC,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,MAAM,EACnB,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,EAChC,QAAQ,GAAE,QAA0B,GAClC,MAAM,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"startup-scan.d.ts","sourceRoot":"","sources":["../src/startup-scan.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACN,KAAK,QAAQ,EAGb,KAAK,MAAM,EACX,MAAM,uBAAuB,CAAC;AAmB/B,wBAAgB,wBAAwB,CACvC,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,MAAM,EACnB,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,EAChC,QAAQ,GAAE,QAA0B,GAClC,MAAM,OAAO,CAAC,IAAI,CAAC,CAkBrB"}
|
package/dist/startup-scan.js
CHANGED
|
@@ -22,7 +22,7 @@ function resolveModelDownloadWorkerPath() {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
export function createSessionScanHandler(logger, projectDir, onResult, branding = defaultBranding) {
|
|
25
|
-
const { threatsDir,
|
|
25
|
+
const { threatsDir, trustedDomainsDir } = getBundledDataDirs();
|
|
26
26
|
const version = getSageVersion();
|
|
27
27
|
return coreScanHandler({
|
|
28
28
|
logger,
|
|
@@ -30,9 +30,10 @@ export function createSessionScanHandler(logger, projectDir, onResult, branding
|
|
|
30
30
|
discoverPlugins: () => discoverOpenCodePlugins(logger, projectDir, branding),
|
|
31
31
|
selfPrefix: "@gendigital/sage-opencode@",
|
|
32
32
|
threatsDir,
|
|
33
|
-
|
|
33
|
+
trustedDomainsDir,
|
|
34
34
|
version,
|
|
35
35
|
agentRuntime: "opencode",
|
|
36
|
+
// No agentRuntimeVersion: the OpenCode plugin SDK exposes no host version synchronously.
|
|
36
37
|
branding,
|
|
37
38
|
onResult,
|
|
38
39
|
modelDownloadWorkerPath: resolveModelDownloadWorkerPath(),
|
package/dist/startup-scan.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"startup-scan.js","sourceRoot":"","sources":["../src/startup-scan.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAEN,iBAAiB,IAAI,eAAe,EACpC,eAAe,GAEf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAEhE;;;;;GAKG;AACH,SAAS,8BAA8B;IACtC,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3C,OAAO,GAAG,CAAC,OAAO,CAAC,qDAAqD,CAAC,CAAC;IAC3E,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,wBAAwB,CACvC,MAAc,EACd,UAAmB,EACnB,QAAgC,EAChC,WAAqB,eAAe;IAEpC,MAAM,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"startup-scan.js","sourceRoot":"","sources":["../src/startup-scan.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAEN,iBAAiB,IAAI,eAAe,EACpC,eAAe,GAEf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAEhE;;;;;GAKG;AACH,SAAS,8BAA8B;IACtC,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3C,OAAO,GAAG,CAAC,OAAO,CAAC,qDAAqD,CAAC,CAAC;IAC3E,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,wBAAwB,CACvC,MAAc,EACd,UAAmB,EACnB,QAAgC,EAChC,WAAqB,eAAe;IAEpC,MAAM,EAAE,UAAU,EAAE,iBAAiB,EAAE,GAAG,kBAAkB,EAAE,CAAC;IAC/D,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;IAEjC,OAAO,eAAe,CAAC;QACtB,MAAM;QACN,OAAO,EAAE,SAAS;QAClB,eAAe,EAAE,GAAG,EAAE,CAAC,uBAAuB,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC;QAC5E,UAAU,EAAE,4BAA4B;QACxC,UAAU;QACV,iBAAiB;QACjB,OAAO;QACP,YAAY,EAAE,UAAU;QACxB,yFAAyF;QACzF,QAAQ;QACR,QAAQ;QACR,uBAAuB,EAAE,8BAA8B,EAAE;KACzD,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/tool-handler.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type ApprovalStore, type Branding, type Logger } from "@gendigital/sage
|
|
|
2
2
|
export interface ToolHandlerOptions {
|
|
3
3
|
showToast?: (msg: string, variant: "info" | "success" | "warning" | "error") => void;
|
|
4
4
|
}
|
|
5
|
-
export declare function createToolHandlers(logger: Logger, approvalStore: ApprovalStore, threatsDir: string,
|
|
5
|
+
export declare function createToolHandlers(logger: Logger, approvalStore: ApprovalStore, threatsDir: string, trustedDomainsDir: string, options?: ToolHandlerOptions, branding?: Branding): {
|
|
6
6
|
"tool.execute.before": (input: {
|
|
7
7
|
tool: string;
|
|
8
8
|
sessionID: string;
|
|
@@ -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,EAMb,KAAK,MAAM,EAEX,MAAM,uBAAuB,CAAC;AA+C/B,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,
|
|
1
|
+
{"version":3,"file":"tool-handler.d.ts","sourceRoot":"","sources":["../src/tool-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,aAAa,EAClB,KAAK,QAAQ,EAMb,KAAK,MAAM,EAEX,MAAM,uBAAuB,CAAC;AA+C/B,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;EAuHhB"}
|
package/dist/tool-handler.js
CHANGED
|
@@ -37,7 +37,7 @@ function normalizeToolInput(toolName, args) {
|
|
|
37
37
|
return args;
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
-
export function createToolHandlers(logger, approvalStore, threatsDir,
|
|
40
|
+
export function createToolHandlers(logger, approvalStore, threatsDir, trustedDomainsDir, options, branding = defaultBranding) {
|
|
41
41
|
const beforeToolUse = async (input, output) => {
|
|
42
42
|
const completeHook = (result, data = {}) => {
|
|
43
43
|
logger.debug("OpenCode tool hook completed", {
|
|
@@ -74,7 +74,7 @@ export function createToolHandlers(logger, approvalStore, threatsDir, allowlists
|
|
|
74
74
|
artifacts,
|
|
75
75
|
}, {
|
|
76
76
|
threatsDir,
|
|
77
|
-
|
|
77
|
+
trustedDomainsDir,
|
|
78
78
|
logger,
|
|
79
79
|
}, approvalStore);
|
|
80
80
|
if (verdict.decision === "allow") {
|
|
@@ -107,7 +107,13 @@ export function createToolHandlers(logger, approvalStore, threatsDir, allowlists
|
|
|
107
107
|
throw new SageVerdictBlockError(formatDenyMessage(verdict, branding));
|
|
108
108
|
}
|
|
109
109
|
// ask — actionId is always set for ask verdicts
|
|
110
|
-
const
|
|
110
|
+
const maxReasons = 3;
|
|
111
|
+
const reasons = verdict.reasons.length > 0
|
|
112
|
+
? verdict.reasons.slice(0, maxReasons).join("; ") +
|
|
113
|
+
(verdict.reasons.length > maxReasons
|
|
114
|
+
? `; ... and ${verdict.reasons.length - maxReasons} more`
|
|
115
|
+
: "")
|
|
116
|
+
: verdict.category;
|
|
111
117
|
completeHook("evaluated", {
|
|
112
118
|
toolName,
|
|
113
119
|
decision: verdict.decision,
|
package/dist/tool-handler.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-handler.js","sourceRoot":"","sources":["../src/tool-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,oBAAoB,EACpB,eAAe,EACf,iBAAiB,EACjB,aAAa,EAEb,kBAAkB,GAClB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,iBAAiB,GAAsC;IAC5D,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,UAAU;IACpB,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,EAAE,EAAE,MAAM;IACV,UAAU,EAAE,YAAY;IACxB,SAAS,EAAE,WAAW;IACtB,QAAQ,EAAE,UAAU;IACpB,IAAI,EAAE,MAAM;IACZ,UAAU,EAAE,WAAW;CACvB,CAAC;AAEF,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,SAAS,QAAQ,CAAC,KAAc;IAC/B,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACtD,CAAC;AAED,SAAS,kBAAkB,CAC1B,QAAgB,EAChB,IAA6B;IAE7B,QAAQ,QAAQ,EAAE,CAAC;QAClB,KAAK,OAAO;YACX,OAAO;gBACN,GAAG,IAAI;gBACP,SAAS,EAAE,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE;gBACpE,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;aACrC,CAAC;QACH,KAAK,MAAM;YACV,OAAO;gBACN,GAAG,IAAI;gBACP,SAAS,EAAE,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE;gBACpE,UAAU,EAAE,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE;aACvE,CAAC;QACH;YACC,OAAO,IAAI,CAAC;IACd,CAAC;AACF,CAAC;AAMD,MAAM,UAAU,kBAAkB,CACjC,MAAc,EACd,aAA4B,EAC5B,UAAkB,EAClB,
|
|
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.
|
|
7
|
+
"version": "0.11.0",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"description": "Safety for Agents - ADR layer for OpenCode",
|
|
10
10
|
"homepage": "https://github.com/gendigitalinc/sage",
|
|
@@ -32,10 +32,12 @@
|
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@opencode-ai/plugin": "^1.14.48",
|
|
35
|
-
"@gendigital/sage-core": "0.
|
|
35
|
+
"@gendigital/sage-core": "0.11.0",
|
|
36
|
+
"@gendigital/sage-mcp": "0.11.0"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
39
|
"@types/node": "^22.0.0",
|
|
40
|
+
"esbuild": "^0.25.0",
|
|
39
41
|
"typescript": "^5.9.0",
|
|
40
42
|
"vitest": "^4.0.0"
|
|
41
43
|
},
|
|
@@ -52,7 +54,7 @@
|
|
|
52
54
|
"malware-detection"
|
|
53
55
|
],
|
|
54
56
|
"scripts": {
|
|
55
|
-
"build": "pnpm
|
|
57
|
+
"build": "pnpm run clean && pnpm run sync:assets && tsc && node esbuild.config.mjs",
|
|
56
58
|
"clean": "node ../../scripts/clean.mjs dist resources tsconfig.tsbuildinfo",
|
|
57
59
|
"sync:assets": "node scripts/sync-assets.mjs",
|
|
58
60
|
"test": "vitest run"
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# Agent-layer threat patterns for Sage
|
|
2
|
+
#
|
|
3
|
+
# Author: ATR (Agent Threat Rules) community contributors
|
|
4
|
+
# Upstream: https://github.com/Agent-Threat-Rule/agent-threat-rules
|
|
5
|
+
# Contributed per issue #30 + vaclavbelak's comment
|
|
6
|
+
# (https://github.com/gendigitalinc/sage/issues/30#issuecomment-4266904912)
|
|
7
|
+
#
|
|
8
|
+
# License: MIT
|
|
9
|
+
# Rules in this file are adapted from the ATR project
|
|
10
|
+
# (https://github.com/Agent-Threat-Rule/agent-threat-rules),
|
|
11
|
+
# Copyright (c) 2026 ATR Contributors, and are included in Sage
|
|
12
|
+
# under the ATR MIT license per explicit agreement in issue #30.
|
|
13
|
+
# Sage-specific modifications to each rule are noted in its comment block.
|
|
14
|
+
#
|
|
15
|
+
# What this file covers (gaps vs Sage's existing rules):
|
|
16
|
+
# MCP tool / response attacks CLT-MCP-004 (1 rule -- path traversal)
|
|
17
|
+
# Skill package compromise CLT-SKL-001..008 (6 rules -- IDs 001,002,004,005,006,008; 003/007 dropped for FP risk)
|
|
18
|
+
# Context exfiltration CLT-CTX-003 (1 rule -- PEM key leak)
|
|
19
|
+
# Supply chain CLT-SUPPLY-002 (1 rule)
|
|
20
|
+
#
|
|
21
|
+
# All prompt_injection rules have been moved to prompt-injection.yaml:
|
|
22
|
+
# CLT-PI-052 (IMPORTANT-tag shadowing, ex CLT-MCP-002)
|
|
23
|
+
# CLT-PI-091..093 (HTML-comment delivery, jailbreak persona, CJK pivot)
|
|
24
|
+
# Dropped: CLT-CTX-002 (instruction tampering) -- covered by CLT-PI-001..005
|
|
25
|
+
#
|
|
26
|
+
# Design notes:
|
|
27
|
+
# - All rules use `match_on: content` so they fire on Write/Edit content,
|
|
28
|
+
# plugin/skill file scans, and any agent integration that passes a
|
|
29
|
+
# `content` artifact. They complement (do not duplicate) Sage's existing
|
|
30
|
+
# command/URL/credential-file rules.
|
|
31
|
+
# - Confidence values are calibrated to Sage's policy zones (docs/decision-pipeline.md):
|
|
32
|
+
# 0.95 = attack-only signal, deny under all sensitivities
|
|
33
|
+
# 0.85 = high-precision attack pattern, deny paranoid/balanced, ask relaxed
|
|
34
|
+
# - `case_insensitive: true` replaces ATR's `(?i)` inline flag.
|
|
35
|
+
|
|
36
|
+
# ===========================================================================
|
|
37
|
+
# MCP TOOL & RESPONSE POISONING
|
|
38
|
+
# ===========================================================================
|
|
39
|
+
|
|
40
|
+
- id: "CLT-MCP-004"
|
|
41
|
+
category: mcp_poisoning
|
|
42
|
+
severity: warning
|
|
43
|
+
confidence: 0.85
|
|
44
|
+
pattern: "\\.\\.[\\/\\\\](?:\\.\\.[\\/\\\\])+(?:etc|proc|root|sys|boot|passwd|shadow|shadow\\.bak|master\\.key)(?:[\\/\\\\]|\\s|$)"
|
|
45
|
+
match_on: content
|
|
46
|
+
case_insensitive: false
|
|
47
|
+
title: "Path traversal targeting system directory (/etc, /proc, /root, /sys, ...)"
|
|
48
|
+
expires_at: null
|
|
49
|
+
revoked: false
|
|
50
|
+
# Adapted from ATR-2026-00012: narrowed to require 2+ traversal hops terminating
|
|
51
|
+
# in a sensitive system directory (dropped dev, hosts from ATR's list); reduces
|
|
52
|
+
# FP on benign code examples that use relative paths like ../../src/.
|
|
53
|
+
# Fires in pre-hook (Write/Edit content blocking) and session-start plugin scans
|
|
54
|
+
# only; post-hook scanning is limited to category=prompt_injection rules.
|
|
55
|
+
|
|
56
|
+
# ===========================================================================
|
|
57
|
+
# SKILL PACKAGE COMPROMISE -- malicious content inside SKILL.md, plugin
|
|
58
|
+
# manifests, or skill package files.
|
|
59
|
+
# ===========================================================================
|
|
60
|
+
|
|
61
|
+
- id: "CLT-SKL-001"
|
|
62
|
+
category: skill_compromise
|
|
63
|
+
severity: critical
|
|
64
|
+
confidence: 0.85
|
|
65
|
+
pattern: "you\\s+(must|should|will|shall)\\s+(ignore|disregard|override|forget|bypass|circumvent|supersede|set\\s+aside|discard|abandon)\\s+(all\\s+)?(previous|prior|system|safety|security)\\s+(instructions?|prompts?|rules?|guidelines?|policies|restrictions?)"
|
|
66
|
+
match_on: content
|
|
67
|
+
case_insensitive: true
|
|
68
|
+
title: "SKILL.md prompt injection via mandatory override"
|
|
69
|
+
expires_at: null
|
|
70
|
+
revoked: false
|
|
71
|
+
# Adapted from ATR-2026-00120: simplified to single regex targeting the
|
|
72
|
+
# mandatory-subject ("you must/shall") framing only; omits ATR's broader
|
|
73
|
+
# context-window injection and multi-condition layers.
|
|
74
|
+
# Intentional layering with CLT-PI-001..004: those rules catch the bare
|
|
75
|
+
# imperative verb; this rule adds a distinct signal for the explicit mandatory
|
|
76
|
+
# subject, increasing confidence when both fire on the same payload.
|
|
77
|
+
|
|
78
|
+
# CLT-SKL-003 intentionally omitted — dropped for FP risk during ATR curation.
|
|
79
|
+
|
|
80
|
+
- id: "CLT-SKL-002"
|
|
81
|
+
category: skill_compromise
|
|
82
|
+
severity: critical
|
|
83
|
+
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))"
|
|
85
|
+
match_on: content
|
|
86
|
+
case_insensitive: true
|
|
87
|
+
title: "Base64-encoded payload piped to interpreter inside skill content"
|
|
88
|
+
expires_at: null
|
|
89
|
+
revoked: false
|
|
90
|
+
# Source: ATR-2026-00121 (pattern unchanged from upstream).
|
|
91
|
+
|
|
92
|
+
- id: "CLT-SKL-004"
|
|
93
|
+
category: skill_compromise
|
|
94
|
+
severity: critical
|
|
95
|
+
confidence: 0.85
|
|
96
|
+
pattern: "<!--[\\s\\S]{0,200}?(agent\\s+should|send\\s+all|output\\s+all|exfiltrate|curl\\s|wget\\s|post\\s+.{0,30}(key|credential|token|password|secret)|api[_-]?key.{0,30}https?://)"
|
|
97
|
+
match_on: content
|
|
98
|
+
case_insensitive: true
|
|
99
|
+
title: "Hidden payload in HTML comment within skill content"
|
|
100
|
+
expires_at: null
|
|
101
|
+
revoked: false
|
|
102
|
+
# Adapted from ATR-2026-00128: changed ATR's [^>] lookahead to [\s\S] to avoid
|
|
103
|
+
# false negatives when a hyphen precedes an exfil keyword; maintains same
|
|
104
|
+
# exfil-keyword focus (distinct from CLT-PI-002's instruction-override focus).
|
|
105
|
+
|
|
106
|
+
- id: "CLT-SKL-005"
|
|
107
|
+
category: skill_compromise
|
|
108
|
+
severity: critical
|
|
109
|
+
confidence: 0.95
|
|
110
|
+
pattern: "(?:\\uDB40[\\uDC00-\\uDC7F]){3,}"
|
|
111
|
+
match_on: content
|
|
112
|
+
case_insensitive: false
|
|
113
|
+
title: "Unicode Tag character smuggling (U+E0000..U+E007F) in skill content"
|
|
114
|
+
expires_at: null
|
|
115
|
+
revoked: false
|
|
116
|
+
# Source: ATR-2026-00129 (pattern unchanged from upstream). Tag characters
|
|
117
|
+
# are invisible to humans but visible to LLMs; 3+ in sequence is an
|
|
118
|
+
# injection signature with no legitimate use.
|
|
119
|
+
|
|
120
|
+
- id: "CLT-SKL-006"
|
|
121
|
+
category: skill_compromise
|
|
122
|
+
severity: critical
|
|
123
|
+
confidence: 0.85
|
|
124
|
+
pattern: "(tar|zip|7z)\\s+[^\\n]*~/?\\.ssh|(find|ls|cat|strings)\\s+[^\\n]*(wallet\\.dat|seed\\.txt|mnemonic|keystore)[^\\n]*(\\||>|>>|curl|wget|fetch|POST)|sqlite3\\s+[^\\n]*(Cookies|Login\\s*Data|cookies\\.sqlite|places\\.sqlite)"
|
|
125
|
+
match_on: content
|
|
126
|
+
case_insensitive: true
|
|
127
|
+
title: "Compound skill-content exfiltration (wallet/browser/SSH archival)"
|
|
128
|
+
expires_at: null
|
|
129
|
+
revoked: false
|
|
130
|
+
# Adapted from ATR-2026-00149: condensed ATR's 13 detection conditions into
|
|
131
|
+
# one regex covering SSH archival, crypto wallet exfil, and browser DB dump;
|
|
132
|
+
# omits ATR's DNS-exfil, IMDS metadata, and env-file piping layers.
|
|
133
|
+
# Intentional layering with CLT-CRED-008 (command artifact): that rule catches
|
|
134
|
+
# the same SSH archival at shell execution time; this rule catches it in
|
|
135
|
+
# written skill/plugin content before it executes.
|
|
136
|
+
|
|
137
|
+
# CLT-SKL-007 intentionally omitted — dropped for FP risk during ATR curation.
|
|
138
|
+
|
|
139
|
+
- id: "CLT-SKL-008"
|
|
140
|
+
category: skill_compromise
|
|
141
|
+
severity: warning
|
|
142
|
+
confidence: 0.85
|
|
143
|
+
pattern: "(?:(?:always|must|shall|will|should)\\s+){1,3}(?:approve|accept|allow|grant|permit)\\b[^.\\n]{0,80}(?:without|regardless|even\\s+if|despite)\\s+(?:confirmation|permission|approval|consent|asking|checking|verification|user)"
|
|
144
|
+
match_on: content
|
|
145
|
+
case_insensitive: true
|
|
146
|
+
title: "Hidden override instruction in skill -- auto-approve all"
|
|
147
|
+
expires_at: null
|
|
148
|
+
revoked: false
|
|
149
|
+
# Adapted from ATR-2026-00163: added "will"/"should" modals and "despite" as
|
|
150
|
+
# an additional consent-bypass synonym; bounded modal repetition to {1,3}.
|
|
151
|
+
|
|
152
|
+
# ===========================================================================
|
|
153
|
+
# CONTEXT EXFILTRATION
|
|
154
|
+
# ===========================================================================
|
|
155
|
+
|
|
156
|
+
- id: "CLT-CTX-003"
|
|
157
|
+
category: context_exfiltration
|
|
158
|
+
severity: critical
|
|
159
|
+
confidence: 0.95
|
|
160
|
+
pattern: "-----BEGIN\\s+[A-Z ]+PRIVATE\\s+KEY-----[\\s\\S]{40,}-----END\\s+[A-Z ]+PRIVATE\\s+KEY-----"
|
|
161
|
+
match_on: content
|
|
162
|
+
title: "PEM private key block appearing in agent content"
|
|
163
|
+
expires_at: null
|
|
164
|
+
revoked: false
|
|
165
|
+
# Source: ATR-2026-00021 (pattern unchanged from upstream). Fires on Write/Edit
|
|
166
|
+
# content and session-start plugin scans (category context_exfiltration is
|
|
167
|
+
# pre-hook only; post-hook scanning is limited to prompt_injection rules).
|
|
168
|
+
# Covers RSA, EC, DSA, OPENSSH, ENCRYPTED variants.
|
|
169
|
+
|
|
170
|
+
# ===========================================================================
|
|
171
|
+
# SUPPLY CHAIN
|
|
172
|
+
# ===========================================================================
|
|
173
|
+
|
|
174
|
+
- id: "CLT-SUPPLY-002"
|
|
175
|
+
category: supply_chain
|
|
176
|
+
severity: warning
|
|
177
|
+
confidence: 0.95
|
|
178
|
+
pattern: "(?:filesytem|filsystem|file_sytem|flie_system|filessystem|filesystm|filsystm|filesysem)[-_](?:read|write|list|delete|search)"
|
|
179
|
+
match_on: content
|
|
180
|
+
case_insensitive: true
|
|
181
|
+
title: "Typosquatted filesystem tool name (targets MCP filesystem server)"
|
|
182
|
+
expires_at: null
|
|
183
|
+
revoked: false
|
|
184
|
+
# Adapted from ATR-2026-00060: extracted filesystem-server typo variants only;
|
|
185
|
+
# narrows ATR's broader MCP squatting rule to the
|
|
186
|
+
# @modelcontextprotocol/server-filesystem impersonation family.
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
# Command threat patterns for Sage
|
|
2
2
|
# Author: Gen Digital Inc.
|
|
3
3
|
# License: DRL-1.1 (see threats/LICENSE)
|
|
4
|
-
# Schema: id, category, severity, confidence,
|
|
4
|
+
# Schema: id, category, severity, confidence, pattern, match_on, title, expires_at, revoked, flags
|
|
5
5
|
|
|
6
6
|
# --- Pipe to shell (Remote Code Execution) ---
|
|
7
7
|
- id: "CLT-CMD-001"
|
|
8
8
|
category: tool
|
|
9
9
|
severity: critical
|
|
10
10
|
confidence: 0.95
|
|
11
|
-
action: block
|
|
12
11
|
pattern: "curl\\s[^|]*\\|\\s*(bash|sh|zsh|ksh|dash)"
|
|
13
12
|
match_on: command
|
|
14
13
|
title: "Remote code execution via curl pipe to shell"
|
|
@@ -19,7 +18,6 @@
|
|
|
19
18
|
category: tool
|
|
20
19
|
severity: critical
|
|
21
20
|
confidence: 0.95
|
|
22
|
-
action: block
|
|
23
21
|
pattern: "wget\\s[^|]*\\|\\s*(bash|sh|zsh|ksh|dash)"
|
|
24
22
|
match_on: command
|
|
25
23
|
title: "Remote code execution via wget pipe to shell"
|
|
@@ -31,8 +29,7 @@
|
|
|
31
29
|
category: tool
|
|
32
30
|
severity: critical
|
|
33
31
|
confidence: 0.90
|
|
34
|
-
|
|
35
|
-
pattern: "/dev/tcp/"
|
|
32
|
+
pattern: "\\b(bash|sh|zsh|ksh|dash)\\s+-i\\b[\\s\\S]{0,160}/dev/tcp/"
|
|
36
33
|
match_on: command
|
|
37
34
|
title: "Reverse shell via /dev/tcp"
|
|
38
35
|
expires_at: null
|
|
@@ -42,7 +39,6 @@
|
|
|
42
39
|
category: tool
|
|
43
40
|
severity: critical
|
|
44
41
|
confidence: 0.90
|
|
45
|
-
action: block
|
|
46
42
|
pattern: "\\bnc\\b.*\\s-e\\s"
|
|
47
43
|
match_on: command
|
|
48
44
|
title: "Reverse shell via netcat -e"
|
|
@@ -53,7 +49,6 @@
|
|
|
53
49
|
category: tool
|
|
54
50
|
severity: critical
|
|
55
51
|
confidence: 0.85
|
|
56
|
-
action: block
|
|
57
52
|
pattern: "bash\\s+-i\\s+>\\s*&\\s*/dev/"
|
|
58
53
|
match_on: command
|
|
59
54
|
title: "Interactive reverse shell via bash"
|
|
@@ -65,7 +60,6 @@
|
|
|
65
60
|
category: tool
|
|
66
61
|
severity: critical
|
|
67
62
|
confidence: 0.95
|
|
68
|
-
action: block
|
|
69
63
|
pattern: "\\brm\\s+(-[a-zA-Z]*f[a-zA-Z]*\\s+)?(-[a-zA-Z]*r[a-zA-Z]*\\s+)?/(\\s|$|[;&|*])|\\brm\\s+(-[a-zA-Z]*r[a-zA-Z]*\\s+)?(-[a-zA-Z]*f[a-zA-Z]*\\s+)?/(\\s|$|[;&|*])|\\brm\\s+-[a-zA-Z]*rf[a-zA-Z]*\\s+/(\\s|$|[;&|*])"
|
|
70
64
|
match_on: command
|
|
71
65
|
title: "Recursive forced deletion from root"
|
|
@@ -76,7 +70,6 @@
|
|
|
76
70
|
category: tool
|
|
77
71
|
severity: critical
|
|
78
72
|
confidence: 0.95
|
|
79
|
-
action: block
|
|
80
73
|
pattern: "\\bmkfs\\b"
|
|
81
74
|
match_on: command
|
|
82
75
|
title: "Filesystem format command"
|
|
@@ -85,9 +78,8 @@
|
|
|
85
78
|
|
|
86
79
|
- id: "CLT-CMD-008"
|
|
87
80
|
category: tool
|
|
88
|
-
severity:
|
|
81
|
+
severity: warning
|
|
89
82
|
confidence: 0.85
|
|
90
|
-
action: block
|
|
91
83
|
pattern: "\\bdd\\s+if=.*of=/dev/"
|
|
92
84
|
match_on: command
|
|
93
85
|
title: "Direct disk write via dd"
|
|
@@ -98,7 +90,6 @@
|
|
|
98
90
|
category: tool
|
|
99
91
|
severity: critical
|
|
100
92
|
confidence: 0.90
|
|
101
|
-
action: block
|
|
102
93
|
pattern: "\\bshred\\b"
|
|
103
94
|
match_on: command
|
|
104
95
|
title: "Secure file destruction via shred"
|
|
@@ -110,7 +101,6 @@
|
|
|
110
101
|
category: tool
|
|
111
102
|
severity: critical
|
|
112
103
|
confidence: 0.90
|
|
113
|
-
action: block
|
|
114
104
|
pattern: "(curl|wget)\\s[\\s\\S]*?(&&|;)\\s*chmod\\s+\\+x"
|
|
115
105
|
match_on: command
|
|
116
106
|
title: "Download and execute chain"
|
|
@@ -120,9 +110,8 @@
|
|
|
120
110
|
# --- Privilege escalation ---
|
|
121
111
|
- id: "CLT-CMD-011"
|
|
122
112
|
category: tool
|
|
123
|
-
severity:
|
|
124
|
-
confidence: 0.
|
|
125
|
-
action: require_approval
|
|
113
|
+
severity: warning
|
|
114
|
+
confidence: 0.60
|
|
126
115
|
pattern: "\\bchmod\\s+777\\b"
|
|
127
116
|
match_on: command
|
|
128
117
|
title: "Overly permissive file permissions"
|
|
@@ -131,9 +120,8 @@
|
|
|
131
120
|
|
|
132
121
|
- id: "CLT-CMD-012"
|
|
133
122
|
category: tool
|
|
134
|
-
severity:
|
|
135
|
-
confidence: 0.
|
|
136
|
-
action: require_approval
|
|
123
|
+
severity: warning
|
|
124
|
+
confidence: 0.60
|
|
137
125
|
pattern: "NOPASSWD"
|
|
138
126
|
match_on: command
|
|
139
127
|
title: "Passwordless sudo configuration"
|
|
@@ -143,9 +131,8 @@
|
|
|
143
131
|
# --- Data exfiltration ---
|
|
144
132
|
- id: "CLT-CMD-013"
|
|
145
133
|
category: network_egress
|
|
146
|
-
severity:
|
|
147
|
-
confidence: 0.
|
|
148
|
-
action: require_approval
|
|
134
|
+
severity: warning
|
|
135
|
+
confidence: 0.60
|
|
149
136
|
pattern: "curl\\s[^|;]*(-d|--data|--data-binary)\\s\\S*(/etc/passwd|/etc/shadow|\\.ssh/|id_rsa|credentials|secrets)"
|
|
150
137
|
match_on: command
|
|
151
138
|
title: "Possible data exfiltration of sensitive files"
|
|
@@ -157,7 +144,6 @@
|
|
|
157
144
|
category: tool
|
|
158
145
|
severity: critical
|
|
159
146
|
confidence: 0.95
|
|
160
|
-
action: block
|
|
161
147
|
pattern: "\\bsudo\\s+(curl|wget)\\s[^|]*\\|\\s*(bash|sh|zsh|ksh|dash)"
|
|
162
148
|
match_on: command
|
|
163
149
|
title: "Privileged pipe-to-shell (sudo curl/wget piped to shell)"
|
|
@@ -171,9 +157,8 @@
|
|
|
171
157
|
# bounded non-greedy quantifier to avoid catastrophic backtracking.
|
|
172
158
|
- id: "CLT-CMD-015"
|
|
173
159
|
category: tool
|
|
174
|
-
severity:
|
|
175
|
-
confidence: 0.
|
|
176
|
-
action: require_approval
|
|
160
|
+
severity: warning
|
|
161
|
+
confidence: 0.60
|
|
177
162
|
pattern: "python[3]?\\s+-c\\s+[\"'][\\s\\S]{0,2048}?(?:os\\.(?:system|popen|exec[lv]?[ep]?e?)|subprocess\\.(?:run|call|Popen|check_output|check_call|getoutput|getstatusoutput)|__import__)\\s*\\("
|
|
178
163
|
match_on: command
|
|
179
164
|
title: "Python one-liner invoking shell/exec/subprocess call"
|
|
@@ -185,7 +170,6 @@
|
|
|
185
170
|
category: tool
|
|
186
171
|
severity: critical
|
|
187
172
|
confidence: 0.90
|
|
188
|
-
action: block
|
|
189
173
|
pattern: "\\bbash\\s+<\\(\\s*(curl|wget)\\b"
|
|
190
174
|
match_on: command
|
|
191
175
|
title: "Process substitution executing remote content"
|
|
@@ -194,9 +178,8 @@
|
|
|
194
178
|
|
|
195
179
|
- id: "CLT-CMD-017"
|
|
196
180
|
category: tool
|
|
197
|
-
severity:
|
|
181
|
+
severity: warning
|
|
198
182
|
confidence: 0.85
|
|
199
|
-
action: block
|
|
200
183
|
pattern: "\\beval\\b[^;|]*\\b(curl|wget)\\b"
|
|
201
184
|
match_on: command
|
|
202
185
|
title: "Eval executing remote download command"
|
|
@@ -205,13 +188,12 @@
|
|
|
205
188
|
|
|
206
189
|
- id: "CLT-CMD-018"
|
|
207
190
|
category: tool
|
|
208
|
-
severity:
|
|
191
|
+
severity: warning
|
|
209
192
|
confidence: 0.85
|
|
210
|
-
action: block
|
|
211
193
|
# The lookarounds prevent matching short-option flags like `du -sh` or
|
|
212
194
|
# identifiers like `shell`/`bashrc`; only standalone command invocations
|
|
213
195
|
# (preceded by whitespace, `/`, etc.) are flagged.
|
|
214
|
-
pattern: "\\bxargs\\b[
|
|
196
|
+
pattern: "\\bxargs\\b[^|;\\r\\n]{0,400}(?:(?<![-\\w])(bash|sh)(?![-\\w])(?:\\s+-[\\w]*c\\b\\s+(?:\"(?!\\s*(?:head|cat|wc)\\b)[^\"\\r\\n]{0,240}(?:\\{\\}|\\$[@*]|\\$\\d)[^\"\\r\\n]{0,240}\"|'(?!\\s*(?:head|cat|wc)\\b)[^'\\r\\n]{0,240}(?:\\{\\}|\\$[@*]|\\$\\d)[^'\\r\\n]{0,240}')|(?!\\s+-[\\w]*c\\b))|(?<![-\\w])(curl|wget)(?![-\\w])[^|;\\r\\n]{0,400}(?:-d|--data|--data-binary|--upload-file|-T|--post-file|--post-data|--body-file)\\b)"
|
|
215
197
|
match_on: command
|
|
216
198
|
title: "xargs dispatching download or shell execution"
|
|
217
199
|
expires_at: null
|
|
@@ -219,9 +201,8 @@
|
|
|
219
201
|
|
|
220
202
|
- id: "CLT-CMD-019"
|
|
221
203
|
category: tool
|
|
222
|
-
severity:
|
|
204
|
+
severity: warning
|
|
223
205
|
confidence: 0.85
|
|
224
|
-
action: block
|
|
225
206
|
pattern: "\\bfind\\b[^|;]*-exec\\s+(bash|sh|curl|wget)\\b"
|
|
226
207
|
match_on: command
|
|
227
208
|
title: "find -exec executing shell or download commands"
|
|
@@ -231,9 +212,8 @@
|
|
|
231
212
|
# --- DNS exfiltration ---
|
|
232
213
|
- id: "CLT-CMD-020"
|
|
233
214
|
category: network_egress
|
|
234
|
-
severity:
|
|
215
|
+
severity: warning
|
|
235
216
|
confidence: 0.80
|
|
236
|
-
action: block
|
|
237
217
|
pattern: "\\b(nslookup|dig|host)\\b[^|;]*\\$\\([^)]+\\)\\.[a-zA-Z]"
|
|
238
218
|
match_on: command
|
|
239
219
|
title: "DNS exfiltration via command substitution as subdomain label"
|
|
@@ -242,9 +222,8 @@
|
|
|
242
222
|
|
|
243
223
|
- id: "CLT-CMD-021"
|
|
244
224
|
category: network_egress
|
|
245
|
-
severity:
|
|
225
|
+
severity: warning
|
|
246
226
|
confidence: 0.80
|
|
247
|
-
action: block
|
|
248
227
|
pattern: "\\b(nslookup|dig|host)\\b[^|;]*`[^`]+`\\.[a-zA-Z]"
|
|
249
228
|
match_on: command
|
|
250
229
|
title: "DNS exfiltration via backtick substitution as subdomain label"
|
|
@@ -254,9 +233,8 @@
|
|
|
254
233
|
# --- Loop-based indirect execution ---
|
|
255
234
|
- id: "CLT-CMD-022"
|
|
256
235
|
category: tool
|
|
257
|
-
severity:
|
|
236
|
+
severity: warning
|
|
258
237
|
confidence: 0.80
|
|
259
|
-
action: block
|
|
260
238
|
pattern: "\\b(while|for)\\b[^;]*;\\s*do[^;]*(\\b(bash|sh)\\s+-c\\b|\\b(curl|wget)\\b[^;]*\\|\\s*(?:sudo\\s+)?(?:env\\s+)?(?:[^\\s\"']*[\\\\/])?(bash|sh|zsh|ksh|dash)\\b|\\b(curl|wget)\\b[^;]*(?:(-d|--data|--data-binary)\\s+['\\\"]?@\\S+|(--upload-file|-T)\\s+['\\\"]?\\S+))"
|
|
261
239
|
match_on: command
|
|
262
240
|
title: "Loop executing shell or download commands"
|
|
@@ -270,7 +248,6 @@
|
|
|
270
248
|
category: tool
|
|
271
249
|
severity: critical
|
|
272
250
|
confidence: 0.90
|
|
273
|
-
action: block
|
|
274
251
|
pattern: "python[23]?\\s+-c.*socket.*connect.*(\\/bin\\/zsh|\\/bin\\/sh|\\/bin\\/bash)"
|
|
275
252
|
match_on: command
|
|
276
253
|
title: "Python reverse shell via socket"
|
|
@@ -282,7 +259,6 @@
|
|
|
282
259
|
category: tool
|
|
283
260
|
severity: critical
|
|
284
261
|
confidence: 0.90
|
|
285
|
-
action: block
|
|
286
262
|
pattern: "ruby\\s+-e.*TCPSocket.*exec.*(\\/bin\\/zsh|\\/bin\\/sh)"
|
|
287
263
|
match_on: command
|
|
288
264
|
title: "Ruby reverse shell via TCPSocket"
|
|
@@ -294,7 +270,6 @@
|
|
|
294
270
|
category: tool
|
|
295
271
|
severity: critical
|
|
296
272
|
confidence: 0.90
|
|
297
|
-
action: block
|
|
298
273
|
pattern: "\\bzsh\\s+-c\\b.*\\b(exec|socket|/dev/tcp)\\b"
|
|
299
274
|
match_on: command
|
|
300
275
|
title: "Zsh reverse shell pattern"
|
|
@@ -306,7 +281,6 @@
|
|
|
306
281
|
category: tool
|
|
307
282
|
severity: critical
|
|
308
283
|
confidence: 0.95
|
|
309
|
-
action: block
|
|
310
284
|
pattern: "\\brm\\s+(-[a-zA-Z]+\\s+)*-[a-zA-Z]*[rR][a-zA-Z]*(\\s+-[a-zA-Z]+)*\\s+/(home|Users|etc|usr|var|boot|bin|sbin|lib|lib64|opt|root|System|Applications|Library|Volumes|private|mnt)\\b/?(\\s|$|[;&|])"
|
|
311
285
|
match_on: command
|
|
312
286
|
title: "Recursive deletion of critical system directory"
|
|
@@ -316,9 +290,8 @@
|
|
|
316
290
|
# --- Deletion of .env files ---
|
|
317
291
|
- id: "CLT-CMD-027"
|
|
318
292
|
category: tool
|
|
319
|
-
severity:
|
|
320
|
-
confidence: 0.
|
|
321
|
-
action: require_approval
|
|
293
|
+
severity: warning
|
|
294
|
+
confidence: 0.60
|
|
322
295
|
pattern: "\\brm\\s+(-{1,2}[\\w-]+(=\\S+)?\\s+)*(\\S+[\\\\/])?\\.env(?!\\S*\\.(example|sample|template|dist)\\b)(\\.(local|production|prod|staging|stage|development|dev|test))?\\b"
|
|
323
296
|
match_on: command
|
|
324
297
|
title: "Deletion of .env file"
|
|
@@ -328,9 +301,8 @@
|
|
|
328
301
|
# --- Deletion of database files ---
|
|
329
302
|
- id: "CLT-CMD-028"
|
|
330
303
|
category: tool
|
|
331
|
-
severity:
|
|
332
|
-
confidence: 0.
|
|
333
|
-
action: require_approval
|
|
304
|
+
severity: warning
|
|
305
|
+
confidence: 0.60
|
|
334
306
|
pattern: "\\brm\\s+(-{1,2}[\\w-]+(=\\S+)?\\s+)*\\S+\\.(db|sqlite|sqlite3)\\b"
|
|
335
307
|
match_on: command
|
|
336
308
|
title: "Deletion of database file"
|
|
@@ -340,9 +312,8 @@
|
|
|
340
312
|
# --- Deletion of .git directory ---
|
|
341
313
|
- id: "CLT-CMD-029"
|
|
342
314
|
category: tool
|
|
343
|
-
severity:
|
|
344
|
-
confidence: 0.
|
|
345
|
-
action: require_approval
|
|
315
|
+
severity: warning
|
|
316
|
+
confidence: 0.60
|
|
346
317
|
pattern: "\\b(rm|del|rmdir|rd|Remove-Item|unlink)\\b.*(\\s|[\\\\/])\\.git(\\s|[\\\\/]|$)"
|
|
347
318
|
case_insensitive: true
|
|
348
319
|
match_on: command
|