shellward 0.5.2 → 0.5.4

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 CHANGED
@@ -50,7 +50,7 @@ Your AI agent has full access to tools — shell, email, HTTP, file system. One
50
50
 
51
51
  | Platform | Integration | Note |
52
52
  |----------|------------|------|
53
- | **OpenClaw** | Plugin | `openclaw plugins install shellward` — out of the box |
53
+ | **OpenClaw** | Plugin + SDK | `openclaw plugins install shellward` — adapts to available hooks |
54
54
  | **Claude Code** | SDK | Anthropic's official CLI agent |
55
55
  | **Cursor** | SDK | AI-powered coding IDE |
56
56
  | **LangChain** | SDK | LLM application framework |
@@ -2,7 +2,7 @@
2
2
  "id": "shellward",
3
3
  "name": "ShellWard",
4
4
  "description": "AI Agent Security Middleware — injection detection, dangerous operation blocking, PII audit (incl. Chinese ID card, phone, bank card), data exfiltration prevention. SDK + OpenClaw plugin.",
5
- "version": "0.5.0",
5
+ "version": "0.5.3",
6
6
  "skills": ["./skills"],
7
7
  "configSchema": {
8
8
  "type": "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shellward",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
4
4
  "description": "AI Agent Security Middleware — 8-layer defense against prompt injection, data exfiltration & dangerous commands. DLP model: use data freely, block external leaks. Zero dependencies. SDK + OpenClaw plugin. Supports LangChain, AutoGPT, Claude Code, Cursor, OpenAI Agents.",
5
5
  "keywords": [
6
6
  "shellward",
package/src/index.ts CHANGED
@@ -20,7 +20,7 @@ import { registerAllCommands } from './commands/index'
20
20
  import { checkForUpdate } from './update-check'
21
21
  import { runAutoCheckOnStartup } from './auto-check'
22
22
 
23
- const CURRENT_VERSION = '0.5.0'
23
+ const CURRENT_VERSION = '0.5.3'
24
24
 
25
25
  // Re-export core engine for SDK usage
26
26
  export { ShellWard } from './core/engine'
@@ -32,11 +32,14 @@ export type { ShellWardConfig } from './types'
32
32
  * If a security hook throws, we log the error and fail-safe:
33
33
  * - before_tool_call: block (deny on error, safer than allow)
34
34
  * - other hooks: return undefined (don't break the chain)
35
+ *
36
+ * Returns boolean indicating whether hook registration succeeded.
37
+ * This allows layers to detect missing hooks and register fallbacks.
35
38
  */
36
39
  function createSafeApi(api: any, guard: ShellWard): any {
37
40
  return {
38
41
  ...api,
39
- on(hookName: string, handler: Function, opts?: any) {
42
+ on(hookName: string, handler: Function, opts?: any): boolean {
40
43
  const isBlockHook = hookName === 'before_tool_call'
41
44
  const wrappedHandler = (event: any) => {
42
45
  try {
@@ -56,7 +59,12 @@ function createSafeApi(api: any, guard: ShellWard): any {
56
59
  return undefined
57
60
  }
58
61
  }
59
- api.on(hookName, wrappedHandler, opts)
62
+ try {
63
+ api.on(hookName, wrappedHandler, opts)
64
+ return true
65
+ } catch {
66
+ return false
67
+ }
60
68
  },
61
69
  }
62
70
  }
@@ -1,9 +1,10 @@
1
1
  // src/layers/data-flow-guard.ts — L7 OpenClaw Adapter
2
- // Thin adapter: wires OpenClaw's after_tool_call + before_tool_call hooks to ShellWard core engine
2
+ // Thin adapter: wires OpenClaw hooks to ShellWard core engine for data flow tracking
3
3
 
4
4
  import type { ShellWard } from '../core/engine'
5
5
 
6
6
  export function setupDataFlowGuard(api: any, guard: ShellWard, enforce: boolean) {
7
+ // Track file reads via after_tool_call
7
8
  api.on('after_tool_call', (event: any) => {
8
9
  const toolName = String(event.toolName || '').toLowerCase()
9
10
  const params = (event.params && typeof event.params === 'object') ? event.params : {}
@@ -14,6 +15,7 @@ export function setupDataFlowGuard(api: any, guard: ShellWard, enforce: boolean)
14
15
  }
15
16
  }, { name: 'shellward.data-flow-read-tracker', priority: 50 })
16
17
 
18
+ // Block outbound sends when sensitive data was recently accessed
17
19
  api.on('before_tool_call', (event: any) => {
18
20
  const toolName = String(event.toolName || '')
19
21
  const params = (event.params && typeof event.params === 'object') ? event.params : {}
@@ -1,9 +1,11 @@
1
1
  // src/layers/input-auditor.ts — L4 OpenClaw Adapter
2
- // Thin adapter: wires OpenClaw's before_tool_call + message_received hooks to ShellWard core engine
2
+ // Thin adapter: wires OpenClaw hooks to ShellWard core engine for injection detection
3
+ // Compat: registers all known hook name variants — OpenClaw silently ignores unknown ones
3
4
 
4
5
  import type { ShellWard } from '../core/engine'
5
6
 
6
7
  export function setupInputAuditor(api: any, guard: ShellWard, enforce: boolean) {
8
+ // Tool call parameter scanning via before_tool_call
7
9
  api.on('before_tool_call', (event: any) => {
8
10
  const args: Record<string, any> = (event.params && typeof event.params === 'object') ? event.params : {}
9
11
  const texts = guard.extractTextFields(args)
@@ -22,11 +24,16 @@ export function setupInputAuditor(api: any, guard: ShellWard, enforce: boolean)
22
24
  }
23
25
  }, { name: 'shellward.input-auditor', priority: 300 })
24
26
 
25
- api.on('message_received', (event: any) => {
27
+ // Message scanning: register ALL known naming conventions
28
+ // OpenClaw silently ignores unknown hooks (no error thrown), so register all variants
29
+ const messageHandler = (event: any) => {
26
30
  const content = typeof event.content === 'string' ? event.content : ''
27
31
  if (!content) return
28
32
  guard.checkInjection(content, { source: 'message' })
29
- }, { name: 'shellward.message-auditor', priority: 100 })
33
+ }
34
+
35
+ api.on('message_received', messageHandler, { name: 'shellward.message-auditor', priority: 100 })
36
+ api.on('message:received', messageHandler, { name: 'shellward.message-auditor-v2', priority: 100 })
30
37
 
31
38
  api.logger.info(`[ShellWard] L4 Input Auditor enabled`)
32
39
  }
@@ -1,10 +1,11 @@
1
1
  // src/layers/outbound-guard.ts — L6 OpenClaw Adapter
2
- // Thin adapter: wires OpenClaw's message_sending hook to ShellWard core engine
2
+ // Thin adapter: wires OpenClaw hooks to ShellWard core engine for outbound response scanning
3
+ // Compat: registers all known hook name variants
3
4
 
4
5
  import type { ShellWard } from '../core/engine'
5
6
 
6
7
  export function setupOutboundGuard(api: any, guard: ShellWard, enforce: boolean) {
7
- api.on('message_sending', (event: any) => {
8
+ const handler = (event: any) => {
8
9
  const content = event.content
9
10
  if (!content || typeof content !== 'string') return undefined
10
11
 
@@ -18,7 +19,11 @@ export function setupOutboundGuard(api: any, guard: ShellWard, enforce: boolean)
18
19
  }
19
20
 
20
21
  return undefined
21
- }, { name: 'shellward.outbound-guard', priority: 100 })
22
+ }
23
+
24
+ // Register ALL known naming conventions — OpenClaw silently ignores unknown ones
25
+ api.on('message_sending', handler, { name: 'shellward.outbound-guard', priority: 100 })
26
+ api.on('message:sent', handler, { name: 'shellward.outbound-guard-v2', priority: 100 })
22
27
 
23
28
  api.logger.info('[ShellWard] L6 Outbound Guard enabled')
24
29
  }
@@ -1,10 +1,11 @@
1
1
  // src/layers/session-guard.ts — L8 OpenClaw Adapter
2
- // Thin adapter: wires OpenClaw's session_end + subagent_spawning hooks to ShellWard core engine
2
+ // Thin adapter: wires OpenClaw hooks to ShellWard core engine for session monitoring
3
+ // Compat: registers all known hook name variants
3
4
 
4
5
  import type { ShellWard } from '../core/engine'
5
6
 
6
7
  export function setupSessionGuard(api: any, guard: ShellWard, enforce: boolean) {
7
- api.on('session_end', () => {
8
+ const sessionEndHandler = () => {
8
9
  guard.log.write({
9
10
  level: 'INFO',
10
11
  layer: 'L8',
@@ -13,9 +14,14 @@ export function setupSessionGuard(api: any, guard: ShellWard, enforce: boolean)
13
14
  ? '会话结束 — 安全审计完成'
14
15
  : 'Session ended — security audit complete',
15
16
  })
16
- }, { name: 'shellward.session-end', priority: 50 })
17
+ }
17
18
 
18
- api.on('subagent_spawning', (event: any) => {
19
+ // Register ALL known naming conventions for session end
20
+ api.on('session_end', sessionEndHandler, { name: 'shellward.session-end', priority: 50 })
21
+ api.on('session:end', sessionEndHandler, { name: 'shellward.session-end-v2', priority: 50 })
22
+ api.on('command:new', sessionEndHandler, { name: 'shellward.session-end-fallback', priority: 50 })
23
+
24
+ const subagentHandler = (event: any) => {
19
25
  const mode = event.mode || 'unknown'
20
26
  guard.log.write({
21
27
  level: 'MEDIUM',
@@ -25,7 +31,11 @@ export function setupSessionGuard(api: any, guard: ShellWard, enforce: boolean)
25
31
  ? `子 Agent 创建: mode=${mode}, agentId=${event.agentId || 'unknown'}`
26
32
  : `Subagent spawning: mode=${mode}, agentId=${event.agentId || 'unknown'}`,
27
33
  })
28
- }, { name: 'shellward.subagent-guard', priority: 100 })
34
+ }
35
+
36
+ // Register ALL known naming conventions for subagent monitoring
37
+ api.on('subagent_spawning', subagentHandler, { name: 'shellward.subagent-guard', priority: 100 })
38
+ api.on('subagent:spawning', subagentHandler, { name: 'shellward.subagent-guard-v2', priority: 100 })
29
39
 
30
40
  api.logger.info('[ShellWard] L8 Session Guard enabled')
31
41
  }