JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 1
  • Score
    100M100P100Q47635F
  • License UNLICENSED

Penjaro AI-powered proxy middleware for preventive cybersecurity

Package Exports

  • penjaro-network-security-library-javascript
  • penjaro-network-security-library-javascript/dist/library.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (penjaro-network-security-library-javascript) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

Penjaro Network Security Middleware (JavaScript/TypeScript)

npm version License: UNLICENSED

Penjaro provides intelligent, proactive network security for your web applications and APIs. It acts as a smart shield, analyzing incoming requests and outgoing responses using a combination of rule-based detection, threat intelligence feeds, AI-powered analysis, and framework-specific hardening techniques.

Stop attacks before they reach your application logic. Penjaro integrates seamlessly as middleware or a standalone proxy, offering a powerful layer of defense against common and sophisticated threats.

Why Penjaro?

  • Proactive Defense: Identifies and blocks threats like SQL injection, XSS, command injection, malicious bots, DoS attempts, and more at the edge.
  • AI-Powered Intelligence: (Optional) Leverage TensorFlow.js models to detect novel and complex attack patterns that signature-based methods might miss.
  • Threat Feed Integration: Stay ahead of attackers by automatically blocking IPs known for malicious activity (malware C&C, scanners, Tor exits, etc.).
  • Response Security: Prevent accidental leaks of sensitive data (API keys, PII) or verbose error messages in responses.
  • Framework Native: Easy integration with popular Node.js frameworks (Express, Koa, NestJS, Fastify, Hapi).
  • Highly Configurable: Fine-tune security policies to match your application's specific needs and risk profile.
  • Distributed Ready: Use Redis to share rate limiting and threat intelligence state across multiple instances.

Features

  • Request Filtering:
    • Rule-based detection (SQLi, XSS, Cmd Inj, Path Trav, SSRF, Log4j, etc.)
    • Customizable rule patterns
    • Threat intelligence IP blocking (Tor, FireHOL, Feodo, CINS, custom feeds)
    • IP Rate Limiting (in-memory or Redis)
    • JA3 TLS Fingerprint blocking (requires upstream proxy setup)
    • GraphQL Protection (depth, complexity, introspection, keyword blocking)
  • Response Filtering (Proxy Mode Only):
    • Data leak prevention (detects common key/PII patterns)
    • Verbose error message scrubbing
    • Customizable detection patterns
  • AI-Powered Analysis (Optional):
    • Integrates with pre-trained tf.js models.
    • Customizable feature extraction.
    • Configurable failure modes (fail-open/fail-closed).
  • Incident Reporting:
    • Reports blocked requests/responses to the Penjaro API for visibility.
  • Flexible Deployment:
    • Middleware Mode: Integrate directly into your application code.
    • Proxy Mode: Run as a standalone reverse proxy shielding your backend.

Installation

npm install penjaro-network-security-library-javascript
# or
yarn add penjaro-network-security-library-javascript

# Install peer dependencies for your framework (e.g., Express)
npm install express
# or yarn add express

# Optional dependencies (needed for specific features)
npm install redis # For Redis-based rate limiting / threat intel
npm install graphql # For GraphQL protection
npm install @tensorflow/tfjs-node # For AI features

Core Concept: Operating Modes

Penjaro can operate in two distinct modes, determined by the presence of the targetServer option:

  1. Middleware Mode (No targetServer):

    • Integrates directly into your framework's middleware chain (e.g., app.use() in Express/Koa, consumer.apply() in NestJS).
    • Analyzes incoming requests only.
    • Blocks malicious requests or passes legitimate ones to your application logic (next()).
    • Ideal for securing existing applications without changing infrastructure.
  2. Proxy Mode (targetServer is provided):

    • Acts as a reverse proxy. It receives all traffic, analyzes incoming requests, forwards valid ones to your targetServer, analyzes outgoing responses from the target, and then sends the final response to the client.
    • Provides both request and response security.
    • Requires Penjaro to run as a separate process or container listening on your public-facing port.
    • Offers the most comprehensive protection but involves a slightly different deployment pattern.

