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 +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/index.ts +11 -3
- package/src/layers/data-flow-guard.ts +3 -1
- package/src/layers/input-auditor.ts +10 -3
- package/src/layers/outbound-guard.ts +8 -3
- package/src/layers/session-guard.ts +15 -5
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` —
|
|
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 |
|
package/openclaw.plugin.json
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
}
|
|
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
|
|
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
|
-
|
|
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
|
-
}
|
|
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
|
|
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
|
-
|
|
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
|
-
}
|
|
17
|
+
}
|
|
17
18
|
|
|
18
|
-
|
|
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
|
-
}
|
|
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
|
}
|