IntegrationsExpress.js

Express.js Integration

The Surfinguard JS SDK includes built-in Express.js middleware that automatically checks incoming requests for security threats.

Installation

npm install @surfinguard/sdk express

Quick Start

import express from 'express';
import { Guard, surfinguardMiddleware } from '@surfinguard/sdk';
 
const app = express();
const guard = await Guard.create({ mode: 'local' });
 
// Apply middleware to all routes
app.use(surfinguardMiddleware(guard));
 
app.post('/api/execute', (req, res) => {
  // If we reach here, the request passed the security check
  res.json({ status: 'executed' });
});
 
app.listen(3000);

How It Works

The middleware inspects incoming requests and checks action values found in the request body against the Surfinguard engine. If the check returns DANGER (or CAUTION in strict mode), the middleware responds with a 403 Forbidden before the request reaches your route handler.

Middleware Options

app.use(surfinguardMiddleware(guard, {
  // Which policy to enforce
  policy: 'moderate', // 'permissive' | 'moderate' | 'strict'
 
  // Custom function to extract the action from the request
  extractAction: (req) => {
    return {
      type: req.body.type || 'text',
      value: req.body.value || req.body.input || '',
    };
  },
 
  // Custom error handler
  onBlocked: (req, res, result) => {
    res.status(403).json({
      error: 'Action blocked by security policy',
      level: result.level,
      score: result.score,
      reasons: result.reasons,
    });
  },
}));

Route-Level Protection

Apply the middleware to specific routes instead of globally:

const checkUrl = surfinguardMiddleware(guard, {
  extractAction: (req) => ({ type: 'url', value: req.body.url }),
});
 
const checkCommand = surfinguardMiddleware(guard, {
  extractAction: (req) => ({ type: 'command', value: req.body.command }),
  policy: 'strict',
});
 
// Only these routes are protected
app.post('/api/fetch-url', checkUrl, (req, res) => {
  // URL has been checked
  res.json({ status: 'ok' });
});
 
app.post('/api/run-command', checkCommand, (req, res) => {
  // Command has been checked with strict policy
  res.json({ status: 'ok' });
});
 
// This route has no security check
app.get('/api/health', (req, res) => {
  res.json({ status: 'healthy' });
});

Custom Action Extraction

The extractAction function determines what gets checked. Here are common patterns:

// Check URL from query parameter
extractAction: (req) => ({
  type: 'url',
  value: req.query.url,
})
 
// Check command from JSON body
extractAction: (req) => ({
  type: 'command',
  value: req.body.command,
})
 
// Check text from form data
extractAction: (req) => ({
  type: 'text',
  value: req.body.prompt || req.body.message,
})
 
// Dynamic type based on request
extractAction: (req) => ({
  type: req.body.action_type,
  value: req.body.action_value,
})

Error Handling

When the middleware blocks a request, it calls the onBlocked handler. The default behavior returns a 403 JSON response:

{
  "error": "Blocked by Surfinguard",
  "level": "DANGER",
  "score": 9,
  "reasons": ["Brand impersonation: google", "Risky TLD: .tk"]
}

Override this with a custom handler:

app.use(surfinguardMiddleware(guard, {
  onBlocked: (req, res, result) => {
    // Log the blocked request
    console.warn(`Blocked ${req.method} ${req.path}:`, result.reasons);
 
    // Custom response
    res.status(422).json({
      message: 'This action has been flagged for security review',
      referenceId: generateReferenceId(),
    });
  },
}));

Full Example

import express from 'express';
import { Guard, surfinguardMiddleware } from '@surfinguard/sdk';
 
const app = express();
app.use(express.json());
 
const guard = await Guard.create({
  mode: 'local',
  policy: 'moderate',
});
 
// Global middleware for all API routes
app.use('/api', surfinguardMiddleware(guard, {
  extractAction: (req) => {
    // Map different endpoints to action types
    if (req.path.includes('/fetch')) {
      return { type: 'url', value: req.body.url };
    }
    if (req.path.includes('/execute')) {
      return { type: 'command', value: req.body.command };
    }
    if (req.path.includes('/chat')) {
      return { type: 'text', value: req.body.message };
    }
    return null; // Skip check if no action to extract
  },
  onBlocked: (req, res, result) => {
    res.status(403).json({
      blocked: true,
      level: result.level,
      reasons: result.reasons,
    });
  },
}));
 
app.post('/api/fetch', (req, res) => {
  res.json({ html: '...' });
});
 
app.post('/api/execute', (req, res) => {
  res.json({ output: '...' });
});
 
app.post('/api/chat', (req, res) => {
  res.json({ reply: '...' });
});
 
app.listen(3000, () => {
  console.log('Server running with Surfinguard protection');
});