Getting Started

Penjaro is initialized asynchronously. You'll typically call createPenjaroProxy (for Express) or createPenjaroAdapter (for other frameworks) within an async context.

Basic Express Example (Middleware Mode)

import express from 'express';
import { createPenjaroProxy, PenjaroConfigOptions } from 'penjaro-network-security-library-javascript'; 
// Adjust path if needed based on your setup, might be just 'penjaro-network-security-library-javascript' after install

const app = express();

const penjaroOptions: PenjaroConfigOptions = {
  apiKey: process.env.PENJARO_API_KEY || 'YOUR_API_KEY', // REQUIRED! Get from Penjaro dashboard
  // Middleware mode - no targetServer specified
  enableRateLimit: true,
  enableThreatIntelCheck: true, 
  includeDefaultFireholFeed: true,
  // Add other options as needed
};

async function startServer() {
  try {
    // Initialize Penjaro middleware
    const penjaroMiddleware = await createPenjaroProxy(penjaroOptions);

    // Apply Penjaro middleware BEFORE other routes/middleware
    app.use(penjaroMiddleware);

    // Your application routes
    app.get('/', (req, res) => {
      res.send('Hello World!');
    });

    const PORT = process.env.PORT || 3000;
    app.listen(PORT, () => {
      console.log(`Server running with Penjaro protection on port ${PORT}`);
    });

  } catch (error) {
    console.error("Failed to initialize Penjaro or start server:", error);
    process.exit(1);
  }
}

startServer();

For Koa, NestJS, Fastify, and Hapi, use the createPenjaroAdapter factory:

import { createPenjaroAdapter, Framework, PenjaroConfigOptions } from 'penjaro-network-security-library-javascript/dist/adapters'; 
// Adjust path if needed

const penjaroOptions: PenjaroConfigOptions = {
  apiKey: process.env.PENJARO_API_KEY || 'YOUR_API_KEY', 
  // Add other desired options...
};

async function initializePenjaro(frameworkType: Framework) {
  try {
    // Create the adapter for your specific framework
    const adapter = await createPenjaroAdapter(frameworkType, penjaroOptions);
    return adapter;
  } catch (error) {
    console.error(`Failed to create Penjaro adapter for ${frameworkType}:`, error);
    throw error; // Re-throw or handle appropriately
  }
}

// Example usage within framework setup (see Framework Integration Examples below)
// const koaMiddleware = await initializePenjaro(Framework.KOA);
// app.use(koaMiddleware); 

Configuration (PenjaroConfigOptions)

The behavior of Penjaro is controlled by the PenjaroConfigOptions object passed during initialization.

