Cognition: Security Scanner
Real-time HTTP request scanning for SQL injection, XSS, path traversal, and command injection. Ships as Express middleware or a standalone function, with 16 built-in detection patterns.
The Security Scanner checks incoming HTTP requests for common injection attacks using 16 pre-compiled patterns across four threat categories. It works as Express middleware or as a standalone function you call directly. Anything it detects is sent to the Skytells platform, where the AI reviews it alongside your other event data.
The scanner is built for high recall. It casts a wide net and reports anything that looks suspicious, even if some matches turn out to be false positives. Skytells handles contextual refinement server-side, so you don't need complex detection rules in your application.
Enabling and Disabling
The Security Scanner is enabled by default:
// Enabled by default
Cognition.init({
apiKey: process.env.SKYTELLS_API_KEY!,
projectId: process.env.SKYTELLS_PROJECT_ID!,
captureSecurityThreats: true, // default
});
// Disable entirely
Cognition.init({
apiKey: process.env.SKYTELLS_API_KEY!,
projectId: process.env.SKYTELLS_PROJECT_ID!,
captureSecurityThreats: false,
});When disabled, scanForThreats() always returns false and the middleware factory produces a no-op.
Express / Connect Middleware
The fastest path to protecting HTTP endpoints is the ready-made middleware:
import express from 'express';
import { Cognition, createSecurityMiddleware } from '@skytells/cognition';
const app = express();
const cognition = Cognition.init({
apiKey: process.env.SKYTELLS_API_KEY!,
projectId: process.env.SKYTELLS_PROJECT_ID!,
});
// Body parsing must come before security scanning
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Security scanning middleware — report-only by default
app.use(
createSecurityMiddleware((event) => {
cognition.captureEvent(event);
}),
);What the Middleware Scans
For every incoming request, the middleware scans:
- URL query parameters — Each query string value individually
- Request headers — All headers except a safe list (see below)
- Request body — String values when the body has been parsed (e.g., by
express.json())
Safe headers (skipped by the scanner):
host, connection, accept, accept-encoding, accept-language, content-length, content-type, x-api-key, x-project-id, authorization
Middleware Behavior
- Non-blocking — calls
next()regardless of whether a threat was detected - Threats are reported asynchronously via the event callback
- Does not block or reject requests — it only observes
Fastify and Koa
The middleware works with any framework that accepts (req, res, next) handlers — Fastify (with middie), Koa (with koa-connect), or plain HTTP servers.
For Fastify, use a preHandler hook and call scanForThreats() directly:
fastify.addHook('preHandler', async (request, reply) => {
const body = typeof request.body === 'string'
? request.body
: JSON.stringify(request.body ?? '');
if (body && cognition.scanForThreats(body, {
method: request.method,
url: request.url,
ip: request.ip,
})) {
reply.status(403).send({ error: 'Forbidden' });
}
});Manual Scanning
Scan any string directly:
const isThreat = cognition.scanForThreats(userInput, {
method: 'POST',
url: '/api/search',
ip: '192.168.1.100',
source: 'body.query', // Where the input came from
});
if (isThreat) {
console.warn('Threat detected in user input');
}The scanner tests the input against all patterns and emits a SecurityEvent for each matching pattern. Returns true if at least one pattern matched.
Parameters
| Parameter | Type | Description |
|---|---|---|
input | string | The string to scan |
context.method | string? | HTTP method (e.g., 'POST') |
context.url | string? | Request URL |
context.ip | string? | Client IP address |
context.source | string? | Where the input came from (e.g., 'body.query', 'header.referer') |
Blocking Malicious Requests
The middleware is observe-only by default. To block requests on specific routes:
import { SecurityScanner } from '@skytells/cognition';
const scanner = new SecurityScanner((event) => {
cognition.captureEvent(event);
});
app.use((req, res, next) => {
const body = req.body;
if (body && typeof body === 'object') {
for (const value of Object.values(body)) {
if (
typeof value === 'string' &&
scanner.scan(value, {
method: req.method,
url: req.url,
ip: req.ip,
source: 'body',
})
) {
return res.status(400).json({ error: 'Malicious input detected' });
}
}
}
next();
});Threat Patterns
The SDK ships with 16 pre-compiled regex patterns across four categories:
SQL Injection
| Pattern | Severity | Example |
|---|---|---|
| SQL union-based injection | critical | 1 UNION SELECT * FROM users |
| SQL comment termination | critical | ' OR '1'='1 |
| SQL tautology | high | OR 1=1 |
| SQL batch execution | high | ; DROP TABLE users |
Cross-Site Scripting (XSS)
| Pattern | Severity | Example |
|---|---|---|
| Script tag injection | high | <script>alert(1)</script> |
| Event handler injection | high | onload="alert(1)" |
| JavaScript URI | medium | javascript:alert(1) |
| Data URI with script | medium | data:text/html,<script> |
Path Traversal
| Pattern | Severity | Example |
|---|---|---|
| Directory traversal | high | ../../etc/passwd |
| Null byte injection | high | file.txt%00.jpg |
| Encoded traversal | medium | %2e%2e%2fetc |
Command Injection
| Pattern | Severity | Example |
|---|---|---|
| Shell command chaining | critical | ; rm -rf / |
| Subshell execution | critical | $(cat /etc/passwd) |
| Pipe to shell | high | | bash |
Security Event Structure
interface SecurityEvent {
type: 'security';
timestamp: number;
threatType: ThreatType; // 'sql_injection' | 'xss' | 'path_traversal' | 'command_injection'
severity: ThreatSeverity; // 'critical' | 'high' | 'medium' | 'low'
message: string; // e.g. "SQL union-based injection detected in body.query"
request?: {
method: string; // 'POST'
url: string; // '/api/search'
headers?: Record<string, string>;
ip?: string;
};
pattern?: string; // Pattern name that matched
payload?: string; // Matched input (truncated to 500 chars)
}Payload truncation: Matched input strings longer than 500 characters are truncated with '...' appended. This prevents oversized events from consuming excess bandwidth while preserving enough context for analysis.
Custom Patterns
Extend the built-in patterns with your own:
import { SecurityScanner, type ThreatPattern } from '@skytells/cognition';
const customPatterns: ThreatPattern[] = [
{
type: 'auth_anomaly',
severity: 'high',
name: 'JWT token in URL',
pattern: /eyJ[A-Za-z0-9-_]+\.eyJ[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+/,
},
{
type: 'command_injection',
severity: 'critical',
name: 'Python eval injection',
pattern: /\beval\s*\(/i,
},
];
const scanner = new SecurityScanner(
(event) => cognition.captureEvent(event),
customPatterns, // Appended to the 16 built-in patterns
);Each custom pattern must conform to:
interface ThreatPattern {
type: ThreatType; // 'sql_injection' | 'xss' | 'path_traversal' | 'command_injection' | 'auth_anomaly' | 'rate_anomaly'
severity: ThreatSeverity; // 'critical' | 'high' | 'medium' | 'low'
name: string;
pattern: RegExp;
}Threat Types Reference
type ThreatType =
| 'sql_injection'
| 'xss'
| 'path_traversal'
| 'command_injection'
| 'auth_anomaly' // Reserved for future use
| 'rate_anomaly'; // Reserved for future use
type ThreatSeverity = 'critical' | 'high' | 'medium' | 'low';Related
- Configuration —
captureSecurityThreatsoption - Analytics — View security threat events in the Console and CLI
- Examples — Express server with security middleware, blocking pattern
How is this guide?
Runtime Observer
Six process health monitors sampling event loop timing, memory, CPU, garbage collection, active handles, and HTTP metrics. Configurable thresholds emit anomaly events when limits are crossed.
OpenTelemetry
Route your existing OpenTelemetry spans through Cognition. Traces, errors, runtime data, and security events all go to one place through a single SDK.