@token-security/clawdit 0.1.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 (94) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +197 -0
  3. package/dist/checks/auth-001-device-auth-disabled.d.ts +10 -0
  4. package/dist/checks/auth-001-device-auth-disabled.js +34 -0
  5. package/dist/checks/auth-002-insecure-fallback.d.ts +10 -0
  6. package/dist/checks/auth-002-insecure-fallback.js +34 -0
  7. package/dist/checks/auth-003-no-gateway-auth.d.ts +10 -0
  8. package/dist/checks/auth-003-no-gateway-auth.js +40 -0
  9. package/dist/checks/auth-004-public-trusted-proxies.d.ts +10 -0
  10. package/dist/checks/auth-004-public-trusted-proxies.js +37 -0
  11. package/dist/checks/auth-005-hooks-no-token.d.ts +10 -0
  12. package/dist/checks/auth-005-hooks-no-token.js +42 -0
  13. package/dist/checks/auth-006-pairing-exposed.d.ts +10 -0
  14. package/dist/checks/auth-006-pairing-exposed.js +46 -0
  15. package/dist/checks/auth-007-missing-trusted-proxies.d.ts +11 -0
  16. package/dist/checks/auth-007-missing-trusted-proxies.js +46 -0
  17. package/dist/checks/chan-001-open-dm.d.ts +10 -0
  18. package/dist/checks/chan-001-open-dm.js +48 -0
  19. package/dist/checks/chan-002-group-policy.d.ts +10 -0
  20. package/dist/checks/chan-002-group-policy.js +43 -0
  21. package/dist/checks/chan-003-no-mention.d.ts +10 -0
  22. package/dist/checks/chan-003-no-mention.js +45 -0
  23. package/dist/checks/chan-004-dm-isolation.d.ts +10 -0
  24. package/dist/checks/chan-004-dm-isolation.js +50 -0
  25. package/dist/checks/chan-005-verbose-groups.d.ts +10 -0
  26. package/dist/checks/chan-005-verbose-groups.js +53 -0
  27. package/dist/checks/disc-001-mdns-full.d.ts +10 -0
  28. package/dist/checks/disc-001-mdns-full.js +34 -0
  29. package/dist/checks/disc-002-mdns-enabled.d.ts +10 -0
  30. package/dist/checks/disc-002-mdns-enabled.js +35 -0
  31. package/dist/checks/exec-001-full-security.d.ts +10 -0
  32. package/dist/checks/exec-001-full-security.js +34 -0
  33. package/dist/checks/exec-002-sandbox-disabled.d.ts +10 -0
  34. package/dist/checks/exec-002-sandbox-disabled.js +34 -0
  35. package/dist/checks/exec-003-elevated-unrestricted.d.ts +10 -0
  36. package/dist/checks/exec-003-elevated-unrestricted.js +38 -0
  37. package/dist/checks/exec-004-approval-fallback.d.ts +10 -0
  38. package/dist/checks/exec-004-approval-fallback.js +50 -0
  39. package/dist/checks/exec-005-sandbox-non-main.d.ts +10 -0
  40. package/dist/checks/exec-005-sandbox-non-main.js +34 -0
  41. package/dist/checks/exec-006-cross-agent-sandbox.d.ts +10 -0
  42. package/dist/checks/exec-006-cross-agent-sandbox.js +34 -0
  43. package/dist/checks/exec-007-workspace-rw.d.ts +10 -0
  44. package/dist/checks/exec-007-workspace-rw.js +34 -0
  45. package/dist/checks/index.d.ts +16 -0
  46. package/dist/checks/index.js +94 -0
  47. package/dist/checks/loader.d.ts +38 -0
  48. package/dist/checks/loader.js +149 -0
  49. package/dist/checks/model-001-weak-model-tools.d.ts +10 -0
  50. package/dist/checks/model-001-weak-model-tools.js +68 -0
  51. package/dist/checks/net-001-gateway-binding.d.ts +10 -0
  52. package/dist/checks/net-001-gateway-binding.js +34 -0
  53. package/dist/checks/net-002-default-port.d.ts +10 -0
  54. package/dist/checks/net-002-default-port.js +35 -0
  55. package/dist/checks/net-003-tailnet-no-token.d.ts +10 -0
  56. package/dist/checks/net-003-tailnet-no-token.js +34 -0
  57. package/dist/checks/plug-001-no-allowlist.d.ts +10 -0
  58. package/dist/checks/plug-001-no-allowlist.js +52 -0
  59. package/dist/checks/plug-002-extensions-exposed.d.ts +10 -0
  60. package/dist/checks/plug-002-extensions-exposed.js +41 -0
  61. package/dist/checks/runner.d.ts +14 -0
  62. package/dist/checks/runner.js +72 -0
  63. package/dist/checks/schema.d.ts +54 -0
  64. package/dist/checks/schema.js +171 -0
  65. package/dist/checks/sec-001-hardcoded-keys.d.ts +10 -0
  66. package/dist/checks/sec-001-hardcoded-keys.js +34 -0
  67. package/dist/checks/sec-002-world-readable-config.d.ts +10 -0
  68. package/dist/checks/sec-002-world-readable-config.js +39 -0
  69. package/dist/checks/sec-003-credentials-exposed.d.ts +10 -0
  70. package/dist/checks/sec-003-credentials-exposed.js +41 -0
  71. package/dist/checks/sec-004-env-readable.d.ts +10 -0
  72. package/dist/checks/sec-004-env-readable.js +40 -0
  73. package/dist/checks/sec-005-transcripts-exposed.d.ts +11 -0
  74. package/dist/checks/sec-005-transcripts-exposed.js +62 -0
  75. package/dist/checks/sec-006-redaction-disabled.d.ts +10 -0
  76. package/dist/checks/sec-006-redaction-disabled.js +34 -0
  77. package/dist/checks/sec-007-no-redact-patterns.d.ts +10 -0
  78. package/dist/checks/sec-007-no-redact-patterns.js +39 -0
  79. package/dist/checks/sec-008-state-dir-permissions.d.ts +10 -0
  80. package/dist/checks/sec-008-state-dir-permissions.js +49 -0
  81. package/dist/checks/types.d.ts +45 -0
  82. package/dist/checks/types.js +2 -0
  83. package/dist/clawdit-output.schema.json +162 -0
  84. package/dist/cli.d.ts +23 -0
  85. package/dist/cli.js +132 -0
  86. package/dist/config.d.ts +22 -0
  87. package/dist/config.js +150 -0
  88. package/dist/formatter.d.ts +42 -0
  89. package/dist/formatter.js +233 -0
  90. package/dist/index.d.ts +3 -0
  91. package/dist/index.js +168 -0
  92. package/dist/utils.d.ts +46 -0
  93. package/dist/utils.js +146 -0
  94. package/package.json +48 -0