Option Type Default Description
apiKey string REQUIRED Your unique API key obtained from the Penjaro dashboard. Used for validation and incident reporting.
targetServer string undefined If set (e.g., 'http://localhost:8080'), enables Proxy Mode. If omitted, enables Middleware Mode.
aiModel tf.LayersModel or compatible null A pre-loaded TensorFlow.js model for AI analysis. If null, AI features are disabled. See 'AI Model Handling'.
proxyConfig object {} Options passed directly to http-proxy-middleware (Proxy Mode only). See HPM Docs.
enableRateLimit boolean true Enables basic IP-based rate limiting. Uses in-memory store by default, or Redis if configured.
rateLimitPoints number 10 Max requests allowed per IP per window duration.
rateLimitDuration number 1 Time window duration in seconds.
enableResponseAnalysis boolean true Master switch for response analysis (Proxy Mode only). Performance cost: buffers responses, breaks streaming.
enableDataLeakChecks boolean true Enables regex checks for common PII/key patterns in responses. Requires enableResponseAnalysis.
enableVerboseErrorChecks boolean true Enables regex checks for stack traces/verbose errors in responses. Requires enableResponseAnalysis.
responseAnalysisMaxSize number 1048576 (1MB) Maximum response body size (bytes) to buffer and analyze.
responseAnalysisContentTypes string[] ['application/json', 'text/html', ...] Array of Content-Type headers (case-insensitive) for which response analysis should run.
blockUnsafeResponses boolean true If true, blocks responses that fail data leak or verbose error checks.
replaceDefaultPatterns boolean false If true, customDataLeakPatterns and customVerboseErrorPatterns replace the defaults. If false, they are merged.
customDataLeakPatterns RegExp[] [] Add your own regex patterns to detect sensitive data leaks in responses.
customVerboseErrorPatterns RegExp[] [] Add your own regex patterns to detect verbose errors in responses.
enableJa3Check boolean false Enables blocking based on TLS JA3 fingerprint. Requires upstream proxy (Nginx, Envoy) to inject the hash. See 'JA3 Fingerprinting'.
ja3HeaderName string 'X-JA3-Hash' HTTP Header name (case-insensitive) containing the JA3 hash provided by the upstream proxy.
badJa3Hashes string[] [...] (List of known bad hashes) Array of malicious JA3 hashes to block if enableJa3Check is true.
enableGraphqlProtection boolean false Enables GraphQL-specific checks (depth, complexity, introspection, keywords). Requires graphql package. See 'GraphQL Protection'.
graphqlMaxDepth number 10 Maximum allowed query nesting depth.
graphqlMaxComplexity number 1000 Maximum allowed query complexity score (approximated by field count).
graphqlBlockIntrospection boolean true Blocks GraphQL introspection queries (__schema, __type). Set false for development if needed.
graphqlBlockKeywords string[] [] Block requests if these keywords appear in GraphQL string arguments/values (e.g., '../', 'SELECT').
enableThreatIntelCheck boolean false Enables checking the source IP against threat intelligence feeds. Uses in-memory store by default, or Redis if configured.
threatIntelFeedUrls string[] [] Array of custom URLs pointing to plain text IP blocklist feeds (one IP per line).
threatIntelFetchIntervalMinutes number 60 How often (in minutes) to refresh the threat intelligence feeds.
includeDefaultTorFeed boolean false Include the Tor exit node list from check.torproject.org.
includeDefaultFireholFeed boolean false Include the FireHOL Level 1 blocklist (raw.githubusercontent.com/firehol/blocklist-ipsets).
includeDefaultFeodoFeed boolean false Include the Feodo Tracker IP blocklist (feodotracker.abuse.ch).
includeDefaultCinsFeed boolean false Include the CINS Army List (cinsscore.com).
whitelistIps string[] [] List of IP addresses that should NEVER be blocked, even if they appear in threat intelligence feeds. Prevents false positives for trusted sources.
onThreatIntelError (error: Error) => void undefined Optional callback function invoked if an error occurs during threat feed fetching or parsing.
excludePathsFromDataLeakCheck RegExp[] [] URL paths to exclude from data leak checks (e.g., /auth endpoints where emails are expected). Reduces false positives.
excludePathsFromErrorCheck RegExp[] [] URL paths to exclude from verbose error checks.
redisClient RedisClientType (v4) undefined Provide a pre-configured redis v4 client instance. Takes precedence over redisUrl/redisOptions. Enables shared state for Rate Limiting & Threat Intel.
redisUrl string undefined Redis connection URL (e.g., 'redis://user:pass@host:port/db'). Used if redisClient is not provided.
redisOptions object undefined Redis connection options (passed to createClient). Used if redisClient and redisUrl are not provided.
disableDefaultRequestRules object {} Disable specific built-in request rule categories. E.g., { sql: true, xss: true }. Categories: sql, xss, command, traversal, header, ssrf, log4j, info, scanner, ssrfHeader, xssLib.
customRequestRulePatterns object {} Add custom request rule regex patterns, keyed by category name. E.g., { myRule: [/bad_pattern/i] }.
replaceDefaultRequestPatterns boolean false If true, customRequestRulePatterns replace the defaults per category. If false, they are merged.
featureExtractor (req: Request) => number[] undefined Custom function to extract features from an Express Request object for the AI model. See 'AI Model Handling'.
aiAnalysisFailureMode 'fail-open' | 'fail-closed' 'fail-open' Behavior if the AI model analysis fails: 'fail-open' allows the request, 'fail-closed' blocks it.
enableIncidentReporting boolean true If true, reports blocked requests/responses and security events to the Penjaro API (using your apiKey).

