hackmyagent-core 0.2.0 → 0.2.2
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/hardening/scanner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,UAAU,EAA0C,MAAM,kBAAkB,CAAC;AAwD3F,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAgHD,qBAAa,gBAAgB;IAE3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAelC;IAEF;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAMvB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;YAyNvC,cAAc;IAsE5B;;OAEG;YACW,iBAAiB;IA+F/B;;OAEG;IACH,OAAO,CAAC,gBAAgB;YAeV,uBAAuB;YAmGvB,aAAa;YAgDb,cAAc;YA+Fd,oBAAoB;YAwDpB,gBAAgB;YA0IhB,oBAAoB;YAgFpB,gBAAgB;YA2IhB,mBAAmB;YA4EnB,iBAAiB;YAyCjB,iBAAiB;YA+DjB,wBAAwB;YA0FxB,wBAAwB;YAmExB,wBAAwB;YAqHxB,oBAAoB;YA+GpB,uBAAuB;YA8HvB,iBAAiB;YA8GjB,oBAAoB;YAuGpB,mBAAmB;YAiGnB,gBAAgB;YAmIhB,oBAAoB;YAoIpB,gBAAgB;YAyHhB,qBAAqB;YA+GrB,eAAe;IAiI7B;;OAEG;YACW,mBAAmB;IA8GjC;;OAEG;YACW,oBAAoB;IAiKlC;;OAEG;YACW,iBAAiB;IA4I/B;;OAEG;YACW,oBAAoB;IAwIlC;;OAEG;YACW,eAAe;IAqJ7B;;OAEG;YACW,eAAe;IAuI7B;;OAEG;YACW,eAAe;IAyG7B;;OAEG;YACW,mBAAmB;IAmHjC,OAAO,CAAC,cAAc;IAsBtB;;OAEG;YACW,YAAY;IAkD1B;;OAEG;IACG,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA6DhD;;;OAGG;YACW,cAAc;IAgD5B;;OAEG;YACW,mBAAmB;IAoUjC;;;OAGG;YACW,kBAAkB;IAgDhC;;OAEG;YACW,sBAAsB;IA2LpC;;OAEG;YACW,sBAAsB;IA+BpC;;OAEG;YACW,oBAAoB;
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/hardening/scanner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,UAAU,EAA0C,MAAM,kBAAkB,CAAC;AAwD3F,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAgHD,qBAAa,gBAAgB;IAE3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAelC;IAEF;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAMvB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;YAyNvC,cAAc;IAsE5B;;OAEG;YACW,iBAAiB;IA+F/B;;OAEG;IACH,OAAO,CAAC,gBAAgB;YAeV,uBAAuB;YAmGvB,aAAa;YAgDb,cAAc;YA+Fd,oBAAoB;YAwDpB,gBAAgB;YA0IhB,oBAAoB;YAgFpB,gBAAgB;YA2IhB,mBAAmB;YA4EnB,iBAAiB;YAyCjB,iBAAiB;YA+DjB,wBAAwB;YA0FxB,wBAAwB;YAmExB,wBAAwB;YAqHxB,oBAAoB;YA+GpB,uBAAuB;YA8HvB,iBAAiB;YA8GjB,oBAAoB;YAuGpB,mBAAmB;YAiGnB,gBAAgB;YAmIhB,oBAAoB;YAoIpB,gBAAgB;YAyHhB,qBAAqB;YA+GrB,eAAe;IAiI7B;;OAEG;YACW,mBAAmB;IA8GjC;;OAEG;YACW,oBAAoB;IAiKlC;;OAEG;YACW,iBAAiB;IA4I/B;;OAEG;YACW,oBAAoB;IAwIlC;;OAEG;YACW,eAAe;IAqJ7B;;OAEG;YACW,eAAe;IAuI7B;;OAEG;YACW,eAAe;IAyG7B;;OAEG;YACW,mBAAmB;IAmHjC,OAAO,CAAC,cAAc;IAsBtB;;OAEG;YACW,YAAY;IAkD1B;;OAEG;IACG,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA6DhD;;;OAGG;YACW,cAAc;IAgD5B;;OAEG;YACW,mBAAmB;IAoUjC;;;OAGG;YACW,kBAAkB;IAgDhC;;OAEG;YACW,sBAAsB;IA2LpC;;OAEG;YACW,sBAAsB;IA+BpC;;OAEG;YACW,oBAAoB;IA0RlC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA4B3B;;OAEG;YACW,iBAAiB;IA8D/B;;OAEG;YACW,mBAAmB;IAmRjC;;OAEG;YACW,wBAAwB;CAsJvC"}
|
|
@@ -4302,23 +4302,39 @@ dist/
|
|
|
4302
4302
|
catch {
|
|
4303
4303
|
continue;
|
|
4304
4304
|
}
|
|
4305
|
+
// Track what fixes we apply
|
|
4306
|
+
let configModified = false;
|
|
4307
|
+
const fixesApplied = [];
|
|
4305
4308
|
// GATEWAY-001: Bound to 0.0.0.0
|
|
4306
4309
|
const gateway = config.gateway;
|
|
4307
|
-
|
|
4310
|
+
const boundToAllInterfaces = gateway && gateway.host === '0.0.0.0';
|
|
4311
|
+
let gateway001Fixed = false;
|
|
4312
|
+
if (boundToAllInterfaces && autoFix) {
|
|
4313
|
+
// Fix: Change 0.0.0.0 to 127.0.0.1
|
|
4314
|
+
config.gateway.host = '127.0.0.1';
|
|
4315
|
+
gateway001Fixed = true;
|
|
4316
|
+
configModified = true;
|
|
4317
|
+
fixesApplied.push('Changed gateway.host from 0.0.0.0 to 127.0.0.1 (local-only access)');
|
|
4318
|
+
}
|
|
4319
|
+
if (boundToAllInterfaces) {
|
|
4308
4320
|
findings.push({
|
|
4309
4321
|
checkId: 'GATEWAY-001',
|
|
4310
4322
|
name: 'Bound to 0.0.0.0',
|
|
4311
4323
|
description: 'Gateway is bound to all interfaces (0.0.0.0)',
|
|
4312
4324
|
category: 'gateway',
|
|
4313
4325
|
severity: 'critical',
|
|
4314
|
-
passed:
|
|
4315
|
-
message:
|
|
4326
|
+
passed: gateway001Fixed,
|
|
4327
|
+
message: gateway001Fixed
|
|
4328
|
+
? 'Fixed: Gateway now bound to 127.0.0.1 (local-only)'
|
|
4329
|
+
: 'Gateway host is 0.0.0.0 - accessible from any network interface',
|
|
4316
4330
|
file: relativePath,
|
|
4317
|
-
fixable:
|
|
4318
|
-
|
|
4331
|
+
fixable: true,
|
|
4332
|
+
fixed: gateway001Fixed,
|
|
4333
|
+
fixMessage: gateway001Fixed ? 'Changed gateway.host from 0.0.0.0 to 127.0.0.1' : undefined,
|
|
4334
|
+
fix: 'Run `hackmyagent secure-openclaw --fix` to bind gateway to 127.0.0.1 for local-only access',
|
|
4319
4335
|
});
|
|
4320
4336
|
}
|
|
4321
|
-
// GATEWAY-002: Missing WebSocket Origin Validation
|
|
4337
|
+
// GATEWAY-002: Missing WebSocket Origin Validation (not auto-fixable - requires user to specify allowed origins)
|
|
4322
4338
|
const security = config.security;
|
|
4323
4339
|
const hasWebSocketOrigins = security && security.websocketOrigins;
|
|
4324
4340
|
findings.push({
|
|
@@ -4333,12 +4349,29 @@ dist/
|
|
|
4333
4349
|
: 'Missing security.websocketOrigins - vulnerable to GHSA-g8p2 cross-origin attacks',
|
|
4334
4350
|
file: relativePath,
|
|
4335
4351
|
fixable: false,
|
|
4336
|
-
fix: '
|
|
4352
|
+
fix: 'Manually add security.websocketOrigins array with your allowed origins (e.g., ["http://localhost:3000"])',
|
|
4337
4353
|
});
|
|
4338
4354
|
// GATEWAY-003: Token Exposed in Config
|
|
4339
4355
|
const gatewayAuth = gateway?.auth;
|
|
4340
|
-
const
|
|
4341
|
-
|
|
4356
|
+
const hasPlaintextTokenInAuth = gatewayAuth && typeof gatewayAuth.token === 'string' && gatewayAuth.token.length > 0;
|
|
4357
|
+
const hasPlaintextTokenAtRoot = typeof config.token === 'string' && config.token.length > 0;
|
|
4358
|
+
const hasPlaintextToken = hasPlaintextTokenInAuth || hasPlaintextTokenAtRoot;
|
|
4359
|
+
let gateway003Fixed = false;
|
|
4360
|
+
if (hasPlaintextToken && autoFix) {
|
|
4361
|
+
// Fix: Replace plaintext token with environment variable reference
|
|
4362
|
+
if (hasPlaintextTokenInAuth && gatewayAuth) {
|
|
4363
|
+
gatewayAuth.token = '${OPENCLAW_AUTH_TOKEN}';
|
|
4364
|
+
gateway003Fixed = true;
|
|
4365
|
+
configModified = true;
|
|
4366
|
+
fixesApplied.push('Replaced gateway.auth.token with ${OPENCLAW_AUTH_TOKEN} env var reference');
|
|
4367
|
+
}
|
|
4368
|
+
if (hasPlaintextTokenAtRoot) {
|
|
4369
|
+
config.token = '${OPENCLAW_AUTH_TOKEN}';
|
|
4370
|
+
gateway003Fixed = true;
|
|
4371
|
+
configModified = true;
|
|
4372
|
+
fixesApplied.push('Replaced token with ${OPENCLAW_AUTH_TOKEN} env var reference');
|
|
4373
|
+
}
|
|
4374
|
+
}
|
|
4342
4375
|
if (hasPlaintextToken) {
|
|
4343
4376
|
findings.push({
|
|
4344
4377
|
checkId: 'GATEWAY-003',
|
|
@@ -4346,11 +4379,15 @@ dist/
|
|
|
4346
4379
|
description: 'Plaintext authentication token stored in configuration file',
|
|
4347
4380
|
category: 'gateway',
|
|
4348
4381
|
severity: 'critical',
|
|
4349
|
-
passed:
|
|
4350
|
-
message:
|
|
4382
|
+
passed: gateway003Fixed,
|
|
4383
|
+
message: gateway003Fixed
|
|
4384
|
+
? 'Fixed: Token replaced with ${OPENCLAW_AUTH_TOKEN} - set this env var with your actual token'
|
|
4385
|
+
: 'Plaintext token found in configuration - use environment variables instead',
|
|
4351
4386
|
file: relativePath,
|
|
4352
|
-
fixable:
|
|
4353
|
-
|
|
4387
|
+
fixable: true,
|
|
4388
|
+
fixed: gateway003Fixed,
|
|
4389
|
+
fixMessage: gateway003Fixed ? 'Replaced plaintext token with ${OPENCLAW_AUTH_TOKEN} env var reference. Set OPENCLAW_AUTH_TOKEN in your environment.' : undefined,
|
|
4390
|
+
fix: 'Run `hackmyagent secure-openclaw --fix` to replace plaintext token with ${OPENCLAW_AUTH_TOKEN} env var reference',
|
|
4354
4391
|
});
|
|
4355
4392
|
}
|
|
4356
4393
|
// GATEWAY-004: Approval Confirmations Disabled
|
|
@@ -4360,6 +4397,28 @@ dist/
|
|
|
4360
4397
|
const approvalsDisabled = approvals?.set === 'off' ||
|
|
4361
4398
|
approvals?.enabled === false ||
|
|
4362
4399
|
configApprovals?.enabled === false;
|
|
4400
|
+
let gateway004Fixed = false;
|
|
4401
|
+
if (approvalsDisabled && autoFix) {
|
|
4402
|
+
// Fix: Enable approvals
|
|
4403
|
+
if (approvals?.set === 'off') {
|
|
4404
|
+
approvals.set = 'on';
|
|
4405
|
+
gateway004Fixed = true;
|
|
4406
|
+
configModified = true;
|
|
4407
|
+
fixesApplied.push('Changed exec.approvals.set from "off" to "on"');
|
|
4408
|
+
}
|
|
4409
|
+
if (approvals?.enabled === false) {
|
|
4410
|
+
approvals.enabled = true;
|
|
4411
|
+
gateway004Fixed = true;
|
|
4412
|
+
configModified = true;
|
|
4413
|
+
fixesApplied.push('Changed exec.approvals.enabled to true');
|
|
4414
|
+
}
|
|
4415
|
+
if (configApprovals?.enabled === false) {
|
|
4416
|
+
configApprovals.enabled = true;
|
|
4417
|
+
gateway004Fixed = true;
|
|
4418
|
+
configModified = true;
|
|
4419
|
+
fixesApplied.push('Changed approvals.enabled to true');
|
|
4420
|
+
}
|
|
4421
|
+
}
|
|
4363
4422
|
if (approvalsDisabled) {
|
|
4364
4423
|
findings.push({
|
|
4365
4424
|
checkId: 'GATEWAY-004',
|
|
@@ -4367,30 +4426,47 @@ dist/
|
|
|
4367
4426
|
description: 'Execution approval confirmations are disabled',
|
|
4368
4427
|
category: 'gateway',
|
|
4369
4428
|
severity: 'critical',
|
|
4370
|
-
passed:
|
|
4371
|
-
message:
|
|
4429
|
+
passed: gateway004Fixed,
|
|
4430
|
+
message: gateway004Fixed
|
|
4431
|
+
? 'Fixed: Approval confirmations are now enabled - commands will require user confirmation'
|
|
4432
|
+
: 'Approval confirmations disabled - commands execute without user confirmation',
|
|
4372
4433
|
file: relativePath,
|
|
4373
|
-
fixable:
|
|
4374
|
-
|
|
4434
|
+
fixable: true,
|
|
4435
|
+
fixed: gateway004Fixed,
|
|
4436
|
+
fixMessage: gateway004Fixed ? 'Enabled approval confirmations for command execution' : undefined,
|
|
4437
|
+
fix: 'Run `hackmyagent secure-openclaw --fix` to enable approval confirmations for safer command execution',
|
|
4375
4438
|
});
|
|
4376
4439
|
}
|
|
4377
4440
|
// GATEWAY-005: Sandbox Disabled
|
|
4378
4441
|
const sandbox = config.sandbox;
|
|
4379
|
-
|
|
4442
|
+
const sandboxDisabled = sandbox && sandbox.enabled === false;
|
|
4443
|
+
let gateway005Fixed = false;
|
|
4444
|
+
if (sandboxDisabled && autoFix) {
|
|
4445
|
+
// Fix: Enable sandbox
|
|
4446
|
+
sandbox.enabled = true;
|
|
4447
|
+
gateway005Fixed = true;
|
|
4448
|
+
configModified = true;
|
|
4449
|
+
fixesApplied.push('Changed sandbox.enabled to true');
|
|
4450
|
+
}
|
|
4451
|
+
if (sandboxDisabled) {
|
|
4380
4452
|
findings.push({
|
|
4381
4453
|
checkId: 'GATEWAY-005',
|
|
4382
4454
|
name: 'Sandbox Disabled',
|
|
4383
4455
|
description: 'Sandbox execution environment is disabled',
|
|
4384
4456
|
category: 'gateway',
|
|
4385
4457
|
severity: 'critical',
|
|
4386
|
-
passed:
|
|
4387
|
-
message:
|
|
4458
|
+
passed: gateway005Fixed,
|
|
4459
|
+
message: gateway005Fixed
|
|
4460
|
+
? 'Fixed: Sandbox is now enabled - code executes in isolated environment'
|
|
4461
|
+
: 'Sandbox is disabled - code executes with full system access',
|
|
4388
4462
|
file: relativePath,
|
|
4389
|
-
fixable:
|
|
4390
|
-
|
|
4463
|
+
fixable: true,
|
|
4464
|
+
fixed: gateway005Fixed,
|
|
4465
|
+
fixMessage: gateway005Fixed ? 'Enabled sandbox mode for isolated code execution' : undefined,
|
|
4466
|
+
fix: 'Run `hackmyagent secure-openclaw --fix` to enable sandbox mode for safer code execution',
|
|
4391
4467
|
});
|
|
4392
4468
|
}
|
|
4393
|
-
// GATEWAY-006: Container Escape Risk
|
|
4469
|
+
// GATEWAY-006: Container Escape Risk (not auto-fixable - requires manual review of mount points)
|
|
4394
4470
|
const docker = config.docker;
|
|
4395
4471
|
const isPrivileged = docker?.privileged === true;
|
|
4396
4472
|
const mounts = docker?.mounts;
|
|
@@ -4415,9 +4491,42 @@ dist/
|
|
|
4415
4491
|
message: `Container escape risk: ${issues.join(', ')}`,
|
|
4416
4492
|
file: relativePath,
|
|
4417
4493
|
fixable: false,
|
|
4418
|
-
fix: '
|
|
4494
|
+
fix: 'Manually disable privileged mode and remove sensitive host mounts - requires careful review',
|
|
4419
4495
|
});
|
|
4420
4496
|
}
|
|
4497
|
+
// Write modified config back to file if any fixes were applied
|
|
4498
|
+
if (configModified) {
|
|
4499
|
+
try {
|
|
4500
|
+
await fs.writeFile(configFile, JSON.stringify(config, null, 2) + '\n');
|
|
4501
|
+
// Add a summary finding about what was fixed
|
|
4502
|
+
findings.push({
|
|
4503
|
+
checkId: 'FIX-SUMMARY',
|
|
4504
|
+
name: 'Auto-Fix Applied',
|
|
4505
|
+
description: 'Configuration was automatically remediated',
|
|
4506
|
+
category: 'gateway',
|
|
4507
|
+
severity: 'low',
|
|
4508
|
+
passed: true,
|
|
4509
|
+
message: `Applied ${fixesApplied.length} fix(es): ${fixesApplied.join('; ')}`,
|
|
4510
|
+
file: relativePath,
|
|
4511
|
+
fixable: false,
|
|
4512
|
+
fix: 'Use `hackmyagent rollback` to undo these changes if needed',
|
|
4513
|
+
});
|
|
4514
|
+
}
|
|
4515
|
+
catch (writeError) {
|
|
4516
|
+
findings.push({
|
|
4517
|
+
checkId: 'FIX-ERROR',
|
|
4518
|
+
name: 'Auto-Fix Failed',
|
|
4519
|
+
description: 'Could not write configuration changes',
|
|
4520
|
+
category: 'gateway',
|
|
4521
|
+
severity: 'medium',
|
|
4522
|
+
passed: false,
|
|
4523
|
+
message: `Failed to write fixes to ${relativePath}: ${writeError instanceof Error ? writeError.message : 'Unknown error'}`,
|
|
4524
|
+
file: relativePath,
|
|
4525
|
+
fixable: false,
|
|
4526
|
+
fix: 'Check file permissions and try again',
|
|
4527
|
+
});
|
|
4528
|
+
}
|
|
4529
|
+
}
|
|
4421
4530
|
}
|
|
4422
4531
|
return findings;
|
|
4423
4532
|
}
|