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;IAqKlC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA4B3B;;OAEG;YACW,iBAAiB;IA8D/B;;OAEG;YACW,mBAAmB;IAmRjC;;OAEG;YACW,wBAAwB;CAsJvC"}
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
- if (gateway && gateway.host === '0.0.0.0') {
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: false,
4315
- message: 'Gateway host is 0.0.0.0 - accessible from any network interface',
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: false,
4318
- fix: 'Bind to 127.0.0.1 for local-only access or specific interface IP',
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: 'Add security.websocketOrigins array with allowed origins',
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 hasPlaintextToken = (gatewayAuth && typeof gatewayAuth.token === 'string' && gatewayAuth.token.length > 0) ||
4341
- (typeof config.token === 'string' && config.token.length > 0);
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: false,
4350
- message: 'Plaintext token found in configuration - use environment variables instead',
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: false,
4353
- fix: 'Move tokens to environment variables: OPENCLAW_AUTH_TOKEN',
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: false,
4371
- message: 'Approval confirmations disabled - commands execute without user confirmation',
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: false,
4374
- fix: 'Enable approvals: exec.approvals.set = "on" or approvals.enabled = true',
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
- if (sandbox && sandbox.enabled === false) {
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: false,
4387
- message: 'Sandbox is disabled - code executes with full system access',
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: false,
4390
- fix: 'Enable sandbox: sandbox.enabled = true',
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: 'Disable privileged mode and remove sensitive host mounts',
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
  }