shield-harness 0.4.0 → 0.5.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/.claude/hooks/lib/automode-detect.js +184 -0
- package/.claude/hooks/sh-config-guard.js +49 -1
- package/.claude/hooks/sh-session-start.js +42 -0
- package/.claude/permissions-spec.json +6 -1
- package/README.ja.md +39 -26
- package/README.md +40 -27
- package/package.json +5 -2
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// automode-detect.js — Claude Code Auto Mode detection & danger assessment
|
|
3
|
+
// Spec: Phase 7 ADR-038 (.reference/PHASE7_8_AUTO_MODE_SELF_EVOLUTION_PLAN.md)
|
|
4
|
+
// Purpose: Detect Auto Mode configuration and classify danger level
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
const fs = require("fs");
|
|
8
|
+
const path = require("path");
|
|
9
|
+
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Constants
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
const SETTINGS_LOCAL = path.join(".claude", "settings.local.json");
|
|
15
|
+
const SETTINGS_MAIN = path.join(".claude", "settings.json");
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Protections lost when autoMode.soft_deny is configured.
|
|
19
|
+
* A single soft_deny entry disables ALL classifier default protections.
|
|
20
|
+
*/
|
|
21
|
+
const LOST_PROTECTIONS = [
|
|
22
|
+
"Default force-push prevention (git push --force)",
|
|
23
|
+
"Default destructive command blocking (rm -rf, format)",
|
|
24
|
+
"Default credential access prevention (~/.ssh, ~/.aws)",
|
|
25
|
+
"Default network isolation (curl|bash, data exfiltration)",
|
|
26
|
+
"Default file system protection (system files modification)",
|
|
27
|
+
"Default package execution control (npm install, npx)",
|
|
28
|
+
"Classifier-based safety judgments for all unlisted tools",
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Utility functions
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Read autoMode section from a settings JSON file.
|
|
37
|
+
* fail-safe: returns null on any error (file missing, parse error, no autoMode).
|
|
38
|
+
* @param {string} filePath - Path to settings JSON file
|
|
39
|
+
* @returns {{ soft_deny: string[], soft_allow: string[], environment: string|null }|null}
|
|
40
|
+
*/
|
|
41
|
+
function readSettingsFile(filePath) {
|
|
42
|
+
try {
|
|
43
|
+
if (!fs.existsSync(filePath)) return null;
|
|
44
|
+
const content = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
45
|
+
const autoMode = content.autoMode;
|
|
46
|
+
if (!autoMode || typeof autoMode !== "object") return null;
|
|
47
|
+
return {
|
|
48
|
+
soft_deny: Array.isArray(autoMode.soft_deny) ? autoMode.soft_deny : [],
|
|
49
|
+
soft_allow: Array.isArray(autoMode.soft_allow) ? autoMode.soft_allow : [],
|
|
50
|
+
environment:
|
|
51
|
+
typeof autoMode.environment === "string" ? autoMode.environment : null,
|
|
52
|
+
};
|
|
53
|
+
} catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Classify danger level based on soft_deny and soft_allow counts.
|
|
60
|
+
* @param {number} softDenyCount
|
|
61
|
+
* @param {number} softAllowCount
|
|
62
|
+
* @returns {"safe"|"warn"|"critical"}
|
|
63
|
+
*/
|
|
64
|
+
function classifyDangerLevel(softDenyCount, softAllowCount) {
|
|
65
|
+
if (softDenyCount > 0) return "critical";
|
|
66
|
+
if (softAllowCount > 0) return "warn";
|
|
67
|
+
return "safe";
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// Main detection function
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Detect Auto Mode configuration and assess danger level.
|
|
76
|
+
* Reads settings.local.json (priority) and settings.json, merges results.
|
|
77
|
+
* fail-safe: never throws, returns safe defaults on any error.
|
|
78
|
+
*
|
|
79
|
+
* @returns {{
|
|
80
|
+
* detected: boolean,
|
|
81
|
+
* danger_level: "safe"|"warn"|"critical",
|
|
82
|
+
* reason: string,
|
|
83
|
+
* soft_deny_count: number,
|
|
84
|
+
* soft_allow_count: number,
|
|
85
|
+
* has_environment: boolean,
|
|
86
|
+
* environment_snippet: string|null,
|
|
87
|
+
* danger_items: string[],
|
|
88
|
+
* source: "settings_local"|"settings"|"both"|"none",
|
|
89
|
+
* detected_at: string
|
|
90
|
+
* }}
|
|
91
|
+
*/
|
|
92
|
+
function detectAutoMode() {
|
|
93
|
+
const detected_at = new Date().toISOString();
|
|
94
|
+
const base = {
|
|
95
|
+
detected: false,
|
|
96
|
+
danger_level: "safe",
|
|
97
|
+
reason: "not_configured",
|
|
98
|
+
soft_deny_count: 0,
|
|
99
|
+
soft_allow_count: 0,
|
|
100
|
+
has_environment: false,
|
|
101
|
+
environment_snippet: null,
|
|
102
|
+
danger_items: [],
|
|
103
|
+
source: "none",
|
|
104
|
+
detected_at,
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
const localResult = readSettingsFile(SETTINGS_LOCAL);
|
|
109
|
+
const mainResult = readSettingsFile(SETTINGS_MAIN);
|
|
110
|
+
|
|
111
|
+
// No autoMode in either file
|
|
112
|
+
if (!localResult && !mainResult) {
|
|
113
|
+
return base;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Determine source
|
|
117
|
+
const source =
|
|
118
|
+
localResult && mainResult
|
|
119
|
+
? "both"
|
|
120
|
+
: localResult
|
|
121
|
+
? "settings_local"
|
|
122
|
+
: "settings";
|
|
123
|
+
|
|
124
|
+
// Merge soft_deny and soft_allow from both files (deduplicate)
|
|
125
|
+
const softDeny = [
|
|
126
|
+
...new Set([
|
|
127
|
+
...(localResult ? localResult.soft_deny : []),
|
|
128
|
+
...(mainResult ? mainResult.soft_deny : []),
|
|
129
|
+
]),
|
|
130
|
+
];
|
|
131
|
+
const softAllow = [
|
|
132
|
+
...new Set([
|
|
133
|
+
...(localResult ? localResult.soft_allow : []),
|
|
134
|
+
...(mainResult ? mainResult.soft_allow : []),
|
|
135
|
+
]),
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
// Environment: local overrides main
|
|
139
|
+
const environment =
|
|
140
|
+
(localResult && localResult.environment) ||
|
|
141
|
+
(mainResult && mainResult.environment) ||
|
|
142
|
+
null;
|
|
143
|
+
|
|
144
|
+
const dangerLevel = classifyDangerLevel(softDeny.length, softAllow.length);
|
|
145
|
+
|
|
146
|
+
// Determine reason code
|
|
147
|
+
let reason = "configured_safe";
|
|
148
|
+
if (softDeny.length > 0 && softAllow.length > 0) {
|
|
149
|
+
reason = "both_present";
|
|
150
|
+
} else if (softDeny.length > 0) {
|
|
151
|
+
reason = "soft_deny_present";
|
|
152
|
+
} else if (softAllow.length > 0) {
|
|
153
|
+
reason = "soft_allow_only";
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
detected: true,
|
|
158
|
+
danger_level: dangerLevel,
|
|
159
|
+
reason,
|
|
160
|
+
soft_deny_count: softDeny.length,
|
|
161
|
+
soft_allow_count: softAllow.length,
|
|
162
|
+
has_environment: environment !== null,
|
|
163
|
+
environment_snippet: environment ? environment.slice(0, 80) : null,
|
|
164
|
+
danger_items: dangerLevel === "critical" ? [...LOST_PROTECTIONS] : [],
|
|
165
|
+
source,
|
|
166
|
+
detected_at,
|
|
167
|
+
};
|
|
168
|
+
} catch {
|
|
169
|
+
return { ...base, reason: "read_error" };
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
// Exports
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
|
|
177
|
+
module.exports = {
|
|
178
|
+
detectAutoMode,
|
|
179
|
+
classifyDangerLevel,
|
|
180
|
+
readSettingsFile,
|
|
181
|
+
LOST_PROTECTIONS,
|
|
182
|
+
SETTINGS_LOCAL,
|
|
183
|
+
SETTINGS_MAIN,
|
|
184
|
+
};
|
|
@@ -14,11 +14,15 @@ const {
|
|
|
14
14
|
sha256,
|
|
15
15
|
appendEvidence,
|
|
16
16
|
} = require("./lib/sh-utils");
|
|
17
|
+
const {
|
|
18
|
+
readSettingsFile: readAutoModeSection,
|
|
19
|
+
} = require("./lib/automode-detect");
|
|
17
20
|
|
|
18
21
|
const HOOK_NAME = "sh-config-guard";
|
|
19
22
|
const SETTINGS_FILE = path.join(".claude", "settings.json");
|
|
20
23
|
const CONFIG_HASH_FILE = path.join(".claude", "logs", "config-hash.json");
|
|
21
24
|
const POLICIES_DIR = path.join(".claude", "policies");
|
|
25
|
+
const SETTINGS_LOCAL = path.join(".claude", "settings.local.json");
|
|
22
26
|
|
|
23
27
|
// ---------------------------------------------------------------------------
|
|
24
28
|
// Config Analysis
|
|
@@ -171,7 +175,7 @@ function extractSecurityFields(settings) {
|
|
|
171
175
|
}
|
|
172
176
|
}
|
|
173
177
|
|
|
174
|
-
|
|
178
|
+
const result = {
|
|
175
179
|
deny_rules: denyRules,
|
|
176
180
|
hook_count: hookCount,
|
|
177
181
|
hook_events: hookEvents,
|
|
@@ -184,7 +188,33 @@ function extractSecurityFields(settings) {
|
|
|
184
188
|
disableAllHooks: Boolean(settings.disableAllHooks),
|
|
185
189
|
policy_hashes: extractPolicyHashes(),
|
|
186
190
|
policy_metrics: extractPolicyMetrics(),
|
|
191
|
+
soft_deny_count: 0,
|
|
192
|
+
soft_allow_count: 0,
|
|
187
193
|
};
|
|
194
|
+
|
|
195
|
+
// Auto Mode: read autoMode from both settings files (Phase 7, ADR-038)
|
|
196
|
+
try {
|
|
197
|
+
const mainAutoMode = readAutoModeSection(SETTINGS_FILE);
|
|
198
|
+
const localAutoMode = readAutoModeSection(SETTINGS_LOCAL);
|
|
199
|
+
const softDeny = [
|
|
200
|
+
...new Set([
|
|
201
|
+
...(mainAutoMode ? mainAutoMode.soft_deny : []),
|
|
202
|
+
...(localAutoMode ? localAutoMode.soft_deny : []),
|
|
203
|
+
]),
|
|
204
|
+
];
|
|
205
|
+
const softAllow = [
|
|
206
|
+
...new Set([
|
|
207
|
+
...(mainAutoMode ? mainAutoMode.soft_allow : []),
|
|
208
|
+
...(localAutoMode ? localAutoMode.soft_allow : []),
|
|
209
|
+
]),
|
|
210
|
+
];
|
|
211
|
+
result.soft_deny_count = softDeny.length;
|
|
212
|
+
result.soft_allow_count = softAllow.length;
|
|
213
|
+
} catch {
|
|
214
|
+
// Auto Mode detection failure is non-blocking for config-guard
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return result;
|
|
188
218
|
}
|
|
189
219
|
|
|
190
220
|
/**
|
|
@@ -286,6 +316,24 @@ function detectDangerousMutations(stored, current) {
|
|
|
286
316
|
}
|
|
287
317
|
}
|
|
288
318
|
|
|
319
|
+
// Check 7: Auto Mode soft_deny addition (CRITICAL — all default protections lost)
|
|
320
|
+
const storedSoftDeny = stored.soft_deny_count || 0;
|
|
321
|
+
const currentSoftDeny = current.soft_deny_count || 0;
|
|
322
|
+
if (currentSoftDeny > storedSoftDeny) {
|
|
323
|
+
reasons.push(
|
|
324
|
+
`Auto Mode soft_deny added (${storedSoftDeny} → ${currentSoftDeny}) — ALL default protections would be lost`,
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Check 8: Auto Mode soft_allow expansion
|
|
329
|
+
const storedSoftAllow = stored.soft_allow_count || 0;
|
|
330
|
+
const currentSoftAllow = current.soft_allow_count || 0;
|
|
331
|
+
if (currentSoftAllow > storedSoftAllow) {
|
|
332
|
+
reasons.push(
|
|
333
|
+
`Auto Mode soft_allow expanded (${storedSoftAllow} → ${currentSoftAllow}) — additional tools auto-approved`,
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
289
337
|
return {
|
|
290
338
|
blocked: reasons.length > 0,
|
|
291
339
|
reasons,
|
|
@@ -18,6 +18,7 @@ const {
|
|
|
18
18
|
const { detectOpenShell } = require("./lib/openshell-detect");
|
|
19
19
|
const { checkPolicyCompatibility } = require("./lib/policy-compat");
|
|
20
20
|
const { checkPolicyDrift } = require("./lib/policy-drift");
|
|
21
|
+
const { detectAutoMode } = require("./lib/automode-detect");
|
|
21
22
|
|
|
22
23
|
const HOOK_NAME = "sh-session-start";
|
|
23
24
|
const CLAUDE_MD = "CLAUDE.md";
|
|
@@ -263,6 +264,39 @@ try {
|
|
|
263
264
|
}
|
|
264
265
|
}
|
|
265
266
|
|
|
267
|
+
// 2f: Auto Mode detection (Phase 7, ADR-038)
|
|
268
|
+
let autoModeResult = null;
|
|
269
|
+
try {
|
|
270
|
+
autoModeResult = detectAutoMode();
|
|
271
|
+
session.auto_mode = autoModeResult;
|
|
272
|
+
writeSession(session);
|
|
273
|
+
|
|
274
|
+
if (autoModeResult.danger_level === "critical") {
|
|
275
|
+
contextParts.push(
|
|
276
|
+
`[auto-mode] CRITICAL: Auto Mode soft_deny detected (${autoModeResult.soft_deny_count} rules) — ALL default protections lost`,
|
|
277
|
+
);
|
|
278
|
+
for (const item of autoModeResult.danger_items.slice(0, 3)) {
|
|
279
|
+
contextParts.push(`[auto-mode] Lost: ${item}`);
|
|
280
|
+
}
|
|
281
|
+
if (autoModeResult.danger_items.length > 3) {
|
|
282
|
+
contextParts.push(
|
|
283
|
+
`[auto-mode] ... and ${autoModeResult.danger_items.length - 3} more protections lost`,
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
} else if (autoModeResult.danger_level === "warn") {
|
|
287
|
+
contextParts.push(
|
|
288
|
+
`[auto-mode] WARNING: Auto Mode soft_allow detected — ${autoModeResult.soft_allow_count} rules auto-approved`,
|
|
289
|
+
);
|
|
290
|
+
} else if (autoModeResult.detected) {
|
|
291
|
+
contextParts.push("[auto-mode] Auto Mode configured (safe)");
|
|
292
|
+
} else {
|
|
293
|
+
contextParts.push("[auto-mode] Auto Mode: not configured");
|
|
294
|
+
}
|
|
295
|
+
} catch {
|
|
296
|
+
// Auto Mode detection failure is non-blocking
|
|
297
|
+
contextParts.push("[auto-mode] Auto Mode detection error (non-blocking)");
|
|
298
|
+
}
|
|
299
|
+
|
|
266
300
|
// --- Module 3: Version Check (§5.1.4) ---
|
|
267
301
|
// Store baseline hashes for instructions monitoring
|
|
268
302
|
const hashes = {};
|
|
@@ -314,6 +348,14 @@ try {
|
|
|
314
348
|
: 0,
|
|
315
349
|
}
|
|
316
350
|
: null,
|
|
351
|
+
auto_mode: autoModeResult
|
|
352
|
+
? {
|
|
353
|
+
detected: autoModeResult.detected,
|
|
354
|
+
danger_level: autoModeResult.danger_level,
|
|
355
|
+
soft_deny_count: autoModeResult.soft_deny_count,
|
|
356
|
+
soft_allow_count: autoModeResult.soft_allow_count,
|
|
357
|
+
}
|
|
358
|
+
: null,
|
|
317
359
|
policy_compat: policyCompat
|
|
318
360
|
? {
|
|
319
361
|
compatible: policyCompat.compatible,
|
|
@@ -85,6 +85,11 @@
|
|
|
85
85
|
"rationale": "Local settings protection",
|
|
86
86
|
"threat_id": "T-03"
|
|
87
87
|
},
|
|
88
|
+
{
|
|
89
|
+
"rule": "Edit(.claude/settings.local.json)",
|
|
90
|
+
"rationale": "Local settings protection — Auto Mode injection prevention (Phase 7, ADR-038)",
|
|
91
|
+
"threat_id": "T-03"
|
|
92
|
+
},
|
|
88
93
|
{
|
|
89
94
|
"rule": "Write(.claude/permissions-spec.json)",
|
|
90
95
|
"rationale": "Permissions SoT self-protection",
|
|
@@ -443,7 +448,7 @@
|
|
|
443
448
|
]
|
|
444
449
|
},
|
|
445
450
|
"expected_counts": {
|
|
446
|
-
"deny":
|
|
451
|
+
"deny": 44,
|
|
447
452
|
"ask": 4,
|
|
448
453
|
"allow": 49
|
|
449
454
|
}
|
package/README.ja.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
> フック駆動の自動判定で安全な自律開発を実現
|
|
8
8
|
|
|
9
|
-
> **v0.
|
|
9
|
+
> **v0.5.0**: 22 フック、4 層防御(L1 権限 + L2 フック + L3 サンドボックス + L3b OpenShell)、426 テスト(OWASP AITG 攻撃シミュレーション 108 テスト + Auto Mode 防御テスト 35 テスト含む)。
|
|
10
10
|
|
|
11
11
|
[](README.md)
|
|
12
12
|
[](#)
|
|
@@ -52,30 +52,30 @@ npx shield-harness init [--profile minimal|standard|strict]
|
|
|
52
52
|
|
|
53
53
|
## フックカタログ
|
|
54
54
|
|
|
55
|
-
| # | フック | イベント | 責務
|
|
56
|
-
| --- | ---------------- | --------------------- |
|
|
57
|
-
| 1 | permission | PreToolUse | ツール使用の 4 カテゴリ分類
|
|
58
|
-
| 2 | gate | PreToolUse | Bash コマンドの 7 攻撃ベクトル検査
|
|
59
|
-
| 3 | injection-guard | PreToolUse | 9 カテゴリ 50+ パターンのインジェクション検出
|
|
60
|
-
| 4 | data-boundary | PreToolUse | 本番データ境界 + 管轄追跡
|
|
61
|
-
| 5 | quiet-inject | PreToolUse | quiet フラグ自動注入
|
|
62
|
-
| 6 | evidence | PostToolUse | SHA-256 ハッシュチェーン証跡
|
|
63
|
-
| 7 | output-control | PostToolUse | 出力トランケーション + トークン予算
|
|
64
|
-
| 8 | dep-audit | PostToolUse | パッケージインストール検出
|
|
65
|
-
| 9 | lint-on-save | PostToolUse | 自動 lint 実行
|
|
66
|
-
| 10 | session-start | SessionStart | セッション初期化 + 整合性ベースライン
|
|
67
|
-
| 11 | session-end | SessionEnd | クリーンアップ + 統計
|
|
68
|
-
| 12 | circuit-breaker | Stop | リトライ上限 (3 回)
|
|
69
|
-
| 13 | config-guard | ConfigChange | 設定変更の監視 + OpenShell ポリシーファイル保護 |
|
|
70
|
-
| 14 | user-prompt | UserPromptSubmit | ユーザー入力のインジェクション検査
|
|
71
|
-
| 15 | permission-learn | PermissionRequest | 権限学習ガード
|
|
72
|
-
| 16 | elicitation | Elicitation | フィッシング + スコープガード
|
|
73
|
-
| 17 | subagent | SubagentStart | サブエージェント予算制約 (25%)
|
|
74
|
-
| 18 | instructions | InstructionsLoaded | ルールファイル整合性監視
|
|
75
|
-
| 19 | precompact | PreCompact | コンパクション前バックアップ
|
|
76
|
-
| 20 | postcompact | PostCompact | コンパクション後復元 + 検証
|
|
77
|
-
| 21 | worktree | WorktreeCreate/Remove | セキュリティ伝播 + 証跡マージ
|
|
78
|
-
| 22 | task-gate | TaskCompleted | テストゲート
|
|
55
|
+
| # | フック | イベント | 責務 |
|
|
56
|
+
| --- | ---------------- | --------------------- | ---------------------------------------------------------------- |
|
|
57
|
+
| 1 | permission | PreToolUse | ツール使用の 4 カテゴリ分類 |
|
|
58
|
+
| 2 | gate | PreToolUse | Bash コマンドの 7 攻撃ベクトル検査 |
|
|
59
|
+
| 3 | injection-guard | PreToolUse | 9 カテゴリ 50+ パターンのインジェクション検出 |
|
|
60
|
+
| 4 | data-boundary | PreToolUse | 本番データ境界 + 管轄追跡 |
|
|
61
|
+
| 5 | quiet-inject | PreToolUse | quiet フラグ自動注入 |
|
|
62
|
+
| 6 | evidence | PostToolUse | SHA-256 ハッシュチェーン証跡 |
|
|
63
|
+
| 7 | output-control | PostToolUse | 出力トランケーション + トークン予算 |
|
|
64
|
+
| 8 | dep-audit | PostToolUse | パッケージインストール検出 |
|
|
65
|
+
| 9 | lint-on-save | PostToolUse | 自動 lint 実行 |
|
|
66
|
+
| 10 | session-start | SessionStart | セッション初期化 + 整合性ベースライン |
|
|
67
|
+
| 11 | session-end | SessionEnd | クリーンアップ + 統計 |
|
|
68
|
+
| 12 | circuit-breaker | Stop | リトライ上限 (3 回) |
|
|
69
|
+
| 13 | config-guard | ConfigChange | 設定変更の監視 + OpenShell ポリシーファイル保護 + Auto Mode 保護 |
|
|
70
|
+
| 14 | user-prompt | UserPromptSubmit | ユーザー入力のインジェクション検査 |
|
|
71
|
+
| 15 | permission-learn | PermissionRequest | 権限学習ガード |
|
|
72
|
+
| 16 | elicitation | Elicitation | フィッシング + スコープガード |
|
|
73
|
+
| 17 | subagent | SubagentStart | サブエージェント予算制約 (25%) |
|
|
74
|
+
| 18 | instructions | InstructionsLoaded | ルールファイル整合性監視 |
|
|
75
|
+
| 19 | precompact | PreCompact | コンパクション前バックアップ |
|
|
76
|
+
| 20 | postcompact | PostCompact | コンパクション後復元 + 検証 |
|
|
77
|
+
| 21 | worktree | WorktreeCreate/Remove | セキュリティ伝播 + 証跡マージ |
|
|
78
|
+
| 22 | task-gate | TaskCompleted | テストゲート |
|
|
79
79
|
|
|
80
80
|
## パイプライン
|
|
81
81
|
|
|
@@ -189,7 +189,7 @@ OpenShell なしの場合、Shield Harness は Layer 1-2 防御にフォール
|
|
|
189
189
|
## テスト
|
|
190
190
|
|
|
191
191
|
```bash
|
|
192
|
-
# 全テスト実行(
|
|
192
|
+
# 全テスト実行(426 テスト、攻撃シミュレーション含む)
|
|
193
193
|
npm test
|
|
194
194
|
|
|
195
195
|
# 攻撃シミュレーションテストのみ実行
|
|
@@ -204,6 +204,19 @@ node --test tests/attack-sim-*.test.js
|
|
|
204
204
|
| attack-sim-agentic-limits | AITG-APP-06: Agentic Behavior Limits | 18 |
|
|
205
205
|
| attack-sim-sandbox-escape | NVIDIA 3-axis: Sandbox Escape | 15 |
|
|
206
206
|
| attack-sim-defense-chain | SAIF: Defense-in-depth Chain | 12 |
|
|
207
|
+
| attack-sim-automode-bypass | Auto Mode: soft_deny/soft_allow bypass | 15 |
|
|
208
|
+
|
|
209
|
+
## Auto Mode 対応 (v0.5.0)
|
|
210
|
+
|
|
211
|
+
Shield Harness はセッション開始時に Claude Code の Auto Mode(Research Preview)設定を検知し、危険な設定を防御します:
|
|
212
|
+
|
|
213
|
+
| 設定 | リスク | Shield Harness の対応 |
|
|
214
|
+
| ---------------------- | ------------------------------------------------------- | ------------------------------------------------------------------- |
|
|
215
|
+
| `autoMode.soft_deny` | **CRITICAL** — 分類器のデフォルト保護が全て無効化される | config-guard が追加をブロック、session-start が CRITICAL 警告を出力 |
|
|
216
|
+
| `autoMode.soft_allow` | WARN — 特定ツールが自動許可される | config-guard が拡大をブロック、session-start が WARNING を出力 |
|
|
217
|
+
| `autoMode.environment` | 安全 — 情報のみ | 検知してセッションに記録 |
|
|
218
|
+
|
|
219
|
+
既存の全フック(PreToolUse, PostToolUse)は Auto Mode でも通常通り発火します。`permissions.deny` ルールは絶対的に維持されます。
|
|
207
220
|
|
|
208
221
|
## チャンネル連携
|
|
209
222
|
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
**Hook-driven auto-defense security harness for Claude Code**
|
|
6
6
|
|
|
7
|
-
> **v0.
|
|
7
|
+
> **v0.5.0**: 22 hooks, 4-layer defense (L1 Permissions + L2 Hooks + L3 Sandbox + L3b OpenShell), 426 tests including 108 OWASP AITG attack simulations + 35 Auto Mode defense tests.
|
|
8
8
|
|
|
9
9
|
[](#)
|
|
10
10
|
[](README.ja.md)
|
|
@@ -50,30 +50,30 @@ npx shield-harness init [--profile minimal|standard|strict]
|
|
|
50
50
|
|
|
51
51
|
## Hook Catalog
|
|
52
52
|
|
|
53
|
-
| # | Hook | Event | Responsibility
|
|
54
|
-
| --- | ---------------- | --------------------- |
|
|
55
|
-
| 1 | permission | PreToolUse | 4-category tool usage classification
|
|
56
|
-
| 2 | gate | PreToolUse | 7 attack vector inspection for Bash commands
|
|
57
|
-
| 3 | injection-guard | PreToolUse | 9-category 50+ pattern injection detection
|
|
58
|
-
| 4 | data-boundary | PreToolUse | Production data boundary + jurisdiction tracking
|
|
59
|
-
| 5 | quiet-inject | PreToolUse | Auto-inject quiet flags
|
|
60
|
-
| 6 | evidence | PostToolUse | SHA-256 hash chain evidence
|
|
61
|
-
| 7 | output-control | PostToolUse | Output truncation + token budget
|
|
62
|
-
| 8 | dep-audit | PostToolUse | Package install detection
|
|
63
|
-
| 9 | lint-on-save | PostToolUse | Auto lint execution
|
|
64
|
-
| 10 | session-start | SessionStart | Session init + integrity baseline
|
|
65
|
-
| 11 | session-end | SessionEnd | Cleanup + statistics
|
|
66
|
-
| 12 | circuit-breaker | Stop | Retry limit (3 attempts)
|
|
67
|
-
| 13 | config-guard | ConfigChange | Settings change monitoring + OpenShell policy file protection |
|
|
68
|
-
| 14 | user-prompt | UserPromptSubmit | User input injection scanning
|
|
69
|
-
| 15 | permission-learn | PermissionRequest | Permission learning guard
|
|
70
|
-
| 16 | elicitation | Elicitation | Phishing + scope guard
|
|
71
|
-
| 17 | subagent | SubagentStart | Subagent budget constraint (25%)
|
|
72
|
-
| 18 | instructions | InstructionsLoaded | Rule file integrity monitoring
|
|
73
|
-
| 19 | precompact | PreCompact | Pre-compaction backup
|
|
74
|
-
| 20 | postcompact | PostCompact | Post-compaction restore + verify
|
|
75
|
-
| 21 | worktree | WorktreeCreate/Remove | Security propagation + evidence merge
|
|
76
|
-
| 22 | task-gate | TaskCompleted | Test gate
|
|
53
|
+
| # | Hook | Event | Responsibility |
|
|
54
|
+
| --- | ---------------- | --------------------- | ------------------------------------------------------------------------------------ |
|
|
55
|
+
| 1 | permission | PreToolUse | 4-category tool usage classification |
|
|
56
|
+
| 2 | gate | PreToolUse | 7 attack vector inspection for Bash commands |
|
|
57
|
+
| 3 | injection-guard | PreToolUse | 9-category 50+ pattern injection detection |
|
|
58
|
+
| 4 | data-boundary | PreToolUse | Production data boundary + jurisdiction tracking |
|
|
59
|
+
| 5 | quiet-inject | PreToolUse | Auto-inject quiet flags |
|
|
60
|
+
| 6 | evidence | PostToolUse | SHA-256 hash chain evidence |
|
|
61
|
+
| 7 | output-control | PostToolUse | Output truncation + token budget |
|
|
62
|
+
| 8 | dep-audit | PostToolUse | Package install detection |
|
|
63
|
+
| 9 | lint-on-save | PostToolUse | Auto lint execution |
|
|
64
|
+
| 10 | session-start | SessionStart | Session init + integrity baseline |
|
|
65
|
+
| 11 | session-end | SessionEnd | Cleanup + statistics |
|
|
66
|
+
| 12 | circuit-breaker | Stop | Retry limit (3 attempts) |
|
|
67
|
+
| 13 | config-guard | ConfigChange | Settings change monitoring + OpenShell policy file protection + Auto Mode protection |
|
|
68
|
+
| 14 | user-prompt | UserPromptSubmit | User input injection scanning |
|
|
69
|
+
| 15 | permission-learn | PermissionRequest | Permission learning guard |
|
|
70
|
+
| 16 | elicitation | Elicitation | Phishing + scope guard |
|
|
71
|
+
| 17 | subagent | SubagentStart | Subagent budget constraint (25%) |
|
|
72
|
+
| 18 | instructions | InstructionsLoaded | Rule file integrity monitoring |
|
|
73
|
+
| 19 | precompact | PreCompact | Pre-compaction backup |
|
|
74
|
+
| 20 | postcompact | PostCompact | Post-compaction restore + verify |
|
|
75
|
+
| 21 | worktree | WorktreeCreate/Remove | Security propagation + evidence merge |
|
|
76
|
+
| 22 | task-gate | TaskCompleted | Test gate |
|
|
77
77
|
|
|
78
78
|
## Pipeline
|
|
79
79
|
|
|
@@ -187,14 +187,14 @@ Policy files are protected by:
|
|
|
187
187
|
## Testing
|
|
188
188
|
|
|
189
189
|
```bash
|
|
190
|
-
# Run all tests (
|
|
190
|
+
# Run all tests (426 tests including attack simulations)
|
|
191
191
|
npm test
|
|
192
192
|
|
|
193
193
|
# Run attack simulation tests only
|
|
194
194
|
node --test tests/attack-sim-*.test.js
|
|
195
195
|
```
|
|
196
196
|
|
|
197
|
-
| Test Suite |
|
|
197
|
+
| Test Suite | Category | Tests |
|
|
198
198
|
| ----------------------------- | -------------------------------------- | ----- |
|
|
199
199
|
| attack-sim-prompt-injection | AITG-APP-01: Direct Prompt Injection | 25 |
|
|
200
200
|
| attack-sim-indirect-injection | AITG-APP-02: Indirect Prompt Injection | 18 |
|
|
@@ -202,6 +202,19 @@ node --test tests/attack-sim-*.test.js
|
|
|
202
202
|
| attack-sim-agentic-limits | AITG-APP-06: Agentic Behavior Limits | 18 |
|
|
203
203
|
| attack-sim-sandbox-escape | NVIDIA 3-axis: Sandbox Escape | 15 |
|
|
204
204
|
| attack-sim-defense-chain | SAIF: Defense-in-depth Chain | 12 |
|
|
205
|
+
| attack-sim-automode-bypass | Auto Mode: soft_deny/soft_allow bypass | 15 |
|
|
206
|
+
|
|
207
|
+
## Auto Mode Awareness (v0.5.0)
|
|
208
|
+
|
|
209
|
+
Shield Harness detects Claude Code's Auto Mode (Research Preview) configuration at session start and protects against dangerous settings:
|
|
210
|
+
|
|
211
|
+
| Setting | Risk | Shield Harness Response |
|
|
212
|
+
| ---------------------- | ---------------------------------------------------------- | -------------------------------------------------------------------- |
|
|
213
|
+
| `autoMode.soft_deny` | **CRITICAL** — disables all classifier default protections | Config-guard blocks addition; session-start outputs CRITICAL warning |
|
|
214
|
+
| `autoMode.soft_allow` | WARN — auto-approves specific tools | Config-guard blocks expansion; session-start outputs WARNING |
|
|
215
|
+
| `autoMode.environment` | Safe — informational only | Detected and recorded in session |
|
|
216
|
+
|
|
217
|
+
All existing hooks (PreToolUse, PostToolUse) fire normally under Auto Mode — `permissions.deny` rules remain absolute. Auto Mode's classifier cannot override hook denials.
|
|
205
218
|
|
|
206
219
|
## Channel Integration
|
|
207
220
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shield-harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Security harness for Claude Code — hooks-driven, zero-hassle defense",
|
|
5
5
|
"bin": {
|
|
6
6
|
"shield-harness": "./bin/shield-harness.js"
|
|
@@ -27,7 +27,10 @@
|
|
|
27
27
|
"test:openshell-detect": "node --test tests/openshell-detect.test.js",
|
|
28
28
|
"test:openshell-evidence": "node --test tests/openshell-evidence.test.js",
|
|
29
29
|
"test:tier-policy": "node --test tests/tier-policy-gen.test.js",
|
|
30
|
-
"test:policy-effectiveness": "node --test tests/policy-effectiveness.test.js"
|
|
30
|
+
"test:policy-effectiveness": "node --test tests/policy-effectiveness.test.js",
|
|
31
|
+
"test:automode": "node --test tests/automode-detect.test.js",
|
|
32
|
+
"test:automode-guard": "node --test tests/config-guard-automode.test.js",
|
|
33
|
+
"test:attack-automode": "node --test tests/attack-sim-automode-bypass.test.js"
|
|
31
34
|
},
|
|
32
35
|
"keywords": [
|
|
33
36
|
"claude-code",
|