@@ -0,0 +1,43 @@
1
+ /**
2
+ * CHAN-002: Group policy not set to allowlist
3
+ *
4
+ * Detects when a channel's groupPolicy is not set to 'allowlist',
5
+ * potentially allowing messages from unauthorized groups.
6
+ */
7
+ import { getValueAtPath } from '../utils.js';
8
+ const check = {
9
+ id: 'CHAN-002',
10
+ severity: 'MEDIUM',
11
+ name: 'Group policy not set to allowlist',
12
+ execute(ctx) {
13
+ const findings = [];
14
+ const channels = getValueAtPath(ctx.config, 'channels');
15
+ if (!channels || typeof channels !== 'object')
16
+ return [];
17
+ for (const [channelName, channelConfig] of Object.entries(channels)) {
18
+ if (!channelConfig || typeof channelConfig !== 'object')
19
+ continue;
20
+ const groupPolicy = channelConfig.groupPolicy;
21
+ // Only 'allowlist' is considered secure
22
+ if (groupPolicy !== undefined && groupPolicy !== 'allowlist') {
23
+ findings.push({
24
+ id: 'CHAN-002',
25
+ severity: 'MEDIUM',
26
+ name: 'Group policy not set to allowlist',
27
+ location: { file: ctx.configPath, path: `channels.${channelName}.groupPolicy` },
28
+ currentValue: groupPolicy,
29
+ expectedValue: 'allowlist',
30
+ risk: `Channel "${channelName}" uses "${groupPolicy}" group policy. This could allow messages from unauthorized groups or channels.`,
31
+ fix: {
32
+ description: 'Set group policy to allowlist',
33
+ command: `jq '.channels["${channelName}"].groupPolicy = "allowlist"' ${ctx.configPath} > tmp.json && mv tmp.json ${ctx.configPath}`,
34
+ },
35
+ references: ['https://docs.openclaw.ai/channels/security#group-policy'],
36
+ });
37
+ }
38
+ }
39
+ return findings;
40
+ },
41
+ };
42
+ export default check;
43
+ //# sourceMappingURL=chan-002-group-policy.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * CHAN-003: Require mention disabled in groups
3
+ *
4
+ * Detects when requireMention is disabled for group channels,
5
+ * allowing the bot to respond to any message without being mentioned.
6
+ */
7
+ import type { Check } from './types.js';
8
+ declare const check: Check;
9
+ export default check;
10
+ //# sourceMappingURL=chan-003-no-mention.d.ts.map
@@ -0,0 +1,45 @@
1
+ /**
2
+ * CHAN-003: Require mention disabled in groups
3
+ *
4
+ * Detects when requireMention is disabled for group channels,
5
+ * allowing the bot to respond to any message without being mentioned.
6
+ */
7
+ import { getValueAtPath } from '../utils.js';
8
+ const check = {
9
+ id: 'CHAN-003',
10
+ severity: 'LOW',
11
+ name: 'Require mention disabled in groups',
12
+ execute(ctx) {
13
+ const findings = [];
14
+ const channels = getValueAtPath(ctx.config, 'channels');
15
+ if (!channels || typeof channels !== 'object')
16
+ return [];
17
+ for (const [channelName, channelConfig] of Object.entries(channels)) {
18
+ if (!channelConfig || typeof channelConfig !== 'object')
19
+ continue;
20
+ const config = channelConfig;
21
+ const requireMention = config.requireMention;
22
+ const channelType = config.type;
23
+ // Only flag for group channels where requireMention is explicitly false
24
+ if (requireMention === false && (channelType === 'group' || channelType === undefined)) {
25
+ findings.push({
26
+ id: 'CHAN-003',
27
+ severity: 'LOW',
28
+ name: 'Require mention disabled in groups',
29
+ location: { file: ctx.configPath, path: `channels.${channelName}.requireMention` },
30
+ currentValue: requireMention,
31
+ expectedValue: 'true (or not set)',
32
+ risk: `Channel "${channelName}" responds to all messages without requiring a mention. This increases exposure to prompt injection and noise.`,
33
+ fix: {
34
+ description: 'Enable require mention for groups',
35
+ command: `jq '.channels["${channelName}"].requireMention = true' ${ctx.configPath} > tmp.json && mv tmp.json ${ctx.configPath}`,
36
+ },
37
+ references: ['https://docs.openclaw.ai/channels/security#require-mention'],
38
+ });
39
+ }
40
+ }
41
+ return findings;
42
+ },
43
+ };
44
+ export default check;
45
+ //# sourceMappingURL=chan-003-no-mention.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * CHAN-004: DM session isolation disabled
3
+ *
4
+ * Detects when session.dmScope is not set to 'per-channel-peer' in configs
5
+ * where multiple users can DM the bot, potentially allowing session cross-contamination.
6
+ */
7
+ import type { Check } from './types.js';
8
+ declare const check: Check;
9
+ export default check;
10
+ //# sourceMappingURL=chan-004-dm-isolation.d.ts.map
@@ -0,0 +1,50 @@
1
+ /**
2
+ * CHAN-004: DM session isolation disabled
3
+ *
4
+ * Detects when session.dmScope is not set to 'per-channel-peer' in configs
5
+ * where multiple users can DM the bot, potentially allowing session cross-contamination.
6
+ */
7
+ import { getValueAtPath } from '../utils.js';
8
+ const check = {
9
+ id: 'CHAN-004',
10
+ severity: 'MEDIUM',
11
+ name: 'DM session isolation disabled',
12
+ execute(ctx) {
13
+ const findings = [];
14
+ const channels = getValueAtPath(ctx.config, 'channels');
15
+ if (!channels || typeof channels !== 'object')
16
+ return [];
17
+ for (const [channelName, channelConfig] of Object.entries(channels)) {
18
+ if (!channelConfig || typeof channelConfig !== 'object')
19
+ continue;
20
+ const config = channelConfig;
21
+ const dmPolicy = config.dmPolicy;
22
+ const allowFrom = config.allowFrom;
23
+ const session = config.session;
24
+ const dmScope = session?.dmScope;
25
+ // Check if multiple users can DM
26
+ const multipleUsersCanDM = dmPolicy === 'open' ||
27
+ (dmPolicy === 'allowlist' && Array.isArray(allowFrom) && allowFrom.length > 1);
28
+ // If multiple users can DM and dmScope isn't per-channel-peer, flag it
29
+ if (multipleUsersCanDM && dmScope !== 'per-channel-peer') {
30
+ findings.push({
31
+ id: 'CHAN-004',
32
+ severity: 'MEDIUM',
33
+ name: 'DM session isolation disabled',
34
+ location: { file: ctx.configPath, path: `channels.${channelName}.session.dmScope` },
35
+ currentValue: dmScope ?? 'not set',
36
+ expectedValue: 'per-channel-peer',
37
+ risk: `Channel "${channelName}" allows multiple users to DM without session isolation. Users could potentially access each other's session context.`,
38
+ fix: {
39
+ description: 'Enable per-channel-peer session isolation',
40
+ command: `jq '.channels["${channelName}"].session.dmScope = "per-channel-peer"' ${ctx.configPath} > tmp.json && mv tmp.json ${ctx.configPath}`,
41
+ },
42
+ references: ['https://docs.openclaw.ai/channels/security#session-isolation'],
43
+ });
44
+ }
45
+ }
46
+ return findings;
47
+ },
48
+ };
49
+ export default check;
50
+ //# sourceMappingURL=chan-004-dm-isolation.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * CHAN-005: Verbose/reasoning enabled in groups
3
+ *
4
+ * Detects when verbose mode or reasoning mode is enabled in group channels,
5
+ * which could leak internal processing details.
6
+ */
7
+ import type { Check } from './types.js';
8
+ declare const check: Check;
9
+ export default check;
10
+ //# sourceMappingURL=chan-005-verbose-groups.d.ts.map
@@ -0,0 +1,53 @@
1
+ /**
2
+ * CHAN-005: Verbose/reasoning enabled in groups
3
+ *
4
+ * Detects when verbose mode or reasoning mode is enabled in group channels,
5
+ * which could leak internal processing details.
6
+ */
7
+ import { getValueAtPath } from '../utils.js';
8
+ const check = {
9
+ id: 'CHAN-005',
10
+ severity: 'LOW',
11
+ name: 'Verbose/reasoning enabled in groups',
12
+ execute(ctx) {
13
+ const findings = [];
14
+ const channels = getValueAtPath(ctx.config, 'channels');
15
+ if (!channels || typeof channels !== 'object')
16
+ return [];
17
+ for (const [channelName, channelConfig] of Object.entries(channels)) {
18
+ if (!channelConfig || typeof channelConfig !== 'object')
19
+ continue;
20
+ const config = channelConfig;
21
+ const channelType = config.type;
22
+ const verbose = config.verbose;
23
+ const reasoning = config.reasoning;
24
+ // Only check group channels (type: group or undefined)
25
+ if (channelType !== 'dm') {
26
+ const issues = [];
27
+ if (verbose === true)
28
+ issues.push('verbose');
29
+ if (reasoning === true)
30
+ issues.push('reasoning');
31
+ if (issues.length > 0) {
32
+ findings.push({
33
+ id: 'CHAN-005',
34
+ severity: 'LOW',
35
+ name: 'Verbose/reasoning enabled in groups',
36
+ location: { file: ctx.configPath, path: `channels.${channelName}` },
37
+ currentValue: issues.join(', ') + ' enabled',
38
+ expectedValue: 'verbose: false, reasoning: false',
39
+ risk: `Channel "${channelName}" has ${issues.join(' and ')} mode enabled. This exposes internal processing details to all group members.`,
40
+ fix: {
41
+ description: 'Disable verbose and reasoning modes in groups',
42
+ command: `jq '.channels["${channelName}"].verbose = false | .channels["${channelName}"].reasoning = false' ${ctx.configPath} > tmp.json && mv tmp.json ${ctx.configPath}`,
43
+ },
44
+ references: ['https://docs.openclaw.ai/channels/security#output-modes'],
45
+ });
46
+ }
47
+ }
48
+ }
49
+ return findings;
50
+ },
51
+ };
52
+ export default check;
53
+ //# sourceMappingURL=chan-005-verbose-groups.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * DISC-001: mDNS full mode exposes system info
3
+ *
4
+ * Detects when mDNS discovery is set to full mode, broadcasting
5
+ * detailed system information on the local network.
6
+ */
7
+ import type { Check } from './types.js';
8
+ declare const check: Check;
9
+ export default check;
10
+ //# sourceMappingURL=disc-001-mdns-full.d.ts.map
@@ -0,0 +1,34 @@
1
+ /**
2
+ * DISC-001: mDNS full mode exposes system info
3
+ *
4
+ * Detects when mDNS discovery is set to full mode, broadcasting
5
+ * detailed system information on the local network.
6
+ */
7
+ import { getValueAtPath } from '../utils.js';
8
+ const check = {
9
+ id: 'DISC-001',
10
+ severity: 'MEDIUM',
11
+ name: 'mDNS full mode exposes system info',
12
+ execute(ctx) {
13
+ const mode = getValueAtPath(ctx.config, 'discovery.mdns.mode');
14
+ if (mode === 'full') {
15
+ return [{
16
+ id: 'DISC-001',
17
+ severity: 'MEDIUM',
18
+ name: 'mDNS full mode exposes system info',
19
+ location: { file: ctx.configPath, path: 'discovery.mdns.mode' },
20
+ currentValue: 'full',
21
+ expectedValue: 'minimal or off',
22
+ risk: 'Full mDNS mode broadcasts detailed system information on the local network, aiding reconnaissance by attackers.',
23
+ fix: {
24
+ description: 'Set mDNS to minimal or off',
25
+ command: `jq '.discovery.mdns.mode = "minimal"' ${ctx.configPath} > tmp.json && mv tmp.json ${ctx.configPath}`,
26
+ },
27
+ references: ['https://docs.openclaw.ai/discovery/mdns'],
28
+ }];
29
+ }
30
+ return [];
31
+ },
32
+ };
33
+ export default check;
34
+ //# sourceMappingURL=disc-001-mdns-full.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * DISC-002: mDNS enabled (information disclosure)
3
+ *
4
+ * Detects when mDNS discovery mode is not set to 'off',
5
+ * potentially advertising the service on the local network.
6
+ */
7
+ import type { Check } from './types.js';
8
+ declare const check: Check;
9
+ export default check;
10
+ //# sourceMappingURL=disc-002-mdns-enabled.d.ts.map
@@ -0,0 +1,35 @@
1
+ /**
2
+ * DISC-002: mDNS enabled (information disclosure)
3
+ *
4
+ * Detects when mDNS discovery mode is not set to 'off',
5
+ * potentially advertising the service on the local network.
6
+ */
7
+ import { getValueAtPath } from '../utils.js';
8
+ const check = {
9
+ id: 'DISC-002',
10
+ severity: 'LOW',
11
+ name: 'mDNS enabled (information disclosure)',
12
+ execute(ctx) {
13
+ const mdnsMode = getValueAtPath(ctx.config, 'discovery.mdns.mode');
14
+ // Flag if mDNS is explicitly enabled (not off or undefined)
15
+ if (mdnsMode !== undefined && mdnsMode !== 'off') {
16
+ return [{
17
+ id: 'DISC-002',
18
+ severity: 'LOW',
19
+ name: 'mDNS enabled (information disclosure)',
20
+ location: { file: ctx.configPath, path: 'discovery.mdns.mode' },
21
+ currentValue: mdnsMode,
22
+ expectedValue: 'off',
23
+ risk: 'mDNS broadcasts the service presence on the local network. Attackers on the same network can easily discover the OpenClaw instance.',
24
+ fix: {
25
+ description: 'Disable mDNS discovery',
26
+ command: `jq '.discovery.mdns.mode = "off"' ${ctx.configPath} > tmp.json && mv tmp.json ${ctx.configPath}`,
27
+ },
28
+ references: ['https://docs.openclaw.ai/discovery/security#mdns'],
29
+ }];
30
+ }
31
+ return [];
32
+ },
33
+ };
34
+ export default check;
35
+ //# sourceMappingURL=disc-002-mdns-enabled.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * EXEC-001: Exec security set to full
3
+ *
4
+ * Detects when exec security is set to "full", allowing arbitrary
5
+ * command execution without restrictions.
6
+ */
7
+ import type { Check } from './types.js';
8
+ declare const check: Check;
9
+ export default check;
10
+ //# sourceMappingURL=exec-001-full-security.d.ts.map
@@ -0,0 +1,34 @@
1
+ /**
2
+ * EXEC-001: Exec security set to full
3
+ *
4
+ * Detects when exec security is set to "full", allowing arbitrary
5
+ * command execution without restrictions.
6
+ */
7
+ import { getValueAtPath } from '../utils.js';
8
+ const check = {
9
+ id: 'EXEC-001',
10
+ severity: 'HIGH',
11
+ name: 'Exec security set to full',
12
+ execute(ctx) {
13
+ const security = getValueAtPath(ctx.config, 'tools.exec.security');
14
+ if (security === 'full') {
15
+ return [{
16
+ id: 'EXEC-001',
17
+ severity: 'HIGH',
18
+ name: 'Exec security set to full',
19
+ location: { file: ctx.configPath, path: 'tools.exec.security' },
20
+ currentValue: 'full',
21
+ expectedValue: 'restricted or sandbox',
22
+ risk: 'Full exec security allows arbitrary command execution without restrictions. Malicious prompts can execute any system command.',
23
+ fix: {
24
+ description: 'Set exec security to restricted',
25
+ command: `jq '.tools.exec.security = "restricted"' ${ctx.configPath} > tmp.json && mv tmp.json ${ctx.configPath}`,
26
+ },
27
+ references: ['https://docs.openclaw.ai/tools/exec#security-modes'],
28
+ }];
29
+ }
30
+ return [];
31
+ },
32
+ };
33
+ export default check;
34
+ //# sourceMappingURL=exec-001-full-security.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * EXEC-002: Sandbox disabled for all sessions
3
+ *
4
+ * Detects when the sandbox mode is set to "off", allowing all commands
5
+ * to execute directly on the host system.
6
+ */
7
+ import type { Check } from './types.js';
8
+ declare const check: Check;
9
+ export default check;
10
+ //# sourceMappingURL=exec-002-sandbox-disabled.d.ts.map
@@ -0,0 +1,34 @@
1
+ /**
2
+ * EXEC-002: Sandbox disabled for all sessions
3
+ *
4
+ * Detects when the sandbox mode is set to "off", allowing all commands
5
+ * to execute directly on the host system.
6
+ */
7
+ import { getValueAtPath } from '../utils.js';
8
+ const check = {
9
+ id: 'EXEC-002',
10
+ severity: 'HIGH',
11
+ name: 'Sandbox disabled for all sessions',
12
+ execute(ctx) {
13
+ const mode = getValueAtPath(ctx.config, 'agents.defaults.sandbox.mode');
14
+ if (mode === 'off') {
15
+ return [{
16
+ id: 'EXEC-002',
17
+ severity: 'HIGH',
18
+ name: 'Sandbox disabled for all sessions',
19
+ location: { file: ctx.configPath, path: 'agents.defaults.sandbox.mode' },
20
+ currentValue: 'off',
21
+ expectedValue: 'all or non-main',
22
+ risk: 'All commands execute directly on the host system without isolation. Malicious prompts can modify system files, install malware, or exfiltrate data.',
23
+ fix: {
24
+ description: 'Enable sandbox for all sessions',
25
+ command: `jq '.agents.defaults.sandbox.mode = "all"' ${ctx.configPath} > tmp.json && mv tmp.json ${ctx.configPath}`,
26
+ },
27
+ references: ['https://docs.openclaw.ai/agents/sandbox'],
28
+ }];
29
+ }
30
+ return [];
31
+ },
32
+ };
33
+ export default check;
34
+ //# sourceMappingURL=exec-002-sandbox-disabled.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * EXEC-003: Elevated mode enabled without restrictions
3
+ *
4
+ * Detects when elevated mode is enabled without an allowFrom restriction,
5
+ * allowing any session to bypass sandbox isolation.
6
+ */
7
+ import type { Check } from './types.js';
8
+ declare const check: Check;
9
+ export default check;
10
+ //# sourceMappingURL=exec-003-elevated-unrestricted.d.ts.map
@@ -0,0 +1,38 @@
1
+ /**
2
+ * EXEC-003: Elevated mode enabled without restrictions
3
+ *
4
+ * Detects when elevated mode is enabled without an allowFrom restriction,
5
+ * allowing any session to bypass sandbox isolation.
6
+ */
7
+ import { getValueAtPath } from '../utils.js';
8
+ const check = {
9
+ id: 'EXEC-003',
10
+ severity: 'HIGH',
11
+ name: 'Elevated mode enabled without restrictions',
12
+ execute(ctx) {
13
+ const enabled = getValueAtPath(ctx.config, 'tools.elevated.enabled');
14
+ const allowFrom = getValueAtPath(ctx.config, 'tools.elevated.allowFrom');
15
+ if (enabled === true) {
16
+ const hasRestrictions = Array.isArray(allowFrom) && allowFrom.length > 0;
17
+ if (!hasRestrictions) {
18
+ return [{
19
+ id: 'EXEC-003',
20
+ severity: 'HIGH',
21
+ name: 'Elevated mode enabled without restrictions',
22
+ location: { file: ctx.configPath, path: 'tools.elevated' },
23
+ currentValue: 'enabled with no allowFrom restrictions',
24
+ expectedValue: 'tools.elevated.allowFrom configured with specific sources',
25
+ risk: 'Elevated mode bypasses sandbox isolation and executes directly on the host. Without restrictions, any session can use elevated commands.',
26
+ fix: {
27
+ description: 'Disable elevated mode or configure allowFrom',
28
+ command: `jq '.tools.elevated.enabled = false' ${ctx.configPath} > tmp.json && mv tmp.json ${ctx.configPath}`,
29
+ },
30
+ references: ['https://docs.openclaw.ai/tools/elevated'],
31
+ }];
32
+ }
33
+ }
34
+ return [];
35
+ },
36
+ };
37
+ export default check;
38
+ //# sourceMappingURL=exec-003-elevated-unrestricted.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * EXEC-004: Exec approval fallback not set to deny
3
+ *
4
+ * Detects when exec-approvals.json has askFallback set to something other than 'deny',
5
+ * which could allow commands through when no explicit approval rule matches.
6
+ */
7
+ import type { Check } from './types.js';
8
+ declare const check: Check;
9
+ export default check;
10
+ //# sourceMappingURL=exec-004-approval-fallback.d.ts.map
@@ -0,0 +1,50 @@
1
+ /**
2
+ * EXEC-004: Exec approval fallback not set to deny
3
+ *
4
+ * Detects when exec-approvals.json has askFallback set to something other than 'deny',
5
+ * which could allow commands through when no explicit approval rule matches.
6
+ */
7
+ import { join } from 'node:path';
8
+ import { existsSync, readFileSync } from 'node:fs';
9
+ const check = {
10
+ id: 'EXEC-004',
11
+ severity: 'MEDIUM',
12
+ name: 'Exec approval fallback not set to deny',
13
+ execute(ctx) {
14
+ // Look for exec-approvals.json in config directory
15
+ const approvalsPath = join(ctx.configDir, 'exec-approvals.json');
16
+ // Skip if file doesn't exist
17
+ if (!existsSync(approvalsPath))
18
+ return [];
19
+ let approvals;
20
+ try {
21
+ const content = readFileSync(approvalsPath, 'utf-8');
22
+ approvals = JSON.parse(content);
23
+ }
24
+ catch {
25
+ // Can't parse file, skip check
26
+ return [];
27
+ }
28
+ const askFallback = approvals.askFallback;
29
+ // Only 'deny' is secure
30
+ if (askFallback !== undefined && askFallback !== 'deny') {
31
+ return [{
32
+ id: 'EXEC-004',
33
+ severity: 'MEDIUM',
34
+ name: 'Exec approval fallback not set to deny',
35
+ location: { file: approvalsPath, path: 'askFallback' },
36
+ currentValue: askFallback,
37
+ expectedValue: 'deny',
38
+ risk: `When no approval rule matches, commands will ${askFallback === 'allow' ? 'be allowed' : 'prompt the user'}. This could allow unintended command execution.`,
39
+ fix: {
40
+ description: 'Set askFallback to deny',
41
+ command: `jq '.askFallback = "deny"' ${approvalsPath} > tmp.json && mv tmp.json ${approvalsPath}`,
42
+ },
43
+ references: ['https://docs.openclaw.ai/exec/approvals#fallback'],
44
+ }];
45
+ }
46
+ return [];
47
+ },
48
+ };
49
+ export default check;
50
+ //# sourceMappingURL=exec-004-approval-fallback.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * EXEC-005: Sandbox only protects non-main sessions
3
+ *
4
+ * Detects when sandbox mode is set to "non-main", leaving the main/DM
5
+ * session without sandbox protection.
6
+ */
7
+ import type { Check } from './types.js';
8
+ declare const check: Check;
9
+ export default check;
10
+ //# sourceMappingURL=exec-005-sandbox-non-main.d.ts.map
@@ -0,0 +1,34 @@
1
+ /**
2
+ * EXEC-005: Sandbox only protects non-main sessions
3
+ *
4
+ * Detects when sandbox mode is set to "non-main", leaving the main/DM
5
+ * session without sandbox protection.
6
+ */
7
+ import { getValueAtPath } from '../utils.js';
8
+ const check = {
9
+ id: 'EXEC-005',
10
+ severity: 'MEDIUM',
11
+ name: 'Sandbox only protects non-main sessions',
12
+ execute(ctx) {
13
+ const mode = getValueAtPath(ctx.config, 'agents.defaults.sandbox.mode');
14
+ if (mode === 'non-main') {
15
+ return [{
16
+ id: 'EXEC-005',
17
+ severity: 'MEDIUM',
18
+ name: 'Sandbox only protects non-main sessions',
19
+ location: { file: ctx.configPath, path: 'agents.defaults.sandbox.mode' },
20
+ currentValue: 'non-main',
21
+ expectedValue: 'all',
22
+ risk: 'Commands from the main/DM session execute directly on the gateway host without sandbox isolation.',
23
+ fix: {
24
+ description: 'Enable sandbox for all sessions',
25
+ command: `jq '.agents.defaults.sandbox.mode = "all"' ${ctx.configPath} > tmp.json && mv tmp.json ${ctx.configPath}`,
26
+ },
27
+ references: ['https://docs.openclaw.ai/agents/sandbox'],
28
+ }];
29
+ }
30
+ return [];
31
+ },
32
+ };
33
+ export default check;
34
+ //# sourceMappingURL=exec-005-sandbox-non-main.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * EXEC-006: Sandbox scope enables cross-agent access
3
+ *
4
+ * Detects when sandbox scope is set to "shared", allowing agents to
5
+ * access each other's data and state.
6
+ */
7
+ import type { Check } from './types.js';
8
+ declare const check: Check;
9
+ export default check;
10
+ //# sourceMappingURL=exec-006-cross-agent-sandbox.d.ts.map
@@ -0,0 +1,34 @@
1
+ /**
2
+ * EXEC-006: Sandbox scope enables cross-agent access
3
+ *
4
+ * Detects when sandbox scope is set to "shared", allowing agents to
5
+ * access each other's data and state.
6
+ */
7
+ import { getValueAtPath } from '../utils.js';
8
+ const check = {
9
+ id: 'EXEC-006',
10
+ severity: 'HIGH',
11
+ name: 'Sandbox scope enables cross-agent access',
12
+ execute(ctx) {
13
+ const scope = getValueAtPath(ctx.config, 'agents.defaults.sandbox.scope');
14
+ if (scope === 'shared') {
15
+ return [{
16
+ id: 'EXEC-006',
17
+ severity: 'HIGH',
18
+ name: 'Sandbox scope enables cross-agent access',
19
+ location: { file: ctx.configPath, path: 'agents.defaults.sandbox.scope' },
20
+ currentValue: 'shared',
21
+ expectedValue: 'isolated or per-session',
22
+ risk: 'Agents share sandbox state, allowing one compromised agent to access or modify another agent\'s data and session state.',
23
+ fix: {
24
+ description: 'Set sandbox scope to isolated',
25
+ command: `jq '.agents.defaults.sandbox.scope = "isolated"' ${ctx.configPath} > tmp.json && mv tmp.json ${ctx.configPath}`,
26
+ },
27
+ references: ['https://docs.openclaw.ai/agents/sandbox#scope'],
28
+ }];
29
+ }
30
+ return [];
31
+ },
32
+ };
33
+ export default check;
34
+ //# sourceMappingURL=exec-006-cross-agent-sandbox.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * EXEC-007: Workspace access too permissive
3
+ *
4
+ * Detects when workspaceAccess is set to 'rw' (read-write),
5
+ * giving agents full write access to the workspace.
6
+ */
7
+ import type { Check } from './types.js';
8
+ declare const check: Check;
9
+ export default check;
10
+ //# sourceMappingURL=exec-007-workspace-rw.d.ts.map