Framework Integration Examples

Always initialize Penjaro early in your application setup, typically before defining routes or applying other middleware that might parse bodies.

Express (Native)

Use createPenjaroProxy directly.

// See "Getting Started" example above
import express from 'express';
import { createPenjaroProxy, PenjaroConfigOptions } from 'penjaro-network-security-library-javascript';

const app = express();
const penjaroOptions: PenjaroConfigOptions = { /* ... your config ... */ apiKey: '...' };

async function start() {
  const penjaroMiddleware = await createPenjaroProxy(penjaroOptions);
  app.use(penjaroMiddleware); 
  // ... rest of your express app setup ...
  app.listen(3000);
}
start();

Koa

Use createPenjaroAdapter with Framework.KOA.

import Koa from 'koa';
import { createPenjaroAdapter, Framework, PenjaroConfigOptions } from 'penjaro-network-security-library-javascript/dist/adapters';

const app = new Koa();
const penjaroOptions: PenjaroConfigOptions = { /* ... your config ... */ apiKey: '...' };

async function start() {
  const penjaroMiddleware = await createPenjaroAdapter(Framework.KOA, penjaroOptions);
  app.use(penjaroMiddleware);
  // ... rest of your koa app setup ...
  app.listen(3000);
}
start();

NestJS

Use createPenjaroAdapter with Framework.NESTJS inside your AppModule's configure method.

import { Module, NestModule, MiddlewareConsumer, RequestMethod } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { createPenjaroAdapter, Framework, PenjaroConfigOptions } from 'penjaro-network-security-library-javascript/dist/adapters';

// Define your options (potentially load from config service)
const penjaroOptions: PenjaroConfigOptions = {
  apiKey: process.env.PENJARO_API_KEY || 'YOUR_API_KEY',
  // ... other options
};

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {
  async configure(consumer: MiddlewareConsumer) {
    // Create the NestJS compatible middleware function
    const PenjaroMiddleware = await createPenjaroAdapter(Framework.NESTJS, penjaroOptions);

    consumer
      .apply(PenjaroMiddleware)
      .forRoutes('*'); // Apply to all routes, or specify paths/methods
      // .forRoutes({ path: 'protected/*', method: RequestMethod.ALL }); 
  }
}

Fastify

Use createPenjaroAdapter with Framework.FASTIFY and register it as a plugin.

import Fastify from 'fastify';
import { createPenjaroAdapter, Framework, PenjaroConfigOptions } from 'penjaro-network-security-library-javascript/dist/adapters';

const fastify = Fastify({ logger: true });
const penjaroOptions: PenjaroConfigOptions = { /* ... your config ... */ apiKey: '...' };

async function start() {
  const penjaroPlugin = await createPenjaroAdapter(Framework.FASTIFY, penjaroOptions);
  
  // Register Penjaro plugin - ensure it runs early (e.g., before routes)
  await fastify.register(penjaroPlugin);

  // Define routes *after* registering Penjaro
  fastify.get('/', async (request, reply) => {
    return { hello: 'world' }
  });

  // ... rest of your fastify app setup ...
  await fastify.listen({ port: 3000 });
}
start();

Hapi

Use createPenjaroAdapter with Framework.HAPI and register it as a plugin.

import Hapi from '@hapi/hapi';
import { createPenjaroAdapter, Framework, PenjaroConfigOptions } from 'penjaro-network-security-library-javascript/dist/adapters';

const penjaroOptions: PenjaroConfigOptions = { /* ... your config ... */ apiKey: '...' };

const init = async () => {
  const server = Hapi.server({
    port: 3000,
    host: 'localhost'
  });

  const penjaroPluginObject = await createPenjaroAdapter(Framework.HAPI, penjaroOptions);

  // Register Penjaro plugin
  await server.register(penjaroPluginObject);

  // Define routes *after* registering Penjaro
  server.route({
    method: 'GET',
    path:'/',
    handler: (request, h) => {
        return 'Hello World!';
    }
  });

  await server.start();
  console.log('Server running on %s', server.info.uri);
};

process.on('unhandledRejection', (err) => {
  console.log(err);
  process.exit(1);
});

init();

Key Feature Deep Dive

False Positive Prevention

Penjaro includes several mechanisms to prevent false positives while maintaining robust security:

  • Request Whitelisting: Built-in whitelist patterns automatically allow known legitimate patterns like OAuth/OIDC callback URLs that might otherwise trigger security alarms.

  • IP Whitelisting: Provide a list of trusted IP addresses via the whitelistIps option to ensure they're never blocked by the threat intelligence module, even if they appear in block lists.

  • Path Exclusions for Response Analysis: Use excludePathsFromDataLeakCheck and excludePathsFromErrorCheck to skip certain checks on specific paths. For example:

    const penjaroOptions: PenjaroConfigOptions = {
      apiKey: '...',
      // Exclude user profile endpoints from data leak checks
      excludePathsFromDataLeakCheck: [
        /\/api\/user\/profile/i,
        /\/auth\//i
      ],
      // Exclude development/debug endpoints from error checks
      excludePathsFromErrorCheck: [
        /\/api\/debug\//i
      ]
    };
  • Context-Aware Analysis: The response analyzer automatically adjusts its checks based on the request context. For example, email patterns aren't flagged as potential data leaks on authentication endpoints where emails are expected.

AI Model Handling

  • Enable: Provide a loaded TensorFlow.js model (tf.LayersModel or compatible object with a predict method) via the aiModel option.
  • Loading: You are responsible for loading the model before initializing Penjaro. Example using @tensorflow/tfjs-node:
    import * as tf from '@tensorflow/tfjs-node'; 
    // Or '@tensorflow/tfjs' for browser/React Native environments if applicable
    
    async function loadMyModel() {
      try {
        const model = await tf.loadLayersModel('file://path/to/your/model/model.json'); 
        // Or tf.loadGraphModel, or load from other sources
        console.log("AI Model loaded successfully.");
        return model;
      } catch (error) {
        console.error("Failed to load AI model:", error);
        return null; // Handle error appropriately
      }
    }
    
    // Then, in your Penjaro init:
    const loadedModel = await loadMyModel();
    const penjaroOptions: PenjaroConfigOptions = {
      apiKey: '...',
      aiModel: loadedModel, 
      // ... other options
    };
    // const penjaroMiddleware = await createPenjaroProxy(penjaroOptions); 
  • Feature Extraction: By default, Penjaro might use a basic feature extractor if none is provided. For optimal results, supply a featureExtractor function in the options. This function receives the framework's request object (currently assumes Express Request type) and must return an array of numbers (number[]) suitable as input for your model's predict method.
    import { Request } from 'express'; // Or the relevant type for your framework if adapters evolve
    
    function myFeatureExtractor(req: Request): number[] {
      // Example: Extract numerical features from headers, body, query params
      const contentLength = parseInt(req.headers['content-length'] || '0', 10);
      const queryParamCount = Object.keys(req.query).length;
      // ... more sophisticated feature engineering ...
      const features = [contentLength, queryParamCount /*, ... */];
      // Ensure the output array shape matches your model's expected input
      return features;
    }
    
    const penjaroOptions: PenjaroConfigOptions = {
      // ...
      aiModel: loadedModel,
      featureExtractor: myFeatureExtractor,
    };
  • Failure Mode: Use aiAnalysisFailureMode ('fail-open' or 'fail-closed') to decide if requests should be allowed or blocked if the AI analysis encounters an error.

Threat Intelligence

  • Enable: Set enableThreatIntelCheck: true.
  • Feeds: Include default feeds (includeDefaultTorFeed, etc.) and/or provide your own via threatIntelFeedUrls. Custom feeds must be plain text URLs with one IP address per line.
  • State: By default, the fetched blocklist is stored in memory. For multi-instance deployments, provide a Redis client (redisClient, redisUrl, or redisOptions) to share the blocklist across all instances.
  • Updates: Feeds are refreshed periodically based on threatIntelFetchIntervalMinutes.
  • Errors: Handle potential feed fetch/parse errors using the onThreatIntelError callback.

JA3 Fingerprinting

  • Concept: JA3 analyzes the parameters of a client's TLS handshake to create a fingerprint. Certain fingerprints are strongly associated with malware or specific bot tools.
  • CRITICAL: Penjaro cannot calculate the JA3 hash itself. You must have an upstream TLS-terminating proxy (like Nginx, Envoy, HAProxy, or Cloudflare) configured to:
    1. Calculate the JA3 hash for incoming connections.
    2. Inject that hash into an HTTP request header sent to Penjaro.
  • Enable: Set enableJa3Check: true.
  • Configuration:
    • Ensure ja3HeaderName matches the header your upstream proxy is injecting (case-insensitive, default X-JA3-Hash).
    • Populate badJa3Hashes with known malicious fingerprints you want to block. Some common ones are included by default.

GraphQL Protection

  • Enable: Set enableGraphqlProtection: true.
  • Dependency: You must have the graphql package installed (npm install graphql).
  • Checks: Applies only to POST requests identified as GraphQL (typically checks for a query field in the body).
    • graphqlMaxDepth: Limits query nesting.
    • graphqlMaxComplexity: Limits the number of requested fields (heuristic).
    • graphqlBlockIntrospection: Blocks schema introspection queries (usually disabled in production).
    • graphqlBlockKeywords: Checks string arguments/values for potentially malicious keywords.

Response Analysis (Proxy Mode Only)

  • Enable: Controlled by enableResponseAnalysis (master switch), enableDataLeakChecks, and enableVerboseErrorChecks.
  • Mechanism: Buffers the response body (up to responseAnalysisMaxSize for specified responseAnalysisContentTypes) and runs regex checks.
  • Performance Impact: Buffering responses adds latency and memory usage, and breaks server-sent events (SSE) or other streaming responses. Disable enableResponseAnalysis if you rely heavily on streaming.
  • Customization: Add your own customDataLeakPatterns and customVerboseErrorPatterns. Use replaceDefaultPatterns: true to use only your custom patterns.

Redis Integration

  • Purpose: Used to share state for Rate Limiting and Threat Intelligence blocklists across multiple Node.js instances of your application.
  • Setup: Provide Redis connection details via one of these options (in order of precedence):
    1. redisClient: A pre-configured, connected redis v4 client instance.
    2. redisUrl: A Redis connection string.
    3. redisOptions: A Redis options object.
  • Fallback: If Redis connection fails or is not configured, Rate Limiting and Threat Intel fall back to using in-memory stores (state is not shared between instances).

Incident Reporting

When Penjaro blocks a request or detects a security event (and enableIncidentReporting is true), it sends details about the incident (request headers, source IP, reason for block, etc.) to the Penjaro API endpoint associated with your apiKey. This allows you to monitor security events in your Penjaro dashboard.

API Key

The apiKey is required for Penjaro to validate its configuration and report incidents. Obtain your key from the Penjaro dashboard or your administrator. Keep your API key secure and prefer loading it from environment variables (process.env.PENJARO_API_KEY) rather than hardcoding it.

License

Currently UNLICENSED. Please contact the author for licensing inquiries.

Contributing